]> granicus.if.org Git - strace/blob - dm.c
Remove HAVE_STRUCT_TCB_EXT_ARG, ext_arg, and u_lrval
[strace] / dm.c
1 #include "defs.h"
2
3 #ifdef HAVE_LINUX_DM_IOCTL_H
4
5 # include <linux/dm-ioctl.h>
6 # include <linux/ioctl.h>
7
8 # include <sys/sysmacros.h>
9
10 # if DM_VERSION_MAJOR == 4
11
12 /* Definitions for command which have been added later */
13
14 #  ifndef DM_LIST_VERSIONS
15 #   define DM_LIST_VERSIONS    _IOWR(DM_IOCTL, 0xd, struct dm_ioctl)
16 #  endif
17 #  ifndef DM_TARGET_MSG
18 #   define DM_TARGET_MSG       _IOWR(DM_IOCTL, 0xe, struct dm_ioctl)
19 #  endif
20 #  ifndef DM_DEV_SET_GEOMETRY
21 #   define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, 0xf, struct dm_ioctl)
22 #  endif
23
24
25 static void
26 dm_decode_device(const unsigned int code, const struct dm_ioctl *ioc)
27 {
28         switch (code) {
29         case DM_REMOVE_ALL:
30         case DM_LIST_DEVICES:
31         case DM_LIST_VERSIONS:
32                 break;
33         default:
34                 if (ioc->dev)
35                         tprintf(", dev=makedev(%u, %u)",
36                                 major(ioc->dev), minor(ioc->dev));
37                 if (ioc->name[0]) {
38                         tprints(", name=");
39                         print_quoted_string(ioc->name, DM_NAME_LEN,
40                                             QUOTE_0_TERMINATED);
41                 }
42                 if (ioc->uuid[0]) {
43                         tprints(", uuid=");
44                         print_quoted_string(ioc->uuid, DM_UUID_LEN,
45                                             QUOTE_0_TERMINATED);
46                 }
47                 break;
48         }
49 }
50
51 static void
52 dm_decode_values(struct tcb *tcp, const unsigned int code,
53                  const struct dm_ioctl *ioc)
54 {
55         if (entering(tcp)) {
56                 switch (code) {
57                 case DM_TABLE_LOAD:
58                         tprintf(", target_count=%" PRIu32,
59                                 ioc->target_count);
60                         break;
61                 case DM_DEV_SUSPEND:
62                         if (ioc->flags & DM_SUSPEND_FLAG)
63                                 break;
64                         /* Fall through */
65                 case DM_DEV_RENAME:
66                 case DM_DEV_REMOVE:
67                 case DM_DEV_WAIT:
68                         tprintf(", event_nr=%" PRIu32,
69                                 ioc->event_nr);
70                         break;
71                 }
72         } else if (!syserror(tcp)) {
73                 switch (code) {
74                 case DM_DEV_CREATE:
75                 case DM_DEV_RENAME:
76                 case DM_DEV_SUSPEND:
77                 case DM_DEV_STATUS:
78                 case DM_DEV_WAIT:
79                 case DM_TABLE_LOAD:
80                 case DM_TABLE_CLEAR:
81                 case DM_TABLE_DEPS:
82                 case DM_TABLE_STATUS:
83                 case DM_TARGET_MSG:
84                         tprintf(", target_count=%" PRIu32,
85                                 ioc->target_count);
86                         tprintf(", open_count=%" PRIu32,
87                                 ioc->open_count);
88                         tprintf(", event_nr=%" PRIu32,
89                                 ioc->event_nr);
90                         break;
91                 }
92         }
93 }
94
95 #include "xlat/dm_flags.h"
96
97 static void
98 dm_decode_flags(const struct dm_ioctl *ioc)
99 {
100         tprints(", flags=");
101         printflags(dm_flags, ioc->flags, "DM_???");
102 }
103
104 static void
105 dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ulong_t addr,
106                          const struct dm_ioctl *const ioc)
107 {
108         static const uint32_t target_spec_size =
109                 sizeof(struct dm_target_spec);
110         uint32_t i;
111         uint32_t offset = ioc->data_start;
112         uint32_t offset_end;
113
114         if (abbrev(tcp)) {
115                 if (ioc->target_count)
116                         tprints(", ...");
117
118                 return;
119         }
120
121         for (i = 0; i < ioc->target_count; i++) {
122                 struct dm_target_spec s;
123
124                 offset_end = offset + target_spec_size;
125
126                 if (offset_end <= offset || offset_end > ioc->data_size)
127                         goto misplaced;
128
129                 tprints(", ");
130
131                 if (i >= max_strlen) {
132                         tprints("...");
133                         break;
134                 }
135
136                 if (umove_or_printaddr(tcp, addr + offset, &s))
137                         break;
138
139                 tprintf("{sector_start=%" PRI__u64 ", length=%" PRI__u64,
140                         s.sector_start, s.length);
141
142                 if (exiting(tcp))
143                         tprintf(", status=%" PRId32, s.status);
144
145                 tprints(", target_type=");
146                 print_quoted_string(s.target_type, DM_MAX_TYPE_NAME,
147                                     QUOTE_0_TERMINATED);
148
149                 tprints(", string=");
150                 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
151                              QUOTE_0_TERMINATED);
152                 tprintf("}");
153
154                 if (entering(tcp))
155                         offset += s.next;
156                 else
157                         offset = ioc->data_start + s.next;
158
159                 if (offset <= offset_end)
160                         goto misplaced;
161         }
162
163         return;
164
165 misplaced:
166         tprints(", /* misplaced struct dm_target_spec */ ...");
167 }
168
169 bool
170 dm_print_dev(struct tcb *tcp, void *dev_ptr, size_t dev_size, void *dummy)
171 {
172         uint64_t *dev = (uint64_t *) dev_ptr;
173
174         tprintf("makedev(%u, %u)", major(*dev), minor(*dev));
175
176         return 1;
177 }
178
179 static void
180 dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ulong_t addr,
181                          const struct dm_ioctl *const ioc)
182 {
183         static const uint32_t target_deps_dev_offs =
184                 offsetof(struct dm_target_deps, dev);
185         uint64_t dev_buf;
186         struct dm_target_deps s;
187         uint32_t offset = ioc->data_start;
188         uint32_t offset_end = offset + target_deps_dev_offs;
189         uint32_t space;
190
191         if (abbrev(tcp)) {
192                 tprints(", ...");
193                 return;
194         }
195
196         tprints(", ");
197
198         if (offset_end <= offset || offset_end > ioc->data_size)
199                 goto misplaced;
200
201         if (umove_or_printaddr(tcp, addr + offset, &s))
202                 return;
203
204         space = (ioc->data_size - offset_end) / sizeof(dev_buf);
205
206         if (s.count > space)
207                 goto misplaced;
208
209         tprintf("{count=%u, deps=", s.count);
210
211         print_array(tcp, addr + offset_end, s.count, &dev_buf, sizeof(dev_buf),
212                     umoven_or_printaddr, dm_print_dev, NULL);
213
214         tprints("}");
215
216         return;
217
218 misplaced:
219         tprints("/* misplaced struct dm_target_deps */ ...");
220 }
221
222 static void
223 dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
224                        const struct dm_ioctl *const ioc)
225 {
226         static const uint32_t name_list_name_offs =
227                 offsetof(struct dm_name_list, name);
228         struct dm_name_list s;
229         uint32_t offset = ioc->data_start;
230         uint32_t offset_end;
231         uint32_t count;
232
233         if (abbrev(tcp)) {
234                 tprints(", ...");
235                 return;
236         }
237
238         for (count = 0;; count++) {
239                 offset_end = offset + name_list_name_offs;
240
241                 if (offset_end <= offset || offset_end > ioc->data_size)
242                         goto misplaced;
243
244                 tprints(", ");
245
246                 if (count >= max_strlen) {
247                         tprints("...");
248                         break;
249                 }
250
251                 if (umove_or_printaddr(tcp, addr + offset, &s))
252                         break;
253                 if (!count && !s.dev) {
254                         tprints("/* no devices present */");
255                         break;
256                 }
257
258                 tprintf("{dev=makedev(%u, %u), name=", major(s.dev),
259                         minor(s.dev));
260                 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
261                             QUOTE_0_TERMINATED);
262                 tprints("}");
263
264                 if (!s.next)
265                         break;
266
267                 offset += s.next;
268                 if (offset <= offset_end)
269                         goto misplaced;
270         }
271
272         return;
273
274 misplaced:
275         tprints(", /* misplaced struct dm_name_list */ ...");
276 }
277
278 static void
279 dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ulong_t addr,
280                              const struct dm_ioctl *const ioc)
281 {
282         static const uint32_t target_vers_name_offs =
283                 offsetof(struct dm_target_versions, name);
284         struct dm_target_versions s;
285         uint32_t offset = ioc->data_start;
286         uint32_t offset_end;
287         uint32_t count;
288
289         if (abbrev(tcp)) {
290                 tprints(", ...");
291                 return;
292         }
293
294         for (count = 0;; count++) {
295                 offset_end = offset + target_vers_name_offs;
296
297                 if (offset_end <= offset || offset_end > ioc->data_size)
298                         goto misplaced;
299
300                 tprints(", ");
301
302                 if (count >= max_strlen) {
303                         tprints("...");
304                         break;
305                 }
306
307                 if (umove_or_printaddr(tcp, addr + offset, &s))
308                         break;
309
310                 tprints("{name=");
311                 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
312                             QUOTE_0_TERMINATED);
313                 tprintf(", version=%" PRIu32 ".%" PRIu32 ".%" PRIu32 "}",
314                         s.version[0], s.version[1], s.version[2]);
315
316                 if (!s.next)
317                         break;
318
319                 offset += s.next;
320                 if (offset <= offset_end)
321                         goto misplaced;
322         }
323
324         return;
325
326 misplaced:
327         tprints(", /* misplaced struct dm_target_versions */ ...");
328 }
329
330 static void
331 dm_decode_dm_target_msg(struct tcb *const tcp, const kernel_ulong_t addr,
332                         const struct dm_ioctl *const ioc)
333 {
334         static const uint32_t target_msg_message_offs =
335                 offsetof(struct dm_target_msg, message);
336         uint32_t offset = ioc->data_start;
337         uint32_t offset_end = offset + target_msg_message_offs;
338
339         if (abbrev(tcp)) {
340                 tprints(", ...");
341                 return;
342         }
343
344         if (offset_end > offset && offset_end <= ioc->data_size) {
345                 struct dm_target_msg s;
346
347                 tprints(", ");
348
349                 if (umove_or_printaddr(tcp, addr + offset, &s))
350                         return;
351
352                 tprintf("{sector=%" PRI__u64 ", message=", s.sector);
353                 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
354                             QUOTE_0_TERMINATED);
355                 tprints("}");
356         } else {
357                 tprints(", /* misplaced struct dm_target_msg */");
358         }
359 }
360
361 static void
362 dm_decode_string(struct tcb *const tcp, const kernel_ulong_t addr,
363                  const struct dm_ioctl *const ioc)
364 {
365         uint32_t offset = ioc->data_start;
366
367         if (abbrev(tcp)) {
368                 tprints(", ...");
369                 return;
370         }
371
372         if (offset < ioc->data_size) {
373                 tprints(", string=");
374                 printstr_ex(tcp, addr + offset, ioc->data_size - offset,
375                             QUOTE_0_TERMINATED);
376         } else {
377                 tprints(", /* misplaced string */");
378         }
379 }
380
381 static inline bool
382 dm_ioctl_has_params(const unsigned int code)
383 {
384         switch (code) {
385         case DM_VERSION:
386         case DM_REMOVE_ALL:
387         case DM_DEV_CREATE:
388         case DM_DEV_REMOVE:
389         case DM_DEV_SUSPEND:
390         case DM_DEV_STATUS:
391         case DM_TABLE_CLEAR:
392                 return false;
393         }
394
395         return true;
396 }
397
398 static int
399 dm_known_ioctl(struct tcb *const tcp, const unsigned int code,
400                const kernel_ulong_t arg)
401 {
402         struct dm_ioctl *ioc = NULL;
403         struct dm_ioctl *entering_ioc = NULL;
404         bool ioc_changed = false;
405
406         if (entering(tcp)) {
407                 ioc = malloc(sizeof(*ioc));
408                 if (!ioc)
409                         return 0;
410         } else {
411                 ioc = alloca(sizeof(*ioc));
412         }
413
414         if ((umoven(tcp, arg, offsetof(struct dm_ioctl, data), ioc) < 0) ||
415             (ioc->data_size < offsetof(struct dm_ioctl, data_size))) {
416                 if (entering(tcp))
417                         free(ioc);
418                 return 0;
419         }
420         if (entering(tcp))
421                 set_tcb_priv_data(tcp, ioc, free);
422         else {
423                 entering_ioc = get_tcb_priv_data(tcp);
424
425                 /*
426                  * retrieve_status, __dev_status called only in case of success,
427                  * so it looks like there's no need to check open_count,
428                  * event_nr, target_count, dev fields for change (they are
429                  * printed only in case of absence of errors).
430                  */
431                 if (!entering_ioc ||
432                     (ioc->version[0] != entering_ioc->version[0]) ||
433                     (ioc->version[1] != entering_ioc->version[1]) ||
434                     (ioc->version[2] != entering_ioc->version[2]) ||
435                     (ioc->data_size != entering_ioc->data_size) ||
436                     (ioc->data_start != entering_ioc->data_start) ||
437                     (ioc->flags != entering_ioc->flags))
438                         ioc_changed = true;
439         }
440
441         if (exiting(tcp) && syserror(tcp) && !ioc_changed)
442                 return 1;
443
444         /*
445          * device mapper code uses %d in some places and %u in another, but
446          * fields themselves are declared as __u32.
447          */
448         tprintf("%s{version=%u.%u.%u",  entering(tcp) ? ", " : " => ",
449                 ioc->version[0], ioc->version[1], ioc->version[2]);
450         /*
451          * if we use a different version of ABI, do not attempt to decode
452          * ioctl fields
453          */
454         if (ioc->version[0] != DM_VERSION_MAJOR) {
455                 tprints(", /* Unsupported device mapper ABI version */ ...");
456                 goto skip;
457         }
458
459         tprintf(", data_size=%u", ioc->data_size);
460
461         if (dm_ioctl_has_params(code))
462                 tprintf(", data_start=%u", ioc->data_start);
463
464         if (ioc->data_size < offsetof(struct dm_ioctl, data)) {
465                 tprints(", /* Incorrect data_size */ ...");
466                 goto skip;
467         }
468
469         dm_decode_device(code, ioc);
470         dm_decode_values(tcp, code, ioc);
471         dm_decode_flags(ioc);
472
473         switch (code) {
474         case DM_DEV_WAIT:
475         case DM_TABLE_STATUS:
476                 if (entering(tcp) || syserror(tcp))
477                         break;
478                 dm_decode_dm_target_spec(tcp, arg, ioc);
479                 break;
480         case DM_TABLE_LOAD:
481                 if (exiting(tcp))
482                         break;
483                 dm_decode_dm_target_spec(tcp, arg, ioc);
484                 break;
485         case DM_TABLE_DEPS:
486                 if (entering(tcp) || syserror(tcp))
487                         break;
488                 dm_decode_dm_target_deps(tcp, arg, ioc);
489                 break;
490         case DM_LIST_DEVICES:
491                 if (entering(tcp) || syserror(tcp))
492                         break;
493                 dm_decode_dm_name_list(tcp, arg, ioc);
494                 break;
495         case DM_LIST_VERSIONS:
496                 if (entering(tcp) || syserror(tcp))
497                         break;
498                 dm_decode_dm_target_versions(tcp, arg, ioc);
499                 break;
500         case DM_TARGET_MSG:
501                 if (entering(tcp))
502                         dm_decode_dm_target_msg(tcp, arg, ioc);
503                 else if (!syserror(tcp) && ioc->flags & DM_DATA_OUT_FLAG)
504                         dm_decode_string(tcp, arg, ioc);
505                 break;
506         case DM_DEV_RENAME:
507         case DM_DEV_SET_GEOMETRY:
508                 if (exiting(tcp))
509                         break;
510                 dm_decode_string(tcp, arg, ioc);
511                 break;
512         }
513
514  skip:
515         tprints("}");
516         return 1;
517 }
518
519 int
520 dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
521 {
522         switch (code) {
523         case DM_VERSION:
524         case DM_REMOVE_ALL:
525         case DM_LIST_DEVICES:
526         case DM_DEV_CREATE:
527         case DM_DEV_REMOVE:
528         case DM_DEV_RENAME:
529         case DM_DEV_SUSPEND:
530         case DM_DEV_STATUS:
531         case DM_DEV_WAIT:
532         case DM_TABLE_LOAD:
533         case DM_TABLE_CLEAR:
534         case DM_TABLE_DEPS:
535         case DM_TABLE_STATUS:
536         case DM_LIST_VERSIONS:
537         case DM_TARGET_MSG:
538         case DM_DEV_SET_GEOMETRY:
539                 return dm_known_ioctl(tcp, code, arg);
540         default:
541                 return 0;
542         }
543 }
544
545 # else /* !(DM_VERSION_MAJOR == 4) */
546
547 int
548 dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
549 {
550         return 0;
551 }
552
553 # endif /* DM_VERSION_MAJOR == 4 */
554 #endif /* HAVE_LINUX_DM_IOCTL_H */