2 * Support for decoding of DM_* ioctl commands.
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>
8 * Copyright (c) 2016-2017 The strace developers.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
36 #ifdef HAVE_LINUX_DM_IOCTL_H
38 # include "print_fields.h"
39 # include <linux/dm-ioctl.h>
40 # include <linux/ioctl.h>
42 # if DM_VERSION_MAJOR == 4
44 /* Definitions for command which have been added later */
46 # ifndef DM_LIST_VERSIONS
47 # define DM_LIST_VERSIONS _IOWR(DM_IOCTL, 0x0d, struct dm_ioctl)
49 # ifndef DM_TARGET_MSG
50 # define DM_TARGET_MSG _IOWR(DM_IOCTL, 0x0e, struct dm_ioctl)
52 # ifndef DM_DEV_SET_GEOMETRY
53 # define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, 0x0f, struct dm_ioctl)
55 # ifndef DM_DEV_ARM_POLL
56 # define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, 0x10, struct dm_ioctl)
61 dm_decode_device(const unsigned int code, const struct dm_ioctl *ioc)
66 case DM_LIST_VERSIONS:
70 PRINT_FIELD_DEV(", ", *ioc, dev);
73 PRINT_FIELD_CSTRING(", ", *ioc, name);
76 PRINT_FIELD_CSTRING(", ", *ioc, uuid);
83 dm_decode_values(struct tcb *tcp, const unsigned int code,
84 const struct dm_ioctl *ioc)
89 PRINT_FIELD_U(", ", *ioc, target_count);
92 if (ioc->flags & DM_SUSPEND_FLAG)
98 PRINT_FIELD_U(", ", *ioc, event_nr);
101 } else if (!syserror(tcp)) {
111 case DM_TABLE_STATUS:
113 PRINT_FIELD_U(", ", *ioc, target_count);
114 PRINT_FIELD_U(", ", *ioc, open_count);
115 PRINT_FIELD_U(", ", *ioc, event_nr);
121 #include "xlat/dm_flags.h"
124 dm_decode_flags(const struct dm_ioctl *ioc)
126 PRINT_FIELD_FLAGS(", ", *ioc, flags, dm_flags, "DM_???");
130 dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ulong_t addr,
131 const struct dm_ioctl *const ioc)
133 static const uint32_t target_spec_size =
134 sizeof(struct dm_target_spec);
136 uint32_t offset = ioc->data_start;
137 uint32_t offset_end = 0;
140 if (ioc->target_count)
146 for (i = 0; i < ioc->target_count; i++) {
149 if (i && offset <= offset_end)
152 offset_end = offset + target_spec_size;
154 if (offset_end <= offset || offset_end > ioc->data_size)
157 if (i >= max_strlen) {
162 struct dm_target_spec s;
164 if (umove_or_printaddr(tcp, addr + offset, &s))
167 PRINT_FIELD_U("{", s, sector_start);
168 PRINT_FIELD_U(", ", s, length);
171 PRINT_FIELD_D(", ", s, status);
173 PRINT_FIELD_CSTRING(", ", s, target_type);
175 tprints(", string=");
176 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
183 offset = ioc->data_start + s.next;
190 tprints_comment("misplaced struct dm_target_spec");
194 dm_print_dev(struct tcb *tcp, void *dev_ptr, size_t dev_size, void *dummy)
196 uint64_t *dev = (uint64_t *) dev_ptr;
204 dm_decode_dm_target_deps(struct tcb *const tcp, const kernel_ulong_t addr,
205 const struct dm_ioctl *const ioc)
207 if (ioc->data_start == ioc->data_size)
217 static const uint32_t target_deps_dev_offs =
218 offsetof(struct dm_target_deps, dev);
220 struct dm_target_deps s;
221 uint32_t offset = ioc->data_start;
222 uint32_t offset_end = offset + target_deps_dev_offs;
225 if (offset_end <= offset || offset_end > ioc->data_size)
228 if (umove_or_printaddr(tcp, addr + offset, &s))
231 space = (ioc->data_size - offset_end) / sizeof(dev_buf);
236 PRINT_FIELD_U("{", s, count);
239 print_array(tcp, addr + offset_end, s.count, &dev_buf, sizeof(dev_buf),
240 umoven_or_printaddr, dm_print_dev, NULL);
248 tprints_comment("misplaced struct dm_target_deps");
252 dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
253 const struct dm_ioctl *const ioc)
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;
259 uint32_t offset_end = 0;
262 if (ioc->data_start == ioc->data_size)
270 for (count = 0;; count++) {
273 if (count && offset <= offset_end)
276 offset_end = offset + name_list_name_offs;
278 if (offset_end <= offset || offset_end > ioc->data_size)
281 if (count >= max_strlen) {
286 if (umove_or_printaddr(tcp, addr + offset, &s))
289 PRINT_FIELD_DEV("{", s, dev);
291 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
305 tprints_comment("misplaced struct dm_name_list");
309 dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ulong_t addr,
310 const struct dm_ioctl *const ioc)
312 static const uint32_t target_vers_name_offs =
313 offsetof(struct dm_target_versions, name);
314 struct dm_target_versions s;
315 uint32_t offset = ioc->data_start;
316 uint32_t offset_end = 0;
319 if (ioc->data_start == ioc->data_size)
327 for (count = 0;; count++) {
330 if (count && offset <= offset_end)
333 offset_end = offset + target_vers_name_offs;
335 if (offset_end <= offset || offset_end > ioc->data_size)
338 if (count >= max_strlen) {
343 if (umove_or_printaddr(tcp, addr + offset, &s))
347 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
349 tprintf(", version=%" PRIu32 ".%" PRIu32 ".%" PRIu32 "}",
350 s.version[0], s.version[1], s.version[2]);
362 tprints_comment("misplaced struct dm_target_versions");
366 dm_decode_dm_target_msg(struct tcb *const tcp, const kernel_ulong_t addr,
367 const struct dm_ioctl *const ioc)
369 if (ioc->data_start == ioc->data_size)
379 static const uint32_t target_msg_message_offs =
380 offsetof(struct dm_target_msg, message);
381 uint32_t offset = ioc->data_start;
382 uint32_t offset_end = offset + target_msg_message_offs;
384 if (offset_end > offset && offset_end <= ioc->data_size) {
385 struct dm_target_msg s;
387 if (umove_or_printaddr(tcp, addr + offset, &s))
390 PRINT_FIELD_U("{", s, sector);
391 tprints(", message=");
392 printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
397 tprints_comment("misplaced struct dm_target_msg");
402 dm_decode_string(struct tcb *const tcp, const kernel_ulong_t addr,
403 const struct dm_ioctl *const ioc)
412 uint32_t offset = ioc->data_start;
414 if (offset <= ioc->data_size) {
416 printstr_ex(tcp, addr + offset, ioc->data_size - offset,
420 tprints_comment("misplaced string");
425 dm_ioctl_has_params(const unsigned int code)
435 case DM_DEV_ARM_POLL:
443 dm_known_ioctl(struct tcb *const tcp, const unsigned int code,
444 const kernel_ulong_t arg)
446 struct dm_ioctl *ioc = NULL;
447 struct dm_ioctl *entering_ioc = NULL;
448 bool ioc_changed = false;
451 ioc = malloc(sizeof(*ioc));
455 ioc = alloca(sizeof(*ioc));
458 if ((umoven(tcp, arg, offsetof(struct dm_ioctl, data), ioc) < 0) ||
459 (ioc->data_size < offsetof(struct dm_ioctl, data_size))) {
465 set_tcb_priv_data(tcp, ioc, free);
467 entering_ioc = get_tcb_priv_data(tcp);
470 * retrieve_status, __dev_status called only in case of success,
471 * so it looks like there's no need to check open_count,
472 * event_nr, target_count, dev fields for change (they are
473 * printed only in case of absence of errors).
476 (ioc->version[0] != entering_ioc->version[0]) ||
477 (ioc->version[1] != entering_ioc->version[1]) ||
478 (ioc->version[2] != entering_ioc->version[2]) ||
479 (ioc->data_size != entering_ioc->data_size) ||
480 (ioc->data_start != entering_ioc->data_start) ||
481 (ioc->flags != entering_ioc->flags))
485 if (exiting(tcp) && syserror(tcp) && !ioc_changed)
486 return RVAL_IOCTL_DECODED;
489 * device mapper code uses %d in some places and %u in another, but
490 * fields themselves are declared as __u32.
492 tprintf("%s{version=%u.%u.%u", entering(tcp) ? ", " : " => ",
493 ioc->version[0], ioc->version[1], ioc->version[2]);
495 * if we use a different version of ABI, do not attempt to decode
498 if (ioc->version[0] != DM_VERSION_MAJOR) {
499 tprints_comment("unsupported device mapper ABI version");
503 PRINT_FIELD_U(", ", *ioc, data_size);
505 if (ioc->data_size < offsetof(struct dm_ioctl, data)) {
506 tprints_comment("data_size too small");
510 if (dm_ioctl_has_params(code))
511 PRINT_FIELD_U(", ", *ioc, data_start);
513 dm_decode_device(code, ioc);
514 dm_decode_values(tcp, code, ioc);
515 dm_decode_flags(ioc);
519 case DM_TABLE_STATUS:
520 if (entering(tcp) || syserror(tcp))
522 dm_decode_dm_target_spec(tcp, arg, ioc);
527 dm_decode_dm_target_spec(tcp, arg, ioc);
530 if (entering(tcp) || syserror(tcp))
532 dm_decode_dm_target_deps(tcp, arg, ioc);
534 case DM_LIST_DEVICES:
535 if (entering(tcp) || syserror(tcp))
537 dm_decode_dm_name_list(tcp, arg, ioc);
539 case DM_LIST_VERSIONS:
540 if (entering(tcp) || syserror(tcp))
542 dm_decode_dm_target_versions(tcp, arg, ioc);
546 dm_decode_dm_target_msg(tcp, arg, ioc);
547 else if (!syserror(tcp) && ioc->flags & DM_DATA_OUT_FLAG)
548 dm_decode_string(tcp, arg, ioc);
551 case DM_DEV_SET_GEOMETRY:
554 dm_decode_string(tcp, arg, ioc);
560 return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
564 dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
569 case DM_LIST_DEVICES:
579 case DM_TABLE_STATUS:
580 case DM_LIST_VERSIONS:
582 case DM_DEV_SET_GEOMETRY:
583 case DM_DEV_ARM_POLL:
584 return dm_known_ioctl(tcp, code, arg);
590 # else /* !(DM_VERSION_MAJOR == 4) */
593 dm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
598 # endif /* DM_VERSION_MAJOR == 4 */
599 #endif /* HAVE_LINUX_DM_IOCTL_H */