blob: 963852f8b3657aa53e8c36e355917cc7a7acf97e [file] [log] [blame]
Elliott Hughesd35df492017-02-15 15:19:05 -08001/*
2 * Support for decoding of DM_* ioctl commands.
3 *
4 * Copyright (c) 2016 Mikulas Patocka <mpatocka@redhat.com>
5 * Copyright (c) 2016 Masatake Yamato <yamato@redhat.com>
6 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
7 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
Elliott Hughes28e98bc2018-06-14 16:59:04 -07008 * Copyright (c) 2016-2018 The strace developers.
Elliott Hughesd35df492017-02-15 15:19:05 -08009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "defs.h"
35
36#ifdef HAVE_LINUX_DM_IOCTL_H
37
Elliott Hughes77c3ff82017-09-08 17:11:00 -070038# include "print_fields.h"
Elliott Hughesd35df492017-02-15 15:19:05 -080039# include <linux/dm-ioctl.h>
40# include <linux/ioctl.h>
41
42# if DM_VERSION_MAJOR == 4
43
44/* Definitions for command which have been added later */
45
46# ifndef DM_LIST_VERSIONS
Elliott Hughesbbf97dc2017-11-15 16:45:52 -080047# define DM_LIST_VERSIONS _IOWR(DM_IOCTL, 0x0d, struct dm_ioctl)
Elliott Hughesd35df492017-02-15 15:19:05 -080048# endif
49# ifndef DM_TARGET_MSG
Elliott Hughesbbf97dc2017-11-15 16:45:52 -080050# define DM_TARGET_MSG _IOWR(DM_IOCTL, 0x0e, struct dm_ioctl)
Elliott Hughesd35df492017-02-15 15:19:05 -080051# endif
52# ifndef DM_DEV_SET_GEOMETRY
Elliott Hughesbbf97dc2017-11-15 16:45:52 -080053# define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, 0x0f, struct dm_ioctl)
54# endif
55# ifndef DM_DEV_ARM_POLL
56# define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, 0x10, struct dm_ioctl)
Elliott Hughesd35df492017-02-15 15:19:05 -080057# endif
58
59
60static void
61dm_decode_device(const unsigned int code, const struct dm_ioctl *ioc)
62{
63 switch (code) {
64 case DM_REMOVE_ALL:
65 case DM_LIST_DEVICES:
66 case DM_LIST_VERSIONS:
67 break;
68 default:
Elliott Hughes77c3ff82017-09-08 17:11:00 -070069 if (ioc->dev)
70 PRINT_FIELD_DEV(", ", *ioc, dev);
71
72 if (ioc->name[0])
73 PRINT_FIELD_CSTRING(", ", *ioc, name);
74
75 if (ioc->uuid[0])
76 PRINT_FIELD_CSTRING(", ", *ioc, uuid);
77
Elliott Hughesd35df492017-02-15 15:19:05 -080078 break;
79 }
80}
81
82static void
83dm_decode_values(struct tcb *tcp, const unsigned int code,
84 const struct dm_ioctl *ioc)
85{
86 if (entering(tcp)) {
87 switch (code) {
88 case DM_TABLE_LOAD:
Elliott Hughes77c3ff82017-09-08 17:11:00 -070089 PRINT_FIELD_U(", ", *ioc, target_count);
Elliott Hughesd35df492017-02-15 15:19:05 -080090 break;
91 case DM_DEV_SUSPEND:
92 if (ioc->flags & DM_SUSPEND_FLAG)
93 break;
Elliott Hughes28e98bc2018-06-14 16:59:04 -070094 ATTRIBUTE_FALLTHROUGH;
Elliott Hughesd35df492017-02-15 15:19:05 -080095 case DM_DEV_RENAME:
96 case DM_DEV_REMOVE:
97 case DM_DEV_WAIT:
Elliott Hughes77c3ff82017-09-08 17:11:00 -070098 PRINT_FIELD_U(", ", *ioc, event_nr);
Elliott Hughesd35df492017-02-15 15:19:05 -080099 break;
100 }
101 } else if (!syserror(tcp)) {
102 switch (code) {
103 case DM_DEV_CREATE:
104 case DM_DEV_RENAME:
105 case DM_DEV_SUSPEND:
106 case DM_DEV_STATUS:
107 case DM_DEV_WAIT:
108 case DM_TABLE_LOAD:
109 case DM_TABLE_CLEAR:
110 case DM_TABLE_DEPS:
111 case DM_TABLE_STATUS:
112 case DM_TARGET_MSG:
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700113 PRINT_FIELD_U(", ", *ioc, target_count);
114 PRINT_FIELD_U(", ", *ioc, open_count);
115 PRINT_FIELD_U(", ", *ioc, event_nr);
Elliott Hughesd35df492017-02-15 15:19:05 -0800116 break;
117 }
118 }
119}
120
121#include "xlat/dm_flags.h"
122
123static void
124dm_decode_flags(const struct dm_ioctl *ioc)
125{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700126 PRINT_FIELD_FLAGS(", ", *ioc, flags, dm_flags, "DM_???");
Elliott Hughesd35df492017-02-15 15:19:05 -0800127}
128
129static void
130dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ulong_t addr,
131 const struct dm_ioctl *const ioc)
132{
133 static const uint32_t target_spec_size =
134 sizeof(struct dm_target_spec);
135 uint32_t i;
136 uint32_t offset = ioc->data_start;
Elliott Hughes39bac052017-05-25 16:56:11 -0700137 uint32_t offset_end = 0;
Elliott Hughesd35df492017-02-15 15:19:05 -0800138
139 if (abbrev(tcp)) {
140 if (ioc->target_count)
141 tprints(", ...");
142
143 return;
144 }
145
146 for (i = 0; i < ioc->target_count; i++) {
Elliott Hughes39bac052017-05-25 16:56:11 -0700147 tprints(", ");
148
149 if (i && offset <= offset_end)
150 goto misplaced;
Elliott Hughesd35df492017-02-15 15:19:05 -0800151
152 offset_end = offset + target_spec_size;
153
154 if (offset_end <= offset || offset_end > ioc->data_size)
155 goto misplaced;
156
Elliott Hughesd35df492017-02-15 15:19:05 -0800157 if (i >= max_strlen) {
158 tprints("...");
159 break;
160 }
161
Elliott Hughes39bac052017-05-25 16:56:11 -0700162 struct dm_target_spec s;
163
Elliott Hughesd35df492017-02-15 15:19:05 -0800164 if (umove_or_printaddr(tcp, addr + offset, &s))
165 break;
166
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700167 PRINT_FIELD_U("{", s, sector_start);
168 PRINT_FIELD_U(", ", s, length);
Elliott Hughesd35df492017-02-15 15:19:05 -0800169
170 if (exiting(tcp))
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700171 PRINT_FIELD_D(", ", s, status);
Elliott Hughesd35df492017-02-15 15:19:05 -0800172
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700173 PRINT_FIELD_CSTRING(", ", s, target_type);
Elliott Hughesd35df492017-02-15 15:19:05 -0800174
175 tprints(", string=");
176 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
177 QUOTE_0_TERMINATED);
Elliott Hughes39bac052017-05-25 16:56:11 -0700178 tprints("}");
Elliott Hughesd35df492017-02-15 15:19:05 -0800179
180 if (entering(tcp))
181 offset += s.next;
182 else
183 offset = ioc->data_start + s.next;
Elliott Hughesd35df492017-02-15 15:19:05 -0800184 }
185
186 return;
187
188misplaced:
Elliott Hughes39bac052017-05-25 16:56:11 -0700189 tprints("???");
190 tprints_comment("misplaced struct dm_target_spec");
Elliott Hughesd35df492017-02-15 15:19:05 -0800191}
192
193bool
194dm_print_dev(struct tcb *tcp, void *dev_ptr, size_t dev_size, void *dummy)
195{
196 uint64_t *dev = (uint64_t *) dev_ptr;
197
198 print_dev_t(*dev);
199
200 return 1;
201}
202
203static void
204dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ulong_t addr,
205 const struct dm_ioctl *const ioc)
206{
Elliott Hughes39bac052017-05-25 16:56:11 -0700207 if (ioc->data_start == ioc->data_size)
208 return;
209
210 tprints(", ");
211
212 if (abbrev(tcp)) {
213 tprints("...");
214 return;
215 }
216
Elliott Hughesd35df492017-02-15 15:19:05 -0800217 static const uint32_t target_deps_dev_offs =
218 offsetof(struct dm_target_deps, dev);
219 uint64_t dev_buf;
220 struct dm_target_deps s;
221 uint32_t offset = ioc->data_start;
222 uint32_t offset_end = offset + target_deps_dev_offs;
223 uint32_t space;
224
Elliott Hughesd35df492017-02-15 15:19:05 -0800225 if (offset_end <= offset || offset_end > ioc->data_size)
226 goto misplaced;
227
228 if (umove_or_printaddr(tcp, addr + offset, &s))
229 return;
230
231 space = (ioc->data_size - offset_end) / sizeof(dev_buf);
232
233 if (s.count > space)
234 goto misplaced;
235
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700236 PRINT_FIELD_U("{", s, count);
Elliott Hughesd35df492017-02-15 15:19:05 -0800237
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700238 tprints(", deps=");
Elliott Hughesd35df492017-02-15 15:19:05 -0800239 print_array(tcp, addr + offset_end, s.count, &dev_buf, sizeof(dev_buf),
Elliott Hughes03a418e2018-06-15 13:11:40 -0700240 tfetch_mem, dm_print_dev, NULL);
Elliott Hughesd35df492017-02-15 15:19:05 -0800241
242 tprints("}");
243
244 return;
245
246misplaced:
Elliott Hughes39bac052017-05-25 16:56:11 -0700247 tprints("???");
248 tprints_comment("misplaced struct dm_target_deps");
Elliott Hughesd35df492017-02-15 15:19:05 -0800249}
250
251static void
252dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
253 const struct dm_ioctl *const ioc)
254{
255 static const uint32_t name_list_name_offs =
256 offsetof(struct dm_name_list, name);
257 struct dm_name_list s;
258 uint32_t offset = ioc->data_start;
Elliott Hughes39bac052017-05-25 16:56:11 -0700259 uint32_t offset_end = 0;
Elliott Hughesd35df492017-02-15 15:19:05 -0800260 uint32_t count;
Elliott Hughesb7556142018-02-20 17:03:16 -0800261 int rc;
Elliott Hughesd35df492017-02-15 15:19:05 -0800262
Elliott Hughes39bac052017-05-25 16:56:11 -0700263 if (ioc->data_start == ioc->data_size)
264 return;
265
Elliott Hughesd35df492017-02-15 15:19:05 -0800266 if (abbrev(tcp)) {
267 tprints(", ...");
268 return;
269 }
270
271 for (count = 0;; count++) {
Elliott Hughes39bac052017-05-25 16:56:11 -0700272 tprints(", ");
273
274 if (count && offset <= offset_end)
275 goto misplaced;
276
Elliott Hughesd35df492017-02-15 15:19:05 -0800277 offset_end = offset + name_list_name_offs;
278
279 if (offset_end <= offset || offset_end > ioc->data_size)
280 goto misplaced;
281
Elliott Hughesd35df492017-02-15 15:19:05 -0800282 if (count >= max_strlen) {
283 tprints("...");
284 break;
285 }
286
287 if (umove_or_printaddr(tcp, addr + offset, &s))
288 break;
Elliott Hughesd35df492017-02-15 15:19:05 -0800289
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700290 PRINT_FIELD_DEV("{", s, dev);
291 tprints(", name=");
Elliott Hughesb7556142018-02-20 17:03:16 -0800292 rc = printstr_ex(tcp, addr + offset_end,
293 ioc->data_size - offset_end,
294 QUOTE_0_TERMINATED);
295
296 /*
297 * In Linux v4.13-rc1~137^2~13 it has been decided to cram in
298 * one more undocumented field after the device name, as if the
299 * format decoding was not twisted enough already. So, we have
300 * to check "next" now, and if it _looks like_ that there is
301 * a space for one additional integer, let's print it. As if the
302 * perversity with "name string going further than pointer to
303 * the next one" wasn't enough. Moreover, the calculation was
304 * broken for m32 on 64-bit kernels until v4.14-rc4~20^2~3, and
305 * we have no ability to detect kernel bit-ness (on x86, at
306 * least), so refrain from printing it for the DM versions below
307 * 4.37 (the original version was also aligned differently than
308 * now even on 64 bit).
309 */
310
311 if ((rc > 0) && ioc->version[1] >= 37) {
312 kernel_ulong_t event_addr =
313 (addr + offset_end + rc + 7) & ~7;
314 uint32_t event_nr;
315
316 if ((event_addr + sizeof(event_nr)) <=
317 (addr + offset + s.next) &&
318 !umove(tcp, event_addr, &event_nr))
319 tprintf(", event_nr=%" PRIu32, event_nr);
320 }
321
Elliott Hughesd35df492017-02-15 15:19:05 -0800322 tprints("}");
323
324 if (!s.next)
325 break;
326
327 offset += s.next;
Elliott Hughesd35df492017-02-15 15:19:05 -0800328 }
329
330 return;
331
332misplaced:
Elliott Hughes39bac052017-05-25 16:56:11 -0700333 tprints("???");
334 tprints_comment("misplaced struct dm_name_list");
Elliott Hughesd35df492017-02-15 15:19:05 -0800335}
336
337static void
338dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ulong_t addr,
339 const struct dm_ioctl *const ioc)
340{
341 static const uint32_t target_vers_name_offs =
342 offsetof(struct dm_target_versions, name);
343 struct dm_target_versions s;
344 uint32_t offset = ioc->data_start;
Elliott Hughes39bac052017-05-25 16:56:11 -0700345 uint32_t offset_end = 0;
Elliott Hughesd35df492017-02-15 15:19:05 -0800346 uint32_t count;
347
Elliott Hughes39bac052017-05-25 16:56:11 -0700348 if (ioc->data_start == ioc->data_size)
349 return;
350
Elliott Hughesd35df492017-02-15 15:19:05 -0800351 if (abbrev(tcp)) {
352 tprints(", ...");
353 return;
354 }
355
356 for (count = 0;; count++) {
Elliott Hughes39bac052017-05-25 16:56:11 -0700357 tprints(", ");
358
359 if (count && offset <= offset_end)
360 goto misplaced;
361
Elliott Hughesd35df492017-02-15 15:19:05 -0800362 offset_end = offset + target_vers_name_offs;
363
364 if (offset_end <= offset || offset_end > ioc->data_size)
365 goto misplaced;
366
Elliott Hughesd35df492017-02-15 15:19:05 -0800367 if (count >= max_strlen) {
368 tprints("...");
369 break;
370 }
371
372 if (umove_or_printaddr(tcp, addr + offset, &s))
373 break;
374
375 tprints("{name=");
376 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
377 QUOTE_0_TERMINATED);
378 tprintf(", version=%" PRIu32 ".%" PRIu32 ".%" PRIu32 "}",
379 s.version[0], s.version[1], s.version[2]);
380
381 if (!s.next)
382 break;
383
384 offset += s.next;
Elliott Hughesd35df492017-02-15 15:19:05 -0800385 }
386
387 return;
388
389misplaced:
Elliott Hughes39bac052017-05-25 16:56:11 -0700390 tprints("???");
391 tprints_comment("misplaced struct dm_target_versions");
Elliott Hughesd35df492017-02-15 15:19:05 -0800392}
393
394static void
395dm_decode_dm_target_msg(struct tcb *const tcp, const kernel_ulong_t addr,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700396 const struct dm_ioctl *const ioc)
Elliott Hughesd35df492017-02-15 15:19:05 -0800397{
Elliott Hughes39bac052017-05-25 16:56:11 -0700398 if (ioc->data_start == ioc->data_size)
399 return;
400
401 tprints(", ");
402
403 if (abbrev(tcp)) {
404 tprints("...");
405 return;
406 }
407
Elliott Hughesd35df492017-02-15 15:19:05 -0800408 static const uint32_t target_msg_message_offs =
409 offsetof(struct dm_target_msg, message);
410 uint32_t offset = ioc->data_start;
411 uint32_t offset_end = offset + target_msg_message_offs;
412
Elliott Hughesd35df492017-02-15 15:19:05 -0800413 if (offset_end > offset && offset_end <= ioc->data_size) {
414 struct dm_target_msg s;
415
Elliott Hughesd35df492017-02-15 15:19:05 -0800416 if (umove_or_printaddr(tcp, addr + offset, &s))
417 return;
418
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700419 PRINT_FIELD_U("{", s, sector);
420 tprints(", message=");
Elliott Hughesd35df492017-02-15 15:19:05 -0800421 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
422 QUOTE_0_TERMINATED);
423 tprints("}");
424 } else {
Elliott Hughes39bac052017-05-25 16:56:11 -0700425 tprints("???");
426 tprints_comment("misplaced struct dm_target_msg");
Elliott Hughesd35df492017-02-15 15:19:05 -0800427 }
428}
429
430static void
431dm_decode_string(struct tcb *const tcp, const kernel_ulong_t addr,
432 const struct dm_ioctl *const ioc)
433{
Elliott Hughes39bac052017-05-25 16:56:11 -0700434 tprints(", ");
Elliott Hughesd35df492017-02-15 15:19:05 -0800435
436 if (abbrev(tcp)) {
Elliott Hughes39bac052017-05-25 16:56:11 -0700437 tprints("...");
Elliott Hughesd35df492017-02-15 15:19:05 -0800438 return;
439 }
440
Elliott Hughes39bac052017-05-25 16:56:11 -0700441 uint32_t offset = ioc->data_start;
442
443 if (offset <= ioc->data_size) {
444 tprints("string=");
Elliott Hughesd35df492017-02-15 15:19:05 -0800445 printstr_ex(tcp, addr + offset, ioc->data_size - offset,
446 QUOTE_0_TERMINATED);
447 } else {
Elliott Hughes39bac052017-05-25 16:56:11 -0700448 tprints("???");
449 tprints_comment("misplaced string");
Elliott Hughesd35df492017-02-15 15:19:05 -0800450 }
451}
452
453static inline bool
454dm_ioctl_has_params(const unsigned int code)
455{
456 switch (code) {
457 case DM_VERSION:
458 case DM_REMOVE_ALL:
459 case DM_DEV_CREATE:
460 case DM_DEV_REMOVE:
461 case DM_DEV_SUSPEND:
462 case DM_DEV_STATUS:
463 case DM_TABLE_CLEAR:
Elliott Hughesbbf97dc2017-11-15 16:45:52 -0800464 case DM_DEV_ARM_POLL:
Elliott Hughesd35df492017-02-15 15:19:05 -0800465 return false;
466 }
467
468 return true;
469}
470
471static int
472dm_known_ioctl(struct tcb *const tcp, const unsigned int code,
473 const kernel_ulong_t arg)
474{
475 struct dm_ioctl *ioc = NULL;
476 struct dm_ioctl *entering_ioc = NULL;
477 bool ioc_changed = false;
478
479 if (entering(tcp)) {
480 ioc = malloc(sizeof(*ioc));
481 if (!ioc)
482 return 0;
483 } else {
484 ioc = alloca(sizeof(*ioc));
485 }
486
487 if ((umoven(tcp, arg, offsetof(struct dm_ioctl, data), ioc) < 0) ||
488 (ioc->data_size < offsetof(struct dm_ioctl, data_size))) {
489 if (entering(tcp))
490 free(ioc);
491 return 0;
492 }
493 if (entering(tcp))
494 set_tcb_priv_data(tcp, ioc, free);
495 else {
496 entering_ioc = get_tcb_priv_data(tcp);
497
498 /*
499 * retrieve_status, __dev_status called only in case of success,
500 * so it looks like there's no need to check open_count,
501 * event_nr, target_count, dev fields for change (they are
502 * printed only in case of absence of errors).
503 */
504 if (!entering_ioc ||
505 (ioc->version[0] != entering_ioc->version[0]) ||
506 (ioc->version[1] != entering_ioc->version[1]) ||
507 (ioc->version[2] != entering_ioc->version[2]) ||
508 (ioc->data_size != entering_ioc->data_size) ||
509 (ioc->data_start != entering_ioc->data_start) ||
510 (ioc->flags != entering_ioc->flags))
511 ioc_changed = true;
512 }
513
514 if (exiting(tcp) && syserror(tcp) && !ioc_changed)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700515 return RVAL_IOCTL_DECODED;
Elliott Hughesd35df492017-02-15 15:19:05 -0800516
517 /*
518 * device mapper code uses %d in some places and %u in another, but
519 * fields themselves are declared as __u32.
520 */
521 tprintf("%s{version=%u.%u.%u", entering(tcp) ? ", " : " => ",
522 ioc->version[0], ioc->version[1], ioc->version[2]);
523 /*
524 * if we use a different version of ABI, do not attempt to decode
525 * ioctl fields
526 */
527 if (ioc->version[0] != DM_VERSION_MAJOR) {
Elliott Hughes39bac052017-05-25 16:56:11 -0700528 tprints_comment("unsupported device mapper ABI version");
Elliott Hughesd35df492017-02-15 15:19:05 -0800529 goto skip;
530 }
531
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700532 PRINT_FIELD_U(", ", *ioc, data_size);
Elliott Hughesd35df492017-02-15 15:19:05 -0800533
Elliott Hughesd35df492017-02-15 15:19:05 -0800534 if (ioc->data_size < offsetof(struct dm_ioctl, data)) {
Elliott Hughes39bac052017-05-25 16:56:11 -0700535 tprints_comment("data_size too small");
Elliott Hughesd35df492017-02-15 15:19:05 -0800536 goto skip;
537 }
538
Elliott Hughes39bac052017-05-25 16:56:11 -0700539 if (dm_ioctl_has_params(code))
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700540 PRINT_FIELD_U(", ", *ioc, data_start);
Elliott Hughes39bac052017-05-25 16:56:11 -0700541
Elliott Hughesd35df492017-02-15 15:19:05 -0800542 dm_decode_device(code, ioc);
543 dm_decode_values(tcp, code, ioc);
544 dm_decode_flags(ioc);
545
546 switch (code) {
547 case DM_DEV_WAIT:
548 case DM_TABLE_STATUS:
549 if (entering(tcp) || syserror(tcp))
550 break;
551 dm_decode_dm_target_spec(tcp, arg, ioc);
552 break;
553 case DM_TABLE_LOAD:
554 if (exiting(tcp))
555 break;
556 dm_decode_dm_target_spec(tcp, arg, ioc);
557 break;
558 case DM_TABLE_DEPS:
559 if (entering(tcp) || syserror(tcp))
560 break;
561 dm_decode_dm_target_deps(tcp, arg, ioc);
562 break;
563 case DM_LIST_DEVICES:
564 if (entering(tcp) || syserror(tcp))
565 break;
566 dm_decode_dm_name_list(tcp, arg, ioc);
567 break;
568 case DM_LIST_VERSIONS:
569 if (entering(tcp) || syserror(tcp))
570 break;
571 dm_decode_dm_target_versions(tcp, arg, ioc);
572 break;
573 case DM_TARGET_MSG:
574 if (entering(tcp))
575 dm_decode_dm_target_msg(tcp, arg, ioc);
576 else if (!syserror(tcp) && ioc->flags & DM_DATA_OUT_FLAG)
577 dm_decode_string(tcp, arg, ioc);
578 break;
579 case DM_DEV_RENAME:
580 case DM_DEV_SET_GEOMETRY:
581 if (exiting(tcp))
582 break;
583 dm_decode_string(tcp, arg, ioc);
584 break;
585 }
586
587 skip:
588 tprints("}");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700589 return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
Elliott Hughesd35df492017-02-15 15:19:05 -0800590}
591
592int
593dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
594{
595 switch (code) {
596 case DM_VERSION:
597 case DM_REMOVE_ALL:
598 case DM_LIST_DEVICES:
599 case DM_DEV_CREATE:
600 case DM_DEV_REMOVE:
601 case DM_DEV_RENAME:
602 case DM_DEV_SUSPEND:
603 case DM_DEV_STATUS:
604 case DM_DEV_WAIT:
605 case DM_TABLE_LOAD:
606 case DM_TABLE_CLEAR:
607 case DM_TABLE_DEPS:
608 case DM_TABLE_STATUS:
609 case DM_LIST_VERSIONS:
610 case DM_TARGET_MSG:
611 case DM_DEV_SET_GEOMETRY:
Elliott Hughesbbf97dc2017-11-15 16:45:52 -0800612 case DM_DEV_ARM_POLL:
Elliott Hughesd35df492017-02-15 15:19:05 -0800613 return dm_known_ioctl(tcp, code, arg);
614 default:
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700615 return RVAL_DECODED;
Elliott Hughesd35df492017-02-15 15:19:05 -0800616 }
617}
618
619# else /* !(DM_VERSION_MAJOR == 4) */
620
621int
622dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
623{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700624 return RVAL_DECODED;
Elliott Hughesd35df492017-02-15 15:19:05 -0800625}
626
627# endif /* DM_VERSION_MAJOR == 4 */
628#endif /* HAVE_LINUX_DM_IOCTL_H */