1 /*
2 * Copyright (c) 2009, 2010 Jeff Mahoney <jeffm@suse.com>
3 * Copyright (c) 2011-2016 Dmitry V. Levin <ldv@strace.io>
4 * Copyright (c) 2016-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11
12 #include DEF_MPERS_TYPE(struct_hd_geometry)
13
14 #include <linux/hdreg.h>
15
16 typedef struct hd_geometry struct_hd_geometry;
17
18 #include MPERS_DEFS
19
20 #include "xlat/hdio_drive_cmds.h"
21
22 #include "gen/generated.h"
23
24 static int
25 print_hdio_getgeo(struct tcb *const tcp, const kernel_ulong_t arg)
26 {
27 if (entering(tcp)) {
28 tprint_arg_next();
29
30 return 0;
31 }
32
33 /* exiting */
34 struct_hd_geometry geo;
35
36 if (umove_or_printaddr(tcp, arg, &geo))
37 return RVAL_IOCTL_DECODED;
38
39 tprint_struct_begin();
40 PRINT_FIELD_U(geo, heads);
41 tprint_struct_next();
42 PRINT_FIELD_U(geo, sectors);
43 tprint_struct_next();
44 PRINT_FIELD_U(geo, cylinders);
45 tprint_struct_next();
46 PRINT_FIELD_U(geo, start);
47 tprint_struct_end();
48
49 return RVAL_IOCTL_DECODED;
50 }
51
52 static int
53 print_hdio_drive_cmd(struct tcb *const tcp, const kernel_ulong_t arg)
54 {
55 enum { SECTOR_SIZE = 512 };
56
57 if (entering(tcp)) {
58 tprint_arg_next();
59
60 struct hd_drive_cmd_hdr c;
61 if (umove_or_printaddr(tcp, arg, &c))
62 return RVAL_IOCTL_DECODED;
63
64 tprint_struct_begin();
65 PRINT_FIELD_XVAL(c, command, hdio_drive_cmds,
66 "ATA_CMD_???");
67 tprint_struct_next();
68 PRINT_FIELD_U(c, sector_number);
69 tprint_struct_next();
70 PRINT_FIELD_U(c, feature);
71 tprint_struct_next();
72 PRINT_FIELD_U(c, sector_count);
73 tprint_struct_end();
74
75 return 0;
76 }
77
78 /* exiting */
79 struct {
80 uint8_t status;
81 uint8_t error;
82 uint8_t nsector;
83 uint8_t sector_count;
84 } c;
85
86 if ((syserror(tcp) && tcp->u_error != EIO) || umove(tcp, arg, &c))
87 return RVAL_IOCTL_DECODED;
88
89 tprint_value_changed();
90 tprint_struct_begin();
91 PRINT_FIELD_X(c, status);
92 tprint_struct_next();
93 PRINT_FIELD_U(c, error);
94 tprint_struct_next();
95 PRINT_FIELD_U(c, nsector);
96
97 if (c.sector_count) {
98 tprint_struct_next();
99 tprints_field_name("buf");
100 printstr_ex(tcp, arg + 4, c.sector_count * SECTOR_SIZE,
101 QUOTE_FORCE_HEX);
102 }
103
104 tprint_struct_end();
105
106 return RVAL_IOCTL_DECODED;
107 }
108
109 MPERS_PRINTER_DECL(int, hdio_ioctl, struct tcb *const tcp,
110 const unsigned int code, const kernel_ulong_t arg)
111 {
112 switch (code) {
113 case HDIO_GETGEO:
114 return print_hdio_getgeo(tcp, arg);
115 case HDIO_DRIVE_CMD:
116 return print_hdio_drive_cmd(tcp, arg);
117 default:
118 if (current_klongsize == sizeof(kernel_ulong_t)) {
119 return var_ioctl_HDIO(tcp, code, arg);
120 } else {
121 /*
122 * HDIO compat has never been supported by the kernel.
123 */
124 return RVAL_DECODED;
125 }
126 }
127
128 return RVAL_IOCTL_DECODED;
129 }