]> granicus.if.org Git - strace/blob - tests/ioctl_dm.c
Add support for decoding of DM_* ioctl commands
[strace] / tests / ioctl_dm.c
1 /*
2  * Check decoding of DM_* commands of ioctl syscall.
3  *
4  * Copyright (c) 2016 Mikulas Patocka <mpatocka@redhat.com>
5  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "tests.h"
32
33 #ifdef HAVE_LINUX_DM_IOCTL_H
34
35 # include <errno.h>
36 # include <inttypes.h>
37 # include <stdbool.h>
38 # include <stdio.h>
39 # include <stddef.h>
40 # include <string.h>
41 # include <sys/ioctl.h>
42 # include <linux/dm-ioctl.h>
43
44 # ifndef VERBOSE
45 #  define VERBOSE 0
46 # endif
47
48 # define STR32 "AbCdEfGhIjKlMnOpQrStUvWxYz012345"
49
50 # define ALIGNED_SIZE(s_, t_) \
51         (((s_) + (ALIGNOF(t_) - 1UL)) & ~(ALIGNOF(t_) - 1UL))
52 # define ALIGNED_OFFSET(t_, m_) \
53         ALIGNED_SIZE(offsetof(t_, m_), t_)
54
55 static const char str129[] = STR32 STR32 STR32 STR32 "6";
56
57 static const __u64 dts_sector_base = (__u64) 0xdeadca75facef157ULL;
58 static const __u64 dts_sector_step = (__u64) 0x100000001ULL;
59 static const __u64 dts_length_base = (__u64) 0xbadc0dedda7a1057ULL;
60 static const __u64 dts_length_step = (__u64) 0x700000007ULL;
61 static const __s32 dts_status_base = (__s32) 3141592653U;
62 static const __s32 dts_status_step = 0x1234;
63
64 static const size_t min_sizeof_dm_ioctl =
65         offsetof(struct dm_ioctl, data);
66
67 static struct s {
68         struct dm_ioctl ioc;
69         union {
70                 struct {
71                         struct dm_target_spec target_spec;
72                         char target_params[256];
73                 } ts;
74                 struct {
75                         struct dm_target_msg target_msg;
76                         char target_string[256];
77                 } tm;
78                 char string[256];
79         } u;
80 } s;
81
82 struct dm_table_open_test {
83         struct dm_ioctl ioc;
84         struct dm_target_spec target0;
85         char param0[1];
86         struct dm_target_spec target1;
87         char param1[2];
88         struct dm_target_spec target2;
89         char param2[3];
90         struct dm_target_spec target3;
91         char param3[4];
92         struct dm_target_spec target4;
93         char param4[5];
94         struct dm_target_spec target5;
95         char param5[6];
96         struct dm_target_spec target6;
97         char param6[7];
98         struct dm_target_spec target7;
99         char param7[8];
100         struct dm_target_spec target8;
101         char param8[9];
102         struct dm_target_spec target9;
103         char param9[10];
104 };
105
106 struct dm_target_msg_test {
107         struct dm_ioctl ioc;
108         struct dm_target_msg msg;
109 };
110
111 struct args {
112         unsigned int arg;
113         const char *str;
114         bool has_params;
115         bool has_event_nr;
116 };
117
118
119 static void
120 init_s(struct dm_ioctl *s, size_t size, size_t offs)
121 {
122         memset(s, 0, size);
123         s->version[0] = DM_VERSION_MAJOR;
124         s->version[1] = 1;
125         s->version[2] = 2;
126         s->data_size = size;
127         s->data_start = offs;
128         s->dev = 0x1234;
129         strcpy(s->name, "nnn");
130         strcpy(s->uuid, "uuu");
131 }
132
133 static void
134 init_dm_target_spec(struct dm_target_spec *ptr, uint32_t id)
135 {
136         ptr->sector_start = dts_sector_base + dts_sector_step * id;
137         ptr->length       = dts_length_base + dts_length_step * id;
138         ptr->status       = dts_status_base + dts_status_step * id;
139
140         strncpy(ptr->target_type, str129 +
141                 id % (sizeof(str129) - sizeof(ptr->target_type)),
142                 id % (sizeof(ptr->target_type) + 1));
143         if (id % (sizeof(ptr->target_type) + 1) < sizeof(ptr->target_type))
144                 ptr->target_type[id % (sizeof(ptr->target_type) + 1)] = '\0';
145 }
146
147 # if VERBOSE
148 static void
149 print_dm_target_spec(struct dm_target_spec *ptr, uint32_t id)
150 {
151         printf("{sector_start=%" PRI__u64 ", length=%" PRI__u64 ", "
152                "target_type=\"%.*s\", string=",
153                dts_sector_base + dts_sector_step * id,
154                dts_length_base + dts_length_step * id,
155                (int) (id % (sizeof(ptr->target_type) + 1)),
156                str129 + id % (sizeof(str129) - sizeof(ptr->target_type)));
157 }
158 # endif /* VERBOSE */
159
160 int
161 main(void)
162 {
163         /* We can't check these properly for now */
164         static struct args dummy_check_cmds_nodev[] = {
165                 { ARG_STR(DM_REMOVE_ALL),    false },
166                 { ARG_STR(DM_LIST_DEVICES),  true  },
167                 { ARG_STR(DM_LIST_VERSIONS), true  },
168         };
169         static struct args dummy_check_cmds[] = {
170                 { ARG_STR(DM_DEV_CREATE),    false },
171                 { ARG_STR(DM_DEV_REMOVE),    false, true },
172                 { ARG_STR(DM_DEV_STATUS),    false },
173                 { ARG_STR(DM_DEV_WAIT),      true,  true },
174                 { ARG_STR(DM_TABLE_CLEAR),   false },
175                 { ARG_STR(DM_TABLE_DEPS),    true  },
176                 { ARG_STR(DM_TABLE_STATUS),  true  },
177         };
178
179         struct dm_ioctl *unaligned_dm_arg =
180                 tail_alloc(offsetof(struct dm_ioctl, data));
181         struct dm_ioctl *dm_arg =
182                 tail_alloc(ALIGNED_OFFSET(struct dm_ioctl, data));
183         struct dm_table_open_test *dm_arg_open1 =
184                 tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, target1));
185         struct dm_table_open_test *dm_arg_open2 =
186                 tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, param1));
187         struct dm_table_open_test *dm_arg_open3 =
188                 tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, target9));
189         struct dm_target_msg_test *dm_arg_msg =
190                 tail_alloc(sizeof(*dm_arg_msg));
191
192         long rc;
193         const char *errstr;
194         unsigned int i;
195
196
197         /* Incorrect operation */
198         ioctl(-1, _IOW(DM_IOCTL, 0xde, int), dm_arg);
199         printf("ioctl(-1, _IOC(_IOC_WRITE, %#04x, 0xde, %#04zx), %p) = "
200                "-1 EBADF (%m)\n",
201                DM_IOCTL, sizeof(int), dm_arg);
202
203
204         /* DM_VERSION */
205         /* Incorrect pointer */
206         ioctl(-1, DM_VERSION, dm_arg + 1);
207         printf("ioctl(-1, DM_VERSION, %p) = -1 EBADF (%m)\n", dm_arg + 1);
208
209         /* Incorrect data_size */
210         init_s(dm_arg, 0, 0);
211         ioctl(-1, DM_VERSION, &s);
212         printf("ioctl(-1, DM_VERSION, %p) = -1 EBADF (%m)\n", &s);
213
214         /* Incorrect version */
215         init_s(dm_arg, min_sizeof_dm_ioctl, 0);
216         dm_arg->version[0] = 0xbadc0ded;
217         dm_arg->version[1] = 0xbadc0dee;
218         dm_arg->version[2] = 0xbadc0def;
219         ioctl(-1, DM_VERSION, dm_arg);
220         printf("ioctl(-1, DM_VERSION, {version=%u.%u.%u, "
221                "/* Unsupported device mapper ABI version */ ...}) = "
222                "-1 EBADF (%m)\n", 0xbadc0ded, 0xbadc0dee, 0xbadc0def);
223
224         /* Incorrect data_size */
225         init_s(dm_arg, 14, 64);
226         ioctl(-1, DM_VERSION, dm_arg);
227         printf("ioctl(-1, DM_VERSION, {version=4.1.2, data_size=14, "
228                "/* Incorrect data_size */ ...}) = -1 EBADF (%m)\n");
229
230         /* Unterminated name/uuid */
231         init_s(dm_arg, min_sizeof_dm_ioctl, 0);
232         strncpy(dm_arg->name, str129, sizeof(dm_arg->name));
233         strncpy(dm_arg->uuid, str129, sizeof(dm_arg->uuid));
234         ioctl(-1, DM_VERSION, dm_arg);
235         printf("ioctl(-1, DM_VERSION, {version=4.1.2, data_size=%zu, "
236                "dev=makedev(18, 52), name=\"%.127s\", uuid=\"%.128s\", "
237                "flags=0}) = -1 EBADF (%m)\n",
238                min_sizeof_dm_ioctl, str129, str129);
239
240         /* Normal call */
241         init_s(dm_arg, min_sizeof_dm_ioctl, 0);
242         ioctl(-1, DM_VERSION, dm_arg);
243         printf("ioctl(-1, DM_VERSION, "
244                "{version=4.1.2, data_size=%zu, "
245                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0}) = "
246                "-1 EBADF (%m)\n", min_sizeof_dm_ioctl);
247
248         /* Zero dev, name, uuid */
249         init_s(dm_arg, min_sizeof_dm_ioctl, 0);
250         dm_arg->data_size = 0xfacefeed;
251         dm_arg->dev = 0;
252         dm_arg->name[0] = '\0';
253         dm_arg->uuid[0] = '\0';
254         ioctl(-1, DM_VERSION, dm_arg);
255         printf("ioctl(-1, DM_VERSION, "
256                "{version=4.1.2, data_size=%u, flags=0}) = "
257                "-1 EBADF (%m)\n", 0xfacefeed);
258
259         /* Flag */
260         init_s(dm_arg, min_sizeof_dm_ioctl, 0);
261         dm_arg->flags = 0xffffffff;
262         ioctl(-1, DM_VERSION, dm_arg);
263         printf("ioctl(-1, DM_VERSION, "
264                "{version=4.1.2, data_size=%zu, "
265                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags="
266                "DM_READONLY_FLAG|DM_SUSPEND_FLAG|DM_EXISTS_FLAG|"
267                "DM_PERSISTENT_DEV_FLAG|DM_STATUS_TABLE_FLAG|"
268                "DM_ACTIVE_PRESENT_FLAG|DM_INACTIVE_PRESENT_FLAG|"
269                "DM_BUFFER_FULL_FLAG|DM_SKIP_BDGET_FLAG|DM_SKIP_LOCKFS_FLAG|"
270                "DM_NOFLUSH_FLAG|DM_QUERY_INACTIVE_TABLE_FLAG|"
271                "DM_UEVENT_GENERATED_FLAG|DM_UUID_FLAG|DM_SECURE_DATA_FLAG|"
272                "DM_DATA_OUT_FLAG|DM_DEFERRED_REMOVE|DM_INTERNAL_SUSPEND_FLAG|"
273                "0xfff80080}) = -1 EBADF (%m)\n",
274                min_sizeof_dm_ioctl);
275
276         /* Normal call */
277         init_s(&s.ioc, sizeof(s.ioc), 0);
278         ioctl(-1, DM_VERSION, &s);
279         printf("ioctl(-1, DM_VERSION, "
280                "{version=4.1.2, data_size=%zu, "
281                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0}) = "
282                "-1 EBADF (%m)\n", sizeof(s.ioc));
283
284
285         /* DM_REMOVE_ALL */
286         /* DM_LIST_DEVICES */
287         /* DM_LIST_VERSIONS */
288         for (i = 0; i < ARRAY_SIZE(dummy_check_cmds_nodev); i++) {
289                 init_s(dm_arg, min_sizeof_dm_ioctl, 0);
290                 ioctl(-1, dummy_check_cmds_nodev[i].arg, dm_arg);
291                 printf("ioctl(-1, %s, {version=4.1.2, data_size=%zu%s, "
292                        "flags=0}) = -1 EBADF (%m)\n",
293                        dummy_check_cmds_nodev[i].str,
294                        min_sizeof_dm_ioctl,
295                        dummy_check_cmds_nodev[i].has_params ?
296                        ", data_start=0" : "");
297         }
298
299
300         /* DM_DEV_CREATE */
301         /* DM_DEV_REMOVE */
302         /* DM_DEV_STATUS */
303         /* DM_DEV_WAIT */
304         /* DM_TABLE_CLEAR */
305         /* DM_TABLE_DEPS */
306         /* DM_TABLE_STATUS */
307         for (i = 0; i < ARRAY_SIZE(dummy_check_cmds); i++) {
308                 init_s(dm_arg, min_sizeof_dm_ioctl, 0);
309                 ioctl(-1, dummy_check_cmds[i].arg, dm_arg);
310                 printf("ioctl(-1, %s, {version=4.1.2, data_size=%zu%s, "
311                        "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\"%s, "
312                        "flags=0}) = -1 EBADF (%m)\n",
313                        dummy_check_cmds[i].str, min_sizeof_dm_ioctl,
314                        dummy_check_cmds[i].has_params ? ", data_start=0" : "",
315                        dummy_check_cmds[i].has_event_nr ? ", event_nr=0" : "");
316         }
317
318
319         /* DM_DEV_SUSPEND */
320         init_s(&s.ioc, sizeof(s.ioc), 0);
321         s.ioc.flags = DM_SUSPEND_FLAG;
322         s.ioc.event_nr = 0xbadc0ded;
323         ioctl(-1, DM_DEV_SUSPEND, &s);
324         printf("ioctl(-1, DM_DEV_SUSPEND, "
325                "{version=4.1.2, data_size=%zu, "
326                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
327                "flags=DM_SUSPEND_FLAG}) = -1 EBADF (%m)\n", sizeof(s.ioc));
328
329         init_s(&s.ioc, sizeof(s.ioc), 0);
330         s.ioc.event_nr = 0xbadc0ded;
331         ioctl(-1, DM_DEV_SUSPEND, &s);
332         printf("ioctl(-1, DM_DEV_SUSPEND, "
333                "{version=4.1.2, data_size=%zu, dev=makedev(18, 52), "
334                "name=\"nnn\", uuid=\"uuu\", event_nr=3134983661, "
335                "flags=0}) = -1 EBADF (%m)\n", sizeof(s.ioc));
336
337
338         /* DM_TABLE_LOAD */
339         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
340         s.ioc.target_count = 1;
341         s.u.ts.target_spec.sector_start = 0x10;
342         s.u.ts.target_spec.length = 0x20;
343         s.u.ts.target_spec.next =
344                 sizeof(s.u.ts.target_spec) + sizeof(s.u.ts.target_params);
345         strcpy(s.u.ts.target_spec.target_type, "tgt");
346         strcpy(s.u.ts.target_params, "tparams");
347         ioctl(-1, DM_TABLE_LOAD, &s);
348         printf("ioctl(-1, DM_TABLE_LOAD, "
349                "{version=4.1.2, data_size=%u, data_start=%u, "
350                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
351                "target_count=1, flags=0, "
352 # if VERBOSE
353                "{sector_start=16, length=32, target_type=\"tgt\", "
354                "string=\"tparams\"}"
355 # else /* !VERBOSE */
356                "..."
357 # endif /* VERBOSE */
358                "}) = -1 EBADF (%m)\n", s.ioc.data_size, s.ioc.data_start);
359
360         /* No targets */
361         init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
362         dm_arg->data_size = sizeof(*dm_arg);
363         dm_arg->target_count = 0;
364         ioctl(-1, DM_TABLE_LOAD, dm_arg);
365         printf("ioctl(-1, DM_TABLE_LOAD, "
366                "{version=4.1.2, data_size=%zu, data_start=%zu, "
367                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
368                "target_count=0, flags=0}) = -1 EBADF (%m)\n",
369                sizeof(*dm_arg), min_sizeof_dm_ioctl);
370
371         /* Invalid data_start */
372         init_s(dm_arg, min_sizeof_dm_ioctl, 0xfffffff8);
373         dm_arg->data_size = sizeof(*dm_arg);
374         dm_arg->target_count = 1234;
375         ioctl(-1, DM_TABLE_LOAD, dm_arg);
376         printf("ioctl(-1, DM_TABLE_LOAD, "
377                "{version=4.1.2, data_size=%zu, data_start=%u, "
378                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
379                "target_count=1234, flags=0, "
380 # if VERBOSE
381                "/* misplaced struct dm_target_spec */ ..."
382 # else /* !VERBOSE */
383                "..."
384 # endif /* VERBOSE */
385                "}) = -1 EBADF (%m)\n", sizeof(*dm_arg), 0xfffffff8);
386
387         /* Inaccessible pointer */
388         init_s(&dm_arg_open1->ioc, offsetof(struct dm_table_open_test, target1),
389                offsetof(struct dm_table_open_test, target1));
390         dm_arg_open1->ioc.data_size = sizeof(*dm_arg_open1);
391         dm_arg_open1->ioc.target_count = 0xdeaddea1;
392         ioctl(-1, DM_TABLE_LOAD, dm_arg_open1);
393         printf("ioctl(-1, DM_TABLE_LOAD, "
394                "{version=4.1.2, data_size=%zu, data_start=%zu, "
395                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
396                "target_count=3735936673, flags=0, "
397 # if VERBOSE
398                "%p"
399 # else /* !VERBOSE */
400                "..."
401 # endif /* VERBOSE */
402                "}) = -1 EBADF (%m)\n", sizeof(*dm_arg_open1),
403                offsetof(struct dm_table_open_test, target1)
404 # if VERBOSE
405                , (char *) dm_arg_open1 +
406                offsetof(struct dm_table_open_test, target1)
407 # endif /* VERBOSE */
408                );
409
410         /* Inaccessible string */
411         init_s(&dm_arg_open2->ioc, offsetof(struct dm_table_open_test, param1),
412                offsetof(struct dm_table_open_test, target1));
413         dm_arg_open2->ioc.data_size = sizeof(*dm_arg_open2);
414         dm_arg_open2->ioc.target_count = 2;
415         init_dm_target_spec(&dm_arg_open2->target1, 7);
416         dm_arg_open2->target1.next =
417                 offsetof(struct dm_table_open_test, target3) -
418                 offsetof(struct dm_table_open_test, target1);
419         rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open2);
420         errstr = sprintrc(rc);
421         printf("ioctl(-1, DM_TABLE_LOAD, "
422                "{version=4.1.2, data_size=%zu, data_start=%zu, "
423                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
424                "target_count=2, flags=0, ",
425                sizeof(*dm_arg_open2),
426                offsetof(struct dm_table_open_test, target1));
427 # if VERBOSE
428         print_dm_target_spec(&dm_arg_open2->target1, 7);
429         printf("%p}, %p",
430                (char *) dm_arg_open2 +
431                offsetof(struct dm_table_open_test, param1),
432                (char *) dm_arg_open2 +
433                offsetof(struct dm_table_open_test, target3));
434 # else /* !VERBOSE */
435         printf("...");
436 # endif /* VERBOSE */
437         printf("}) = %s\n", errstr);
438
439         /* Incorrect next */
440         init_s(&dm_arg_open3->ioc, offsetof(struct dm_table_open_test, target5),
441                offsetof(struct dm_table_open_test, target0));
442         dm_arg_open3->ioc.target_count = 4;
443
444         init_dm_target_spec(&dm_arg_open3->target0, 9);
445         dm_arg_open3->target0.next =
446                 offsetof(struct dm_table_open_test, target1) -
447                 offsetof(struct dm_table_open_test, target0);
448         dm_arg_open3->param0[0] = '\0';
449
450         init_dm_target_spec(&dm_arg_open3->target1, 15);
451         dm_arg_open3->target1.next =
452                 offsetof(struct dm_table_open_test, target3) -
453                 offsetof(struct dm_table_open_test, target1);
454         dm_arg_open3->param1[0] = '\377';
455         dm_arg_open3->param1[1] = '\0';
456
457         init_dm_target_spec(&dm_arg_open3->target3, 42);
458         dm_arg_open3->target3.next = 0xdeadbeef;
459         dm_arg_open3->param3[0] = '\1';
460         dm_arg_open3->param3[1] = '\2';
461         dm_arg_open3->param3[2] = '\0';
462
463         rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open3);
464         errstr = sprintrc(rc);
465         printf("ioctl(-1, DM_TABLE_LOAD, "
466                "{version=4.1.2, data_size=%zu, data_start=%zu, "
467                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
468                "target_count=4, flags=0, ",
469                offsetof(struct dm_table_open_test, target5),
470                offsetof(struct dm_table_open_test, target0));
471 # if VERBOSE
472         print_dm_target_spec(&dm_arg_open3->target0, 9);
473         printf("\"\"}, ");
474         print_dm_target_spec(&dm_arg_open3->target1, 15);
475         printf("\"\\377\"}, ");
476         print_dm_target_spec(&dm_arg_open3->target1, 42);
477         printf("\"\\1\\2\"}, /* misplaced struct dm_target_spec */ ...");
478 # else /* !VERBOSE */
479         printf("...");
480 # endif /* VERBOSE */
481         printf("}) = %s\n", errstr);
482
483         #define FILL_DM_TARGET(id, id_next) \
484                 do { \
485                         init_dm_target_spec(&dm_arg_open3->target##id, id); \
486                         dm_arg_open3->target##id.next = \
487                                 offsetof(struct dm_table_open_test, \
488                                          target##id_next) - \
489                                 offsetof(struct dm_table_open_test, \
490                                          target##id); \
491                         strncpy(dm_arg_open3->param##id, str129 + id * 2, id); \
492                         dm_arg_open3->param##id[id] = '\0'; \
493                 } while (0)
494         #define PRINT_DM_TARGET(id) \
495                 do { \
496                         print_dm_target_spec(&dm_arg_open3->target##id, id); \
497                         printf("\"%.*s\"}, ", id, str129 + id * 2); \
498                 } while (0)
499
500         /* max_strlen limit */
501         init_s(&dm_arg_open3->ioc, offsetof(struct dm_table_open_test, target9),
502                offsetof(struct dm_table_open_test, target0));
503         dm_arg_open3->ioc.data_size = sizeof(*dm_arg_open3);
504         dm_arg_open3->ioc.target_count = 0xbadc0ded;
505         FILL_DM_TARGET(0, 1);
506         FILL_DM_TARGET(1, 2);
507         FILL_DM_TARGET(2, 3);
508         FILL_DM_TARGET(3, 4);
509         FILL_DM_TARGET(4, 5);
510         FILL_DM_TARGET(5, 6);
511         FILL_DM_TARGET(6, 7);
512         FILL_DM_TARGET(7, 8);
513         FILL_DM_TARGET(8, 9);
514         rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open3);
515         errstr = sprintrc(rc);
516         printf("ioctl(-1, DM_TABLE_LOAD, "
517                "{version=4.1.2, data_size=%zu, data_start=%zu, "
518                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
519                "target_count=3134983661, flags=0, ",
520                sizeof(*dm_arg_open3),
521                offsetof(struct dm_table_open_test, target0));
522 # if VERBOSE
523         PRINT_DM_TARGET(0);
524         PRINT_DM_TARGET(1);
525         PRINT_DM_TARGET(2);
526         PRINT_DM_TARGET(3);
527         PRINT_DM_TARGET(4);
528         PRINT_DM_TARGET(5);
529         PRINT_DM_TARGET(6);
530         PRINT_DM_TARGET(7);
531         PRINT_DM_TARGET(8);
532 # endif /* VERBOSE */
533         printf("...}) = %s\n", errstr);
534
535
536         /* DM_TARGET_MSG */
537         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
538         s.u.tm.target_msg.sector = 0x1234;
539         strcpy(s.u.string + offsetof(struct dm_target_msg, message),
540                "long target msg");
541         ioctl(-1, DM_TARGET_MSG, &s);
542         printf("ioctl(-1, DM_TARGET_MSG, "
543                "{version=4.1.2, data_size=%u, data_start=%u, "
544                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
545 # if VERBOSE
546                "{sector=4660, message=\"long targ\"...}"
547 # else /* !VERBOSE */
548                "..."
549 # endif /* VERBOSE */
550                "}) = -1 EBADF (%m)\n",
551                s.ioc.data_size, s.ioc.data_start);
552
553         /* Invalid data_start */
554         init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
555         dm_arg->data_size = sizeof(*dm_arg);
556         ioctl(-1, DM_TARGET_MSG, dm_arg);
557         printf("ioctl(-1, DM_TARGET_MSG, "
558                "{version=4.1.2, data_size=%zu, data_start=%zu, "
559                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
560 # if VERBOSE
561                "/* misplaced struct dm_target_msg */"
562 # else /* !VERBOSE */
563                "..."
564 # endif /* VERBOSE */
565                "}) = -1 EBADF (%m)\n",
566                sizeof(*dm_arg), min_sizeof_dm_ioctl);
567
568         /* Invalid data_start */
569         init_s(dm_arg, min_sizeof_dm_ioctl, 0xffffffff);
570         dm_arg->data_size = sizeof(*dm_arg);
571         ioctl(-1, DM_TARGET_MSG, dm_arg);
572         printf("ioctl(-1, DM_TARGET_MSG, "
573                "{version=4.1.2, data_size=%zu, data_start=%u, "
574                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
575 # if VERBOSE
576                "/* misplaced struct dm_target_msg */"
577 # else /* !VERBOSE */
578                "..."
579 # endif /* VERBOSE */
580                "}) = -1 EBADF (%m)\n",
581                sizeof(*dm_arg), 0xffffffff);
582
583         /* Inaccessible pointer */
584         init_s(dm_arg, min_sizeof_dm_ioctl, 0);
585         dm_arg->data_size = sizeof(*dm_arg) + sizeof(struct dm_target_msg);
586         dm_arg->data_start = sizeof(*dm_arg);
587         ioctl(-1, DM_TARGET_MSG, dm_arg);
588         printf("ioctl(-1, DM_TARGET_MSG, "
589                "{version=4.1.2, data_size=%zu, data_start=%zu, "
590                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
591 # if VERBOSE
592                "%p"
593 # else /* !VERBOSE */
594                "..."
595 # endif /* VERBOSE */
596                "}) = -1 EBADF (%m)\n",
597                sizeof(*dm_arg) + sizeof(struct dm_target_msg),
598                sizeof(*dm_arg)
599 # if VERBOSE
600                , (char *) dm_arg + sizeof(*dm_arg)
601 # endif /* VERBOSE */
602                );
603
604         /* Inaccessible string */
605         init_s(&dm_arg_msg->ioc, sizeof(*dm_arg_msg),
606                offsetof(struct dm_target_msg_test, msg));
607         dm_arg_msg->ioc.data_size = sizeof(*dm_arg_msg) + 1;
608         dm_arg_msg->msg.sector = (__u64) 0xdeadbeeffacef157ULL;
609         rc = ioctl(-1, DM_TARGET_MSG, dm_arg_msg);
610         errstr = sprintrc(rc);
611         printf("ioctl(-1, DM_TARGET_MSG, "
612                "{version=4.1.2, data_size=%zu, data_start=%zu, "
613                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, ",
614                sizeof(*dm_arg_msg) + 1,
615                offsetof(struct dm_target_msg_test, msg));
616 # if VERBOSE
617         printf("{sector=%" PRI__u64 ", message=%p}",
618                (__u64) 0xdeadbeeffacef157ULL,
619                (char *) dm_arg_msg +
620                offsetof(struct dm_target_msg_test, msg.message));
621 # else /* !VERBOSE */
622         printf("...");
623 # endif /* VERBOSE */
624         printf("}) = %s\n", errstr);
625
626         /* Zero-sied string */
627         init_s(&dm_arg_msg->ioc, sizeof(*dm_arg_msg),
628                offsetof(struct dm_target_msg_test, msg));
629         dm_arg_msg->msg.sector = (__u64) 0xdeadbeeffacef157ULL;
630         rc = ioctl(-1, DM_TARGET_MSG, dm_arg_msg);
631         errstr = sprintrc(rc);
632         printf("ioctl(-1, DM_TARGET_MSG, "
633                "{version=4.1.2, data_size=%zu, data_start=%zu, "
634                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, ",
635                sizeof(*dm_arg_msg), offsetof(struct dm_target_msg_test, msg));
636 # if VERBOSE
637         printf("{sector=%" PRI__u64 ", message=\"\"}",
638                (__u64) 0xdeadbeeffacef157ULL);
639 # else /* !VERBOSE */
640         printf("...");
641 # endif /* VERBOSE */
642         printf("}) = %s\n", errstr);
643
644
645         /* DM_DEV_SET_GEOMETRY */
646         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
647         strcpy(s.u.string, "10 20 30 40");
648         ioctl(-1, DM_DEV_SET_GEOMETRY, &s);
649         printf("ioctl(-1, DM_DEV_SET_GEOMETRY, "
650                "{version=4.1.2, data_size=%u, data_start=%u, "
651                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
652 # if VERBOSE
653                "string=\"10 20 30 \"..."
654 # else /* !VERBOSE */
655                "..."
656 # endif /* VERBOSE */
657                "}) = -1 EBADF (%m)\n",
658                s.ioc.data_size, s.ioc.data_start);
659
660
661         /* DM_DEV_RENAME */
662         /* Inaccessible data */
663         init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
664         dm_arg->data_size = sizeof(*dm_arg);
665         memcpy(unaligned_dm_arg, dm_arg, offsetof(struct dm_ioctl, data));
666         ioctl(-1, DM_DEV_RENAME, unaligned_dm_arg);
667         printf("ioctl(-1, DM_DEV_RENAME, "
668                "{version=4.1.2, data_size=%zu, data_start=%zu, "
669                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
670                "flags=0, "
671 # if VERBOSE
672                "string=%p"
673 # else /* !VERBOSE */
674                "..."
675 # endif /* VERBOSE */
676                "}) = -1 EBADF (%m)\n",
677                sizeof(*unaligned_dm_arg), min_sizeof_dm_ioctl
678 # if VERBOSE
679                , (char *) unaligned_dm_arg + min_sizeof_dm_ioctl
680 # endif /* VERBOSE */
681                );
682
683         /* Incorrect data_start data */
684         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
685         s.ioc.data_start = 0xdeadbeef;
686         ioctl(-1, DM_DEV_RENAME, &s);
687         printf("ioctl(-1, DM_DEV_RENAME, "
688                "{version=4.1.2, data_size=%u, data_start=3735928559, "
689                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
690                "flags=0, "
691 # if VERBOSE
692                "/* misplaced string */"
693 # else /* !VERBOSE */
694                "..."
695 # endif /* VERBOSE */
696                "}) = -1 EBADF (%m)\n",
697                s.ioc.data_size);
698
699         /* Strange but still valid data_start */
700         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
701         /* Curiously, this is a valid structure */
702         s.ioc.data_start = offsetof(struct dm_ioctl, name) + 1;
703         ioctl(-1, DM_DEV_RENAME, &s);
704         printf("ioctl(-1, DM_DEV_RENAME, "
705                "{version=4.1.2, data_size=%u, data_start=%zu, "
706                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
707                "flags=0, "
708 # if VERBOSE
709                "string=\"nn\""
710 # else /* !VERBOSE */
711                "..."
712 # endif /* VERBOSE */
713                "}) = -1 EBADF (%m)\n",
714                s.ioc.data_size,
715                offsetof(struct dm_ioctl, name) + 1);
716
717         /* Correct data */
718         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
719         strcpy(s.u.string, "new long name");
720         ioctl(-1, DM_DEV_RENAME, &s);
721         printf("ioctl(-1, DM_DEV_RENAME, "
722                "{version=4.1.2, data_size=%u, data_start=%u, "
723                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
724                "flags=0, "
725 # if VERBOSE
726                "string=\"new long \"..."
727 # else /* !VERBOSE */
728                "..."
729 # endif /* VERBOSE */
730                "}) = -1 EBADF (%m)\n",
731                s.ioc.data_size, s.ioc.data_start);
732
733
734         /* DM_TABLE_LOAD */
735         init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
736         s.ioc.target_count = -1U;
737         ioctl(-1, DM_TABLE_LOAD, &s);
738         printf("ioctl(-1, DM_TABLE_LOAD, "
739                "{version=4.1.2, data_size=%u, data_start=%u, "
740                "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
741                "target_count=4294967295, flags=0, "
742 # if VERBOSE
743                "{sector_start=0, length=0, target_type=\"\", string=\"\"}, "
744                "/* misplaced struct dm_target_spec */ "
745 # endif /* VERBOSE */
746                "...}) = -1 EBADF (%m)\n",
747                s.ioc.data_size, s.ioc.data_start);
748
749         puts("+++ exited with 0 +++");
750         return 0;
751 }
752
753 #else /* !HAVE_LINUX_DM_IOCTL_H */
754
755 SKIP_MAIN_UNDEFINED("HAVE_LINUX_DM_IOCTL_H")
756
757 #endif /* HAVE_LINUX_DM_IOCTL_H */