Import lvm2 from NetBSD
[dragonfly.git] / contrib / lvm2 / dist / tools / dmsetup.c
1 /*      $NetBSD: dmsetup.c,v 1.1.1.2 2009/12/02 00:25:49 haad Exp $     */
2
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
6  * Copyright (C) 2005-2007 NEC Corporation
7  *
8  * This file is part of the device-mapper userspace tools.
9  *
10  * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/
11  *
12  * This copyrighted material is made available to anyone wishing to use,
13  * modify, copy, or redistribute it subject to the terms and conditions
14  * of the GNU General Public License v.2.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define _GNU_SOURCE
22 #define _FILE_OFFSET_BITS 64
23
24 #include "configure.h"
25
26 #include "dm-logging.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <dirent.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <libgen.h>
36 #include <sys/wait.h>
37 #include <unistd.h>
38 #include <sys/param.h>
39 #include <locale.h>
40 #include <langinfo.h>
41 #include <time.h>
42
43 #include <fcntl.h>
44 #include <sys/stat.h>
45
46 #ifdef UDEV_SYNC_SUPPORT
47 #  include <sys/types.h>
48 #  include <sys/ipc.h>
49 #  include <sys/sem.h>
50 #endif
51
52 /* FIXME Unused so far */
53 #undef HAVE_SYS_STATVFS_H
54
55 #ifdef HAVE_SYS_STATVFS_H
56 #  include <sys/statvfs.h>
57 #endif
58
59 #ifdef HAVE_SYS_IOCTL_H
60 #  include <sys/ioctl.h>
61 #endif
62
63 #if HAVE_TERMIOS_H
64 #  include <termios.h>
65 #endif
66
67 #ifdef HAVE_GETOPTLONG
68 #  include <getopt.h>
69 #  define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
70 #  define OPTIND_INIT 0
71 #else
72 struct option {
73 };
74 extern int optind;
75 extern char *optarg;
76 #  define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
77 #  define OPTIND_INIT 1
78 #endif
79
80 #ifndef TEMP_FAILURE_RETRY
81 # define TEMP_FAILURE_RETRY(expression) \
82   (__extension__                                                              \
83     ({ long int __result;                                                     \
84        do __result = (long int) (expression);                                 \
85        while (__result == -1L && errno == EINTR);                             \
86        __result; }))
87 #endif
88
89 #ifdef linux
90 #  include "kdev_t.h"
91 #else
92 #  define MAJOR(x) major((x))
93 #  define MINOR(x) minor((x))
94 #  define MKDEV(x,y) makedev((x),(y))
95 #endif
96
97 #define LINE_SIZE 4096
98 #define ARGS_MAX 256
99 #define LOOP_TABLE_SIZE (PATH_MAX + 255)
100
101 #define DEFAULT_DM_DEV_DIR "/dev"
102
103 /* FIXME Should be imported */
104 #ifndef DM_MAX_TYPE_NAME
105 #  define DM_MAX_TYPE_NAME 16
106 #endif
107
108 /* FIXME Should be elsewhere */
109 #define SECTOR_SHIFT 9L
110
111 #define err(msg, x...) fprintf(stderr, msg "\n", ##x)
112
113 /*
114  * We have only very simple switches ATM.
115  */
116 enum {
117         READ_ONLY = 0,
118         COLS_ARG,
119         EXEC_ARG,
120         FORCE_ARG,
121         GID_ARG,
122         INACTIVE_ARG,
123         MAJOR_ARG,
124         MINOR_ARG,
125         MODE_ARG,
126         NAMEPREFIXES_ARG,
127         NOFLUSH_ARG,
128         NOHEADINGS_ARG,
129         NOLOCKFS_ARG,
130         NOOPENCOUNT_ARG,
131         NOTABLE_ARG,
132         NOUDEVSYNC_ARG,
133         OPTIONS_ARG,
134         READAHEAD_ARG,
135         ROWS_ARG,
136         SEPARATOR_ARG,
137         SHOWKEYS_ARG,
138         SORT_ARG,
139         TABLE_ARG,
140         TARGET_ARG,
141         TREE_ARG,
142         UID_ARG,
143         UNBUFFERED_ARG,
144         UNQUOTED_ARG,
145         UUID_ARG,
146         VERBOSE_ARG,
147         VERSION_ARG,
148         YES_ARG,
149         NUM_SWITCHES
150 };
151
152 typedef enum {
153         DR_TASK = 1,
154         DR_INFO = 2,
155         DR_DEPS = 4,
156         DR_TREE = 8,    /* Complete dependency tree required */
157         DR_NAME = 16
158 } report_type_t;
159
160 static int _switches[NUM_SWITCHES];
161 static int _int_args[NUM_SWITCHES];
162 static char *_string_args[NUM_SWITCHES];
163 static int _num_devices;
164 static char *_uuid;
165 static char *_table;
166 static char *_target;
167 static char *_command;
168 static uint32_t _read_ahead_flags;
169 static struct dm_tree *_dtree;
170 static struct dm_report *_report;
171 static report_type_t _report_type;
172
173 /*
174  * Commands
175  */
176
177 typedef int (*command_fn) (int argc, char **argv, void *data);
178
179 struct command {
180         const char *name;
181         const char *help;
182         int min_args;
183         int max_args;
184         command_fn fn;
185 };
186
187 static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
188                        int line)
189 {
190         char ttype[LINE_SIZE], *ptr, *comment;
191         unsigned long long start, size;
192         int n;
193
194         /* trim trailing space */
195         for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr--)
196                 if (!isspace((int) *ptr))
197                         break;
198         ptr++;
199         *ptr = '\0';
200
201         /* trim leading space */
202         for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++)
203                 ;
204
205         if (!*ptr || *ptr == '#')
206                 return 1;
207
208         if (sscanf(ptr, "%llu %llu %s %n",
209                    &start, &size, ttype, &n) < 3) {
210                 err("Invalid format on line %d of table %s", line, file);
211                 return 0;
212         }
213
214         ptr += n;
215         if ((comment = strchr(ptr, (int) '#')))
216                 *comment = '\0';
217
218         if (!dm_task_add_target(dmt, start, size, ttype, ptr))
219                 return 0;
220
221         return 1;
222 }
223
224 static int _parse_file(struct dm_task *dmt, const char *file)
225 {
226         char *buffer = NULL;
227         size_t buffer_size = 0;
228         FILE *fp;
229         int r = 0, line = 0;
230
231         /* one-line table on cmdline */
232         if (_table)
233                 return _parse_line(dmt, _table, "", ++line);
234
235         /* OK for empty stdin */
236         if (file) {
237                 if (!(fp = fopen(file, "r"))) {
238                         err("Couldn't open '%s' for reading", file);
239                         return 0;
240                 }
241         } else
242                 fp = stdin;
243
244 #ifndef HAVE_GETLINE
245         buffer_size = LINE_SIZE;
246         if (!(buffer = dm_malloc(buffer_size))) {
247                 err("Failed to malloc line buffer.");
248                 return 0;
249         }
250
251         while (fgets(buffer, (int) buffer_size, fp))
252 #else
253         while (getline(&buffer, &buffer_size, fp) > 0)
254 #endif
255                 if (!_parse_line(dmt, buffer, file ? : "on stdin", ++line))
256                         goto out;
257
258         r = 1;
259
260       out:
261 #ifndef HAVE_GETLINE
262         dm_free(buffer);
263 #else
264         free(buffer);
265 #endif
266         if (file && fclose(fp))
267                 fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno));
268
269         return r;
270 }
271
272 struct dm_split_name {
273         char *subsystem;
274         char *vg_name;
275         char *lv_name;
276         char *lv_layer;
277 };
278
279 struct dmsetup_report_obj {
280         struct dm_task *task;
281         struct dm_info *info;
282         struct dm_task *deps_task;
283         struct dm_tree_node *tree_node;
284         struct dm_split_name *split_name;
285 };
286
287 static struct dm_task *_get_deps_task(int major, int minor)
288 {
289         struct dm_task *dmt;
290         struct dm_info info;
291
292         if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
293                 return NULL;
294
295         if (!dm_task_set_major(dmt, major) ||
296             !dm_task_set_minor(dmt, minor))
297                 goto err;
298
299         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
300                 goto err;
301
302         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
303                 goto err;
304
305         if (!dm_task_run(dmt))
306                 goto err;
307
308         if (!dm_task_get_info(dmt, &info))
309                 goto err;
310
311         if (!info.exists)
312                 goto err;
313
314         return dmt;
315
316       err:
317         dm_task_destroy(dmt);
318         return NULL;
319 }
320
321 static char *_extract_uuid_prefix(const char *uuid, const int separator)
322 {
323         char *ptr = NULL;
324         char *uuid_prefix = NULL;
325         size_t len;
326
327         if (uuid)
328                 ptr = strchr(uuid, separator);
329
330         len = ptr ? ptr - uuid : 0;
331         if (!(uuid_prefix = dm_malloc(len + 1))) {
332                 log_error("Failed to allocate memory to extract uuid prefix.");
333                 return NULL;
334         }
335
336         memcpy(uuid_prefix, uuid, len);
337         uuid_prefix[len] = '\0';
338
339         return uuid_prefix;
340 }
341
342 static struct dm_split_name *_get_split_name(const char *uuid, const char *name,
343                                              int separator)
344 {
345         struct dm_split_name *split_name;
346
347         if (!(split_name = dm_malloc(sizeof(*split_name)))) {
348                 log_error("Failed to allocate memory to split device name "
349                           "into components.");
350                 return NULL;
351         }
352
353         split_name->subsystem = _extract_uuid_prefix(uuid, separator);
354         split_name->vg_name = split_name->lv_name =
355             split_name->lv_layer = (char *) "";
356
357         if (!strcmp(split_name->subsystem, "LVM") &&
358             (!(split_name->vg_name = dm_strdup(name)) ||
359              !dm_split_lvm_name(NULL, NULL, &split_name->vg_name,
360                                 &split_name->lv_name, &split_name->lv_layer)))
361                 log_error("Failed to allocate memory to split LVM name "
362                           "into components.");
363
364         return split_name;
365 }
366
367 static void _destroy_split_name(struct dm_split_name *split_name)
368 {
369         /*
370          * lv_name and lv_layer are allocated within the same block
371          * of memory as vg_name so don't need to be freed separately.
372          */
373         if (!strcmp(split_name->subsystem, "LVM"))
374                 dm_free(split_name->vg_name);
375
376         dm_free(split_name->subsystem);
377         dm_free(split_name);
378 }
379
380 static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
381 {
382         struct dmsetup_report_obj obj;
383         int r = 0;
384
385         if (!info->exists) {
386                 fprintf(stderr, "Device does not exist.\n");
387                 return 0;
388         }
389
390         obj.task = dmt;
391         obj.info = info;
392         obj.deps_task = NULL;
393         obj.split_name = NULL;
394
395         if (_report_type & DR_TREE)
396                 obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor);
397
398         if (_report_type & DR_DEPS)
399                 obj.deps_task = _get_deps_task(info->major, info->minor);
400
401         if (_report_type & DR_NAME)
402                 obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-');
403
404         if (!dm_report_object(_report, &obj))
405                 goto out;
406
407         r = 1;
408
409       out:
410         if (obj.deps_task)
411                 dm_task_destroy(obj.deps_task);
412         if (obj.split_name)
413                 _destroy_split_name(obj.split_name);
414         return r;
415 }
416
417 static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
418 {
419         const char *uuid;
420         uint32_t read_ahead;
421
422         if (!info->exists) {
423                 printf("Device does not exist.\n");
424                 return;
425         }
426
427         printf("Name:              %s\n", dm_task_get_name(dmt));
428
429         printf("State:             %s%s\n",
430                info->suspended ? "SUSPENDED" : "ACTIVE",
431                info->read_only ? " (READ-ONLY)" : "");
432
433         /* FIXME Old value is being printed when it's being changed. */
434         if (dm_task_get_read_ahead(dmt, &read_ahead))
435                 printf("Read Ahead:        %" PRIu32 "\n", read_ahead);
436
437         if (!info->live_table && !info->inactive_table)
438                 printf("Tables present:    None\n");
439         else
440                 printf("Tables present:    %s%s%s\n",
441                        info->live_table ? "LIVE" : "",
442                        info->live_table && info->inactive_table ? " & " : "",
443                        info->inactive_table ? "INACTIVE" : "");
444
445         if (info->open_count != -1)
446                 printf("Open count:        %d\n", info->open_count);
447
448         printf("Event number:      %" PRIu32 "\n", info->event_nr);
449         printf("Major, minor:      %d, %d\n", info->major, info->minor);
450
451         if (info->target_count != -1)
452                 printf("Number of targets: %d\n", info->target_count);
453
454         if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
455                 printf("UUID: %s\n", uuid);
456
457         printf("\n");
458 }
459
460 static int _display_info(struct dm_task *dmt)
461 {
462         struct dm_info info;
463
464         if (!dm_task_get_info(dmt, &info))
465                 return 0;
466
467         if (!_switches[COLS_ARG])
468                 _display_info_long(dmt, &info);
469         else
470                 /* FIXME return code */
471                 _display_info_cols(dmt, &info);
472
473         return info.exists ? 1 : 0;
474 }
475
476 static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
477 {
478         if (name) {
479                 if (!dm_task_set_name(dmt, name))
480                         return 0;
481         } else if (_switches[UUID_ARG]) {
482                 if (!dm_task_set_uuid(dmt, _uuid))
483                         return 0;
484         } else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) {
485                 if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) ||
486                     !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
487                         return 0;
488         } else if (!optional) {
489                 fprintf(stderr, "No device specified.\n");
490                 return 0;
491         }
492
493         return 1;
494 }
495
496 static int _load(int argc, char **argv, void *data __attribute((unused)))
497 {
498         int r = 0;
499         struct dm_task *dmt;
500         const char *file = NULL;
501         const char *name = NULL;
502
503         if (_switches[NOTABLE_ARG]) {
504                 err("--notable only available when creating new device\n");
505                 return 0;
506         }
507
508         if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
509                 if (argc == 1) {
510                         err("Please specify device.\n");
511                         return 0;
512                 }
513                 name = argv[1];
514                 argc--;
515                 argv++;
516         } else if (argc > 2) {
517                 err("Too many command line arguments.\n");
518                 return 0;
519         }
520
521         if (argc == 2)
522                 file = argv[1];
523
524         if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
525                 return 0;
526
527         if (!_set_task_device(dmt, name, 0))
528                 goto out;
529
530         if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
531                 goto out;
532
533         if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
534                 goto out;
535
536         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
537                 goto out;
538
539         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
540                 goto out;
541
542         if (!dm_task_run(dmt))
543                 goto out;
544
545         r = 1;
546
547         if (_switches[VERBOSE_ARG])
548                 r = _display_info(dmt);
549
550       out:
551         dm_task_destroy(dmt);
552
553         return r;
554 }
555
556 static int _create(int argc, char **argv, void *data __attribute((unused)))
557 {
558         int r = 0;
559         struct dm_task *dmt;
560         const char *file = NULL;
561         uint32_t cookie = 0;
562
563         if (argc == 3)
564                 file = argv[2];
565
566         if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
567                 return 0;
568
569         if (!dm_task_set_name(dmt, argv[1]))
570                 goto out;
571
572         if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid))
573                 goto out;
574
575         if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file))
576                 goto out;
577
578         if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
579                 goto out;
580
581         if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG]))
582                 goto out;
583
584         if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
585                 goto out;
586
587         if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG]))
588                 goto out;
589
590         if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG]))
591                 goto out;
592
593         if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG]))
594                 goto out;
595
596         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
597                 goto out;
598
599         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
600                 goto out;
601
602         if (_switches[READAHEAD_ARG] &&
603             !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
604                                     _read_ahead_flags))
605                 goto out;
606
607         if (_switches[NOTABLE_ARG])
608                 dm_udev_set_sync_support(0);
609
610         if (!dm_task_set_cookie(dmt, &cookie, 0) ||
611             !dm_task_run(dmt))
612                 goto out;
613
614         r = 1;
615
616         if (_switches[VERBOSE_ARG])
617                 r = _display_info(dmt);
618
619       out:
620         (void) dm_udev_wait(cookie);
621         dm_task_destroy(dmt);
622
623         return r;
624 }
625
626 static int _rename(int argc, char **argv, void *data __attribute((unused)))
627 {
628         int r = 0;
629         struct dm_task *dmt;
630         uint32_t cookie = 0;
631
632         if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
633                 return 0;
634
635         /* FIXME Kernel doesn't support uuid or device number here yet */
636         if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0))
637                 goto out;
638
639         if (!dm_task_set_newname(dmt, argv[argc - 1]))
640                 goto out;
641
642         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
643                 goto out;
644
645         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
646                 goto out;
647
648         if (!dm_task_set_cookie(dmt, &cookie, 0) ||
649             !dm_task_run(dmt))
650                 goto out;
651
652         r = 1;
653
654       out:
655         (void) dm_udev_wait(cookie);
656         dm_task_destroy(dmt);
657
658         return r;
659 }
660
661 static int _message(int argc, char **argv, void *data __attribute((unused)))
662 {
663         int r = 0, i;
664         size_t sz = 1;
665         struct dm_task *dmt;
666         char *str;
667
668         if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
669                 return 0;
670
671         if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
672                 if (!_set_task_device(dmt, NULL, 0))
673                         goto out;
674         } else {
675                 if (!_set_task_device(dmt, argv[1], 0))
676                         goto out;
677                 argc--;
678                 argv++;
679         }
680
681         if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
682                 goto out;
683
684         argc -= 2;
685         argv += 2;
686
687         if (argc <= 0)
688                 err("No message supplied.\n");
689
690         for (i = 0; i < argc; i++)
691                 sz += strlen(argv[i]) + 1;
692
693         if (!(str = dm_malloc(sz))) {
694                 err("message string allocation failed");
695                 goto out;
696         }
697
698         memset(str, 0, sz);
699
700         for (i = 0; i < argc; i++) {
701                 if (i)
702                         strcat(str, " ");
703                 strcat(str, argv[i]);
704         }
705
706         if (!dm_task_set_message(dmt, str))
707                 goto out;
708
709         dm_free(str);
710
711         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
712                 goto out;
713
714         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
715                 goto out;
716
717         if (!dm_task_run(dmt))
718                 goto out;
719
720         r = 1;
721
722       out:
723         dm_task_destroy(dmt);
724
725         return r;
726 }
727
728 static int _setgeometry(int argc, char **argv, void *data __attribute((unused)))
729 {
730         int r = 0;
731         struct dm_task *dmt;
732
733         if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
734                 return 0;
735
736         if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
737                 if (!_set_task_device(dmt, NULL, 0))
738                         goto out;
739         } else {
740                 if (!_set_task_device(dmt, argv[1], 0))
741                         goto out;
742                 argc--;
743                 argv++;
744         }
745
746         if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
747                 goto out;
748
749         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
750                 goto out;
751
752         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
753                 goto out;
754
755         /* run the task */
756         if (!dm_task_run(dmt))
757                 goto out;
758
759         r = 1;
760
761       out:
762         dm_task_destroy(dmt);
763
764         return r;
765 }
766
767 static int _splitname(int argc, char **argv, void *data __attribute((unused)))
768 {
769         struct dmsetup_report_obj obj;
770         int r = 1;
771
772         obj.task = NULL;
773         obj.info = NULL;
774         obj.deps_task = NULL;
775         obj.tree_node = NULL;
776         obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
777                                          argv[1], '\0');
778
779         r = dm_report_object(_report, &obj);
780         _destroy_split_name(obj.split_name);
781
782         return r;
783 }
784
785 static uint32_t _get_cookie_value(char *str_value)
786 {
787         unsigned long int value;
788         char *p;
789
790         if (!(value = strtoul(str_value, &p, 0)) ||
791             *p ||
792             (value == ULONG_MAX && errno == ERANGE) ||
793             value > 0xFFFFFFFF) {
794                 err("Incorrect cookie value");
795                 return 0;
796         }
797         else
798                 return (uint32_t) value;
799 }
800
801 static int _udevflags(int args, char **argv, void *data __attribute((unused)))
802 {
803         uint32_t cookie;
804         uint16_t flags;
805         int i;
806         static const char *dm_flag_names[] = {"DISABLE_DM_RULES",
807                                               "DISABLE_SUBSYSTEM_RULES",
808                                               "DISABLE_DISK_RULES",
809                                               "DISABLE_OTHER_RULES",
810                                               "LOW_PRIORITY",
811                                                0, 0, 0};
812
813         if (!(cookie = _get_cookie_value(argv[1])))
814                 return 0;
815
816         flags = cookie >> DM_UDEV_FLAGS_SHIFT;
817
818         for (i = 0; i < DM_UDEV_FLAGS_SHIFT; i++)
819                 if (1 << i & flags) {
820                         if (i < DM_UDEV_FLAGS_SHIFT / 2 && dm_flag_names[i])
821                                 printf("DM_UDEV_%s_FLAG='1'\n", dm_flag_names[i]);
822                         else if (i < DM_UDEV_FLAGS_SHIFT / 2)
823                                 /*
824                                  * This is just a fallback. Each new DM flag
825                                  * should have its symbolic name assigned.
826                                  */
827                                 printf("DM_UDEV_FLAG%d='1'\n", i);
828                         else
829                                 /*
830                                  * We can't assign symbolic names to subsystem
831                                  * flags. Their semantics vary based on the
832                                  * subsystem that is currently used.
833                                  */
834                                 printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n",
835                                         i - DM_UDEV_FLAGS_SHIFT / 2);
836                 }
837
838         return 1;
839 }
840
841 static int _udevcomplete(int argc, char **argv, void *data __attribute((unused)))
842 {
843         uint32_t cookie;
844
845         if (!(cookie = _get_cookie_value(argv[1])))
846                 return 0;
847
848         /*
849          * Strip flags from the cookie and use cookie magic instead.
850          * If the cookie has non-zero prefix and the base is zero then
851          * this one carries flags to control udev rules only and it is
852          * not meant to be for notification. Return with success in this
853          * situation.
854          */
855         if (!(cookie &= ~DM_UDEV_FLAGS_MASK))
856                 return 1;
857
858         cookie |= DM_COOKIE_MAGIC << DM_UDEV_FLAGS_SHIFT;
859
860         return dm_udev_complete(cookie);
861 }
862
863 #ifndef UDEV_SYNC_SUPPORT
864 static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
865
866 static int _udevcomplete_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
867 {
868         log_error(_cmd_not_supported);
869
870         return 0;
871 }
872
873 static int _udevcookies(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
874 {
875         log_error(_cmd_not_supported);
876
877         return 0;
878 }
879
880 #else   /* UDEV_SYNC_SUPPORT */
881
882 static char _yes_no_prompt(const char *prompt, ...)
883 {
884         int c = 0, ret = 0;
885         va_list ap;
886
887         do {
888                 if (c == '\n' || !c) {
889                         va_start(ap, prompt);
890                         vprintf(prompt, ap);
891                         va_end(ap);
892                 }
893
894                 if ((c = getchar()) == EOF) {
895                         ret = 'n';
896                         break;
897                 }
898
899                 c = tolower(c);
900                 if ((c == 'y') || (c == 'n'))
901                         ret = c;
902         } while (!ret || c != '\n');
903
904         if (c != '\n')
905                 printf("\n");
906
907         return ret;
908 }
909
910 static int _udevcomplete_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
911 {
912         int max_id, id, sid;
913         struct seminfo sinfo;
914         struct semid_ds sdata;
915         int counter = 0;
916
917         if (!_switches[YES_ARG]) {
918                 log_warn("This operation will destroy all semaphores with keys "
919                          "that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
920                          DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
921
922                 if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
923                         log_print("Semaphores with keys prefixed by %" PRIu16
924                                   " (0x%" PRIx16 ") NOT destroyed.",
925                                   DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
926                         return 1;
927                 }
928         }
929
930         if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
931                 log_sys_error("semctl", "SEM_INFO");
932                 return 0;
933         }
934
935         for (id = 0; id <= max_id; id++) {
936                 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
937                         continue;
938
939                 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
940                         if (semctl(sid, 0, IPC_RMID, 0) < 0) {
941                                 log_error("Could not cleanup notification semaphore "
942                                           "with semid %d and cookie value "
943                                           "%" PRIu32 " (0x%" PRIx32 ")", sid,
944                                           sdata.sem_perm.__key, sdata.sem_perm.__key);
945                                 continue;
946                         }
947
948                         counter++;
949                 }
950         }
951
952         log_print("%d semaphores with keys prefixed by "
953                   "%" PRIu16 " (0x%" PRIx16 ") destroyed.",
954                   counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
955
956         return 1;
957 }
958
959 static int _udevcookies(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
960 {
961         int max_id, id, sid;
962         struct seminfo sinfo;
963         struct semid_ds sdata;
964         int val;
965         char *time_str;
966
967         if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
968                 log_sys_error("sem_ctl", "SEM_INFO");
969                 return 0;
970         }
971
972         printf("cookie       semid      value      last_semop_time\n");
973
974         for (id = 0; id <= max_id; id++) {
975                 if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
976                         continue;
977
978                 if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
979                         if ((val = semctl(sid, 0, GETVAL)) < 0) {
980                                 log_error("semid %d: sem_ctl failed for "
981                                           "cookie 0x%" PRIx32 ": %s",
982                                           sid, sdata.sem_perm.__key,
983                                           strerror(errno));
984                                 continue;
985                         }
986
987                         time_str = ctime((const time_t *) &sdata.sem_otime);
988
989                         printf("0x%-10x %-10d %-10d %s", sdata.sem_perm.__key,
990                                 sid, val, time_str ? time_str : "unknown\n");
991                 }
992         }
993
994         return 1;
995 }
996 #endif  /* UDEV_SYNC_SUPPORT */
997
998 static int _version(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
999 {
1000         char version[80];
1001
1002         if (dm_get_library_version(version, sizeof(version)))
1003                 printf("Library version:   %s\n", version);
1004
1005         if (!dm_driver_version(version, sizeof(version)))
1006                 return 0;
1007
1008         printf("Driver version:    %s\n", version);
1009
1010         return 1;
1011 }
1012
1013 static int _simple(int task, const char *name, uint32_t event_nr, int display)
1014 {
1015         uint32_t cookie = 0;
1016         int udev_wait_flag = task == DM_DEVICE_RESUME ||
1017                              task == DM_DEVICE_REMOVE;
1018         int r = 0;
1019
1020         struct dm_task *dmt;
1021
1022         if (!(dmt = dm_task_create(task)))
1023                 return 0;
1024
1025         if (!_set_task_device(dmt, name, 0))
1026                 goto out;
1027
1028         if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
1029                 goto out;
1030
1031         if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
1032                 goto out;
1033
1034         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1035                 goto out;
1036
1037         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1038                 goto out;
1039
1040         if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt))
1041                 goto out;
1042
1043         if (_switches[READAHEAD_ARG] &&
1044             !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
1045                                     _read_ahead_flags))
1046                 goto out;
1047
1048         if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, 0))
1049                 goto out;
1050
1051         r = dm_task_run(dmt);
1052
1053         if (r && display && _switches[VERBOSE_ARG])
1054                 r = _display_info(dmt);
1055
1056       out:
1057         if (udev_wait_flag)
1058                 (void) dm_udev_wait(cookie);
1059
1060         dm_task_destroy(dmt);
1061         return r;
1062 }
1063
1064 static int _suspend(int argc, char **argv, void *data __attribute((unused)))
1065 {
1066         return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
1067 }
1068
1069 static int _resume(int argc, char **argv, void *data __attribute((unused)))
1070 {
1071         return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
1072 }
1073
1074 static int _clear(int argc, char **argv, void *data __attribute((unused)))
1075 {
1076         return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
1077 }
1078
1079 static int _wait(int argc, char **argv, void *data __attribute((unused)))
1080 {
1081         const char *name = NULL;
1082
1083         if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
1084                 if (argc == 1) {
1085                         err("No device specified.");
1086                         return 0;
1087                 }
1088                 name = argv[1];
1089                 argc--, argv++;
1090         }
1091
1092         return _simple(DM_DEVICE_WAITEVENT, name,
1093                        (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
1094 }
1095
1096 static int _process_all(int argc, char **argv, int silent,
1097                         int (*fn) (int argc, char **argv, void *data))
1098 {
1099         int r = 1;
1100         struct dm_names *names;
1101         unsigned next = 0;
1102
1103         struct dm_task *dmt;
1104
1105         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
1106                 return 0;
1107
1108         if (!dm_task_run(dmt)) {
1109                 r = 0;
1110                 goto out;
1111         }
1112
1113         if (!(names = dm_task_get_names(dmt))) {
1114                 r = 0;
1115                 goto out;
1116         }
1117
1118         if (!names->dev) {
1119                 if (!silent)
1120                         printf("No devices found\n");
1121                 goto out;
1122         }
1123
1124         do {
1125                 names = (void *) names + next;
1126                 if (!fn(argc, argv, (void *) names))
1127                         r = 0;
1128                 next = names->next;
1129         } while (next);
1130
1131       out:
1132         dm_task_destroy(dmt);
1133         return r;
1134 }
1135
1136 static uint64_t _get_device_size(const char *name)
1137 {
1138         uint64_t start, length, size = UINT64_C(0);
1139         struct dm_info info;
1140         char *target_type, *params;
1141         struct dm_task *dmt;
1142         void *next = NULL;
1143
1144         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
1145                 return 0;
1146
1147         if (!_set_task_device(dmt, name, 0))
1148                 goto out;
1149
1150         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1151                 goto out;
1152
1153         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1154                 goto out;
1155
1156         if (!dm_task_run(dmt))
1157                 goto out;
1158
1159         if (!dm_task_get_info(dmt, &info) || !info.exists)
1160                 goto out;
1161
1162         do {
1163                 next = dm_get_next_target(dmt, next, &start, &length,
1164                                           &target_type, &params);
1165                 size += length;
1166         } while (next);
1167
1168       out:
1169         dm_task_destroy(dmt);
1170         return size;
1171 }
1172
1173 static int _error_device(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
1174 {
1175         struct dm_names *names = (struct dm_names *) data;
1176         struct dm_task *dmt;
1177         const char *name;
1178         uint64_t size;
1179         int r = 0;
1180
1181         if (data)
1182                 name = names->name;
1183         else
1184                 name = argv[1];
1185
1186         size = _get_device_size(name);
1187
1188         if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
1189                 return 0;
1190
1191         if (!_set_task_device(dmt, name, 0))
1192                 goto error;
1193
1194         if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
1195                 goto error;
1196
1197         if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
1198                 goto error;
1199
1200         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1201                 goto error;
1202
1203         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1204                 goto error;
1205
1206         if (!dm_task_run(dmt))
1207                 goto error;
1208
1209         if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
1210                 _simple(DM_DEVICE_CLEAR, name, 0, 0);
1211                 goto error;
1212         }
1213
1214         r = 1;
1215
1216 error:
1217         dm_task_destroy(dmt);
1218         return r;
1219 }
1220
1221 static int _remove(int argc, char **argv, void *data __attribute((unused)))
1222 {
1223         int r;
1224
1225         if (_switches[FORCE_ARG] && argc > 1)
1226                 r = _error_device(argc, argv, NULL);
1227
1228         return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
1229 }
1230
1231 static int _count_devices(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
1232 {
1233         _num_devices++;
1234
1235         return 1;
1236 }
1237
1238 static int _remove_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
1239 {
1240         int r;
1241
1242         /* Remove all closed devices */
1243         r =  _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
1244
1245         if (!_switches[FORCE_ARG])
1246                 return r;
1247
1248         _num_devices = 0;
1249         r |= _process_all(argc, argv, 1, _count_devices);
1250
1251         /* No devices left? */
1252         if (!_num_devices)
1253                 return r;
1254
1255         r |= _process_all(argc, argv, 1, _error_device);
1256         r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
1257
1258         _num_devices = 0;
1259         r |= _process_all(argc, argv, 1, _count_devices);
1260         if (!_num_devices)
1261                 return r;
1262
1263         fprintf(stderr, "Unable to remove %d device(s).\n", _num_devices);
1264
1265         return r;
1266 }
1267
1268 static void _display_dev(struct dm_task *dmt, const char *name)
1269 {
1270         struct dm_info info;
1271
1272         if (dm_task_get_info(dmt, &info))
1273                 printf("%s\t(%u, %u)\n", name, info.major, info.minor);
1274 }
1275
1276 static int _mknodes(int argc, char **argv, void *data __attribute((unused)))
1277 {
1278         return dm_mknodes(argc > 1 ? argv[1] : NULL);
1279 }
1280
1281 static int _exec_command(const char *name)
1282 {
1283         int n;
1284         static char path[PATH_MAX];
1285         static char *args[ARGS_MAX + 1];
1286         static int argc = 0;
1287         char *c;
1288         pid_t pid;
1289
1290         if (argc < 0)
1291                 return 0;
1292
1293         if (!dm_mknodes(name))
1294                 return 0;
1295
1296         n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
1297         if (n < 0 || n > (int) sizeof(path) - 1)
1298                 return 0;
1299
1300         if (!argc) {
1301                 c = _command;
1302                 while (argc < ARGS_MAX) {
1303                         while (*c && isspace(*c))
1304                                 c++;
1305                         if (!*c)
1306                                 break;
1307                         args[argc++] = c;
1308                         while (*c && !isspace(*c))
1309                                 c++;
1310                         if (*c)
1311                                 *c++ = '\0';
1312                 }
1313
1314                 if (!argc) {
1315                         argc = -1;
1316                         return 0;
1317                 }
1318
1319                 if (argc == ARGS_MAX) {
1320                         err("Too many args to --exec\n");
1321                         argc = -1;
1322                         return 0;
1323                 }
1324
1325                 args[argc++] = path;
1326                 args[argc] = NULL;
1327         }
1328
1329         if (!(pid = fork())) {
1330                 execvp(args[0], args);
1331                 _exit(127);
1332         } else if (pid < (pid_t) 0)
1333                 return 0;
1334
1335         TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
1336
1337         return 1;
1338 }
1339
1340 static int _status(int argc, char **argv, void *data)
1341 {
1342         int r = 0;
1343         struct dm_task *dmt;
1344         void *next = NULL;
1345         uint64_t start, length;
1346         char *target_type = NULL;
1347         char *params, *c;
1348         int cmd;
1349         struct dm_names *names = (struct dm_names *) data;
1350         const char *name = NULL;
1351         int matched = 0;
1352         int ls_only = 0;
1353         struct dm_info info;
1354
1355         if (data)
1356                 name = names->name;
1357         else {
1358                 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1359                         return _process_all(argc, argv, 0, _status);
1360                 if (argc == 2)
1361                         name = argv[1];
1362         }
1363
1364         if (!strcmp(argv[0], "table"))
1365                 cmd = DM_DEVICE_TABLE;
1366         else
1367                 cmd = DM_DEVICE_STATUS;
1368
1369         if (!strcmp(argv[0], "ls"))
1370                 ls_only = 1;
1371
1372         if (!(dmt = dm_task_create(cmd)))
1373                 return 0;
1374
1375         if (!_set_task_device(dmt, name, 0))
1376                 goto out;
1377
1378         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1379                 goto out;
1380
1381         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1382                 goto out;
1383
1384         if (!dm_task_run(dmt))
1385                 goto out;
1386
1387         if (!dm_task_get_info(dmt, &info) || !info.exists)
1388                 goto out;
1389
1390         if (!name)
1391                 name = dm_task_get_name(dmt);
1392
1393         /* Fetch targets and print 'em */
1394         do {
1395                 next = dm_get_next_target(dmt, next, &start, &length,
1396                                           &target_type, &params);
1397                 /* Skip if target type doesn't match */
1398                 if (_switches[TARGET_ARG] &&
1399                     (!target_type || strcmp(target_type, _target)))
1400                         continue;
1401                 if (ls_only) {
1402                         if (!_switches[EXEC_ARG] || !_command ||
1403                             _switches[VERBOSE_ARG])
1404                                 _display_dev(dmt, name);
1405                         next = NULL;
1406                 } else if (!_switches[EXEC_ARG] || !_command ||
1407                            _switches[VERBOSE_ARG]) {
1408                         if (!matched && _switches[VERBOSE_ARG])
1409                                 _display_info(dmt);
1410                         if (data && !_switches[VERBOSE_ARG])
1411                                 printf("%s: ", name);
1412                         if (target_type) {
1413                                 /* Suppress encryption key */
1414                                 if (!_switches[SHOWKEYS_ARG] &&
1415                                     cmd == DM_DEVICE_TABLE &&
1416                                     !strcmp(target_type, "crypt")) {
1417                                         c = params;
1418                                         while (*c && *c != ' ')
1419                                                 c++;
1420                                         if (*c)
1421                                                 c++;
1422                                         while (*c && *c != ' ')
1423                                                 *c++ = '0';
1424                                 }
1425                                 printf("%" PRIu64 " %" PRIu64 " %s %s",
1426                                        start, length, target_type, params);
1427                         }
1428                         printf("\n");
1429                 }
1430                 matched = 1;
1431         } while (next);
1432
1433         if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
1434                 printf("\n");
1435
1436         if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
1437                 goto out;
1438
1439         r = 1;
1440
1441       out:
1442         dm_task_destroy(dmt);
1443         return r;
1444 }
1445
1446 /* Show target names and their version numbers */
1447 static int _targets(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
1448 {
1449         int r = 0;
1450         struct dm_task *dmt;
1451         struct dm_versions *target;
1452         struct dm_versions *last_target;
1453
1454         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
1455                 return 0;
1456
1457         if (!dm_task_run(dmt))
1458                 goto out;
1459
1460         target = dm_task_get_versions(dmt);
1461
1462         /* Fetch targets and print 'em */
1463         do {
1464                 last_target = target;
1465
1466                 printf("%-16s v%d.%d.%d\n", target->name, target->version[0],
1467                        target->version[1], target->version[2]);
1468
1469                 target = (void *) target + target->next;
1470         } while (last_target != target);
1471
1472         r = 1;
1473
1474       out:
1475         dm_task_destroy(dmt);
1476         return r;
1477 }
1478
1479 static int _info(int argc, char **argv, void *data)
1480 {
1481         int r = 0;
1482
1483         struct dm_task *dmt;
1484         struct dm_names *names = (struct dm_names *) data;
1485         char *name = NULL;
1486
1487         if (data)
1488                 name = names->name;
1489         else {
1490                 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1491                         return _process_all(argc, argv, 0, _info);
1492                 if (argc == 2)
1493                         name = argv[1];
1494         }
1495
1496         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
1497                 return 0;
1498
1499         if (!_set_task_device(dmt, name, 0))
1500                 goto out;
1501
1502         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1503                 goto out;
1504
1505         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1506                 goto out;
1507
1508         if (!dm_task_run(dmt))
1509                 goto out;
1510
1511         r = _display_info(dmt);
1512
1513       out:
1514         dm_task_destroy(dmt);
1515         return r;
1516 }
1517
1518 static int _deps(int argc, char **argv, void *data)
1519 {
1520         int r = 0;
1521         uint32_t i;
1522         struct dm_deps *deps;
1523         struct dm_task *dmt;
1524         struct dm_info info;
1525         struct dm_names *names = (struct dm_names *) data;
1526         char *name = NULL;
1527
1528         if (data)
1529                 name = names->name;
1530         else {
1531                 if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1532                         return _process_all(argc, argv, 0, _deps);
1533                 if (argc == 2)
1534                         name = argv[1];
1535         }
1536
1537         if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
1538                 return 0;
1539
1540         if (!_set_task_device(dmt, name, 0))
1541                 goto out;
1542
1543         if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1544                 goto out;
1545
1546         if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1547                 goto out;
1548
1549         if (!dm_task_run(dmt))
1550                 goto out;
1551
1552         if (!dm_task_get_info(dmt, &info))
1553                 goto out;
1554
1555         if (!(deps = dm_task_get_deps(dmt)))
1556                 goto out;
1557
1558         if (!info.exists) {
1559                 printf("Device does not exist.\n");
1560                 r = 1;
1561                 goto out;
1562         }
1563
1564         if (_switches[VERBOSE_ARG])
1565                 _display_info(dmt);
1566
1567         if (data && !_switches[VERBOSE_ARG])
1568                 printf("%s: ", name);
1569         printf("%d dependencies\t:", deps->count);
1570
1571         for (i = 0; i < deps->count; i++)
1572                 printf(" (%d, %d)",
1573                        (int) MAJOR(deps->device[i]),
1574                        (int) MINOR(deps->device[i]));
1575         printf("\n");
1576
1577         if (data && _switches[VERBOSE_ARG])
1578                 printf("\n");
1579
1580         r = 1;
1581
1582       out:
1583         dm_task_destroy(dmt);
1584         return r;
1585 }
1586
1587 static int _display_name(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
1588 {
1589         struct dm_names *names = (struct dm_names *) data;
1590
1591         printf("%s\t(%d, %d)\n", names->name,
1592                (int) MAJOR(names->dev), (int) MINOR(names->dev));
1593
1594         return 1;
1595 }
1596
1597 /*
1598  * Tree drawing code
1599  */
1600
1601 enum {
1602         TR_DEVICE=0,    /* display device major:minor number */
1603         TR_TABLE,
1604         TR_STATUS,
1605         TR_ACTIVE,
1606         TR_RW,
1607         TR_OPENCOUNT,
1608         TR_UUID,
1609         TR_COMPACT,
1610         TR_TRUNCATE,
1611         TR_BOTTOMUP,
1612         NUM_TREEMODE,
1613 };
1614
1615 static int _tree_switches[NUM_TREEMODE];
1616
1617 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1618                              _tree_switches[TR_RW] || \
1619                              _tree_switches[TR_OPENCOUNT] || \
1620                              _tree_switches[TR_UUID] )
1621
1622 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1623                            _tree_switches[TR_STATUS] )
1624
1625 /* Compact - fewer newlines */
1626 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1627                           !TR_PRINT_ATTRIBUTE && \
1628                           !TR_PRINT_TARGETS)
1629
1630 /* FIXME Get rid of this */
1631 #define MAX_DEPTH 100
1632
1633 /* Drawing character definition from pstree */
1634 /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
1635 #define UTF_V   "\342\224\202"  /* U+2502, Vertical line drawing char */
1636 #define UTF_VR  "\342\224\234"  /* U+251C, Vertical and right */
1637 #define UTF_H   "\342\224\200"  /* U+2500, Horizontal */
1638 #define UTF_UR  "\342\224\224"  /* U+2514, Up and right */
1639 #define UTF_HD  "\342\224\254"  /* U+252C, Horizontal and down */
1640
1641 #define VT_BEG  "\033(0\017"    /* use graphic chars */
1642 #define VT_END  "\033(B"        /* back to normal char set */
1643 #define VT_V    "x"             /* see UTF definitions above */
1644 #define VT_VR   "t"
1645 #define VT_H    "q"
1646 #define VT_UR   "m"
1647 #define VT_HD   "w"
1648
1649 static struct {
1650         const char *empty_2;    /*    */
1651         const char *branch_2;   /* |- */
1652         const char *vert_2;     /* |  */
1653         const char *last_2;     /* `- */
1654         const char *single_3;   /* --- */
1655         const char *first_3;    /* -+- */
1656 }
1657 _tsym_ascii = {
1658         "  ",
1659         "|-",
1660         "| ",
1661         "`-",
1662         "---",
1663         "-+-"
1664 },
1665 _tsym_utf = {
1666         "  ",
1667         UTF_VR UTF_H,
1668         UTF_V " ",
1669         UTF_UR UTF_H,
1670         UTF_H UTF_H UTF_H,
1671         UTF_H UTF_HD UTF_H
1672 },
1673 _tsym_vt100 = {
1674         "  ",
1675         VT_BEG VT_VR VT_H VT_END,
1676         VT_BEG VT_V VT_END " ",
1677         VT_BEG VT_UR VT_H VT_END,
1678         VT_BEG VT_H VT_H VT_H VT_END,
1679         VT_BEG VT_H VT_HD VT_H VT_END
1680 },
1681 *_tsym = &_tsym_ascii;
1682
1683 /*
1684  * Tree drawing functions.
1685  */
1686 /* FIXME Get rid of these statics - use dynamic struct */
1687 /* FIXME Explain what these vars are for */
1688 static int _tree_width[MAX_DEPTH], _tree_more[MAX_DEPTH];
1689 static int _termwidth = 80;     /* Maximum output width */
1690 static int _cur_x = 1;          /* Current horizontal output position */
1691 static char _last_char = 0;
1692
1693 static void _out_char(const unsigned c)
1694 {
1695         /* Only first UTF-8 char counts */
1696         _cur_x += ((c & 0xc0) != 0x80);
1697
1698         if (!_tree_switches[TR_TRUNCATE]) {
1699                 putchar((int) c);
1700                 return;
1701         }
1702
1703         /* Truncation? */
1704         if (_cur_x <= _termwidth)
1705                 putchar((int) c);
1706
1707         if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) {
1708                 if (_last_char || (c & 0x80)) {
1709                         putchar('.');
1710                         putchar('.');
1711                         putchar('.');
1712                 } else {
1713                         _last_char = c;
1714                         _cur_x--;
1715                 }
1716         }
1717 }
1718
1719 static void _out_string(const char *str)
1720 {
1721         while (*str)
1722                 _out_char((unsigned char) *str++);
1723 }
1724
1725 /* non-negative integers only */
1726 static unsigned _out_int(unsigned num)
1727 {
1728         unsigned digits = 0;
1729         unsigned divi;
1730
1731         if (!num) {
1732                 _out_char('0');
1733                 return 1;
1734         }
1735
1736         /* non zero case */
1737         for (divi = 1; num / divi; divi *= 10)
1738                 digits++;
1739
1740         for (divi /= 10; divi; divi /= 10)
1741                 _out_char('0' + (num / divi) % 10);
1742
1743         return digits;
1744 }
1745
1746 static void _out_newline(void)
1747 {
1748         if (_last_char && _cur_x == _termwidth)
1749                 putchar(_last_char);
1750         _last_char = 0;
1751         putchar('\n');
1752         _cur_x = 1;
1753 }
1754
1755 static void _out_prefix(unsigned depth)
1756 {
1757         unsigned x, d;
1758
1759         for (d = 0; d < depth; d++) {
1760                 for (x = _tree_width[d] + 1; x > 0; x--)
1761                         _out_char(' ');
1762
1763                 _out_string(d == depth - 1 ?
1764                                 !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2
1765                            : _tree_more[d + 1] ?
1766                                 _tsym->vert_2 : _tsym->empty_2);
1767         }
1768 }
1769
1770 /*
1771  * Display tree
1772  */
1773 static void _display_tree_attributes(struct dm_tree_node *node)
1774 {
1775         int attr = 0;
1776         const char *uuid;
1777         const struct dm_info *info;
1778
1779         uuid = dm_tree_node_get_uuid(node);
1780         info = dm_tree_node_get_info(node);
1781
1782         if (!info->exists)
1783                 return;
1784
1785         if (_tree_switches[TR_ACTIVE]) {
1786                 _out_string(attr++ ? ", " : " [");
1787                 _out_string(info->suspended ? "SUSPENDED" : "ACTIVE");
1788         }
1789
1790         if (_tree_switches[TR_RW]) {
1791                 _out_string(attr++ ? ", " : " [");
1792                 _out_string(info->read_only ? "RO" : "RW");
1793         }
1794
1795         if (_tree_switches[TR_OPENCOUNT]) {
1796                 _out_string(attr++ ? ", " : " [");
1797                 (void) _out_int((unsigned) info->open_count);
1798         }
1799
1800         if (_tree_switches[TR_UUID]) {
1801                 _out_string(attr++ ? ", " : " [");
1802                 _out_string(uuid && *uuid ? uuid : "");
1803         }
1804
1805         if (attr)
1806                 _out_char(']');
1807 }
1808
1809 static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
1810                                unsigned first_child __attribute((unused)),
1811                                unsigned last_child, unsigned has_children)
1812 {
1813         int offset;
1814         const char *name;
1815         const struct dm_info *info;
1816         int first_on_line = 0;
1817
1818         /* Sub-tree for targets has 2 more depth */
1819         if (depth + 2 > MAX_DEPTH)
1820                 return;
1821
1822         name = dm_tree_node_get_name(node);
1823
1824         if ((!name || !*name) && !_tree_switches[TR_DEVICE])
1825                 return;
1826
1827         /* Indicate whether there are more nodes at this depth */
1828         _tree_more[depth] = !last_child;
1829         _tree_width[depth] = 0;
1830
1831         if (_cur_x == 1)
1832                 first_on_line = 1;
1833
1834         if (!TR_PRINT_COMPACT || first_on_line)
1835                 _out_prefix(depth);
1836
1837         /* Remember the starting point for compact */
1838         offset = _cur_x;
1839
1840         if (TR_PRINT_COMPACT && !first_on_line)
1841                 _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3);
1842
1843         /* display node */
1844         if (name)
1845                 _out_string(name);
1846
1847         info = dm_tree_node_get_info(node);
1848
1849         if (_tree_switches[TR_DEVICE]) {
1850                 _out_string(name ? " (" : "(");
1851                 (void) _out_int(info->major);
1852                 _out_char(':');
1853                 (void) _out_int(info->minor);
1854                 _out_char(')');
1855         }
1856
1857         /* display additional info */
1858         if (TR_PRINT_ATTRIBUTE)
1859                 _display_tree_attributes(node);
1860
1861         if (TR_PRINT_COMPACT)
1862                 _tree_width[depth] = _cur_x - offset;
1863
1864         if (!TR_PRINT_COMPACT || !has_children)
1865                 _out_newline();
1866
1867         if (TR_PRINT_TARGETS) {
1868                 _tree_more[depth + 1] = has_children;
1869                 // FIXME _display_tree_targets(name, depth + 2);
1870         }
1871 }
1872
1873 /*
1874  * Walk the dependency tree
1875  */
1876 static void _display_tree_walk_children(struct dm_tree_node *node,
1877                                         unsigned depth)
1878 {
1879         struct dm_tree_node *child, *next_child;
1880         void *handle = NULL;
1881         uint32_t inverted = _tree_switches[TR_BOTTOMUP];
1882         unsigned first_child = 1;
1883         unsigned has_children;
1884
1885         next_child = dm_tree_next_child(&handle, node, inverted);
1886
1887         while ((child = next_child)) {
1888                 next_child = dm_tree_next_child(&handle, node, inverted);
1889                 has_children =
1890                     dm_tree_node_num_children(child, inverted) ? 1 : 0;
1891
1892                 _display_tree_node(child, depth, first_child,
1893                                    next_child ? 0U : 1U, has_children);
1894
1895                 if (has_children)
1896                         _display_tree_walk_children(child, depth + 1);
1897
1898                 first_child = 0;
1899         }
1900 }
1901
1902 static int _add_dep(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
1903 {
1904         struct dm_names *names = (struct dm_names *) data;
1905
1906         if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
1907                 return 0;
1908
1909         return 1;
1910 }
1911
1912 /*
1913  * Create and walk dependency tree
1914  */
1915 static int _build_whole_deptree(void)
1916 {
1917         if (_dtree)
1918                 return 1;
1919
1920         if (!(_dtree = dm_tree_create()))
1921                 return 0;
1922
1923         if (!_process_all(0, NULL, 0, _add_dep))
1924                 return 0;
1925
1926         return 1;
1927 }
1928
1929 static int _display_tree(int argc __attribute((unused)),
1930                          char **argv __attribute((unused)),
1931                          void *data __attribute((unused)))
1932 {
1933         if (!_build_whole_deptree())
1934                 return 0;
1935
1936         _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
1937
1938         return 1;
1939 }
1940
1941 /*
1942  * Report device information
1943  */
1944
1945 /* dm specific display functions */
1946
1947 static int _int32_disp(struct dm_report *rh,
1948                        struct dm_pool *mem __attribute((unused)),
1949                        struct dm_report_field *field, const void *data,
1950                        void *private __attribute((unused)))
1951 {
1952         const int32_t value = *(const int32_t *)data;
1953
1954         return dm_report_field_int32(rh, field, &value);
1955 }
1956
1957 static int _uint32_disp(struct dm_report *rh,
1958                         struct dm_pool *mem __attribute((unused)),
1959                         struct dm_report_field *field, const void *data,
1960                         void *private __attribute((unused)))
1961 {
1962         const uint32_t value = *(const int32_t *)data;
1963
1964         return dm_report_field_uint32(rh, field, &value);
1965 }
1966
1967 static int _dm_name_disp(struct dm_report *rh,
1968                          struct dm_pool *mem __attribute((unused)),
1969                          struct dm_report_field *field, const void *data,
1970                          void *private __attribute((unused)))
1971 {
1972         const char *name = dm_task_get_name((const struct dm_task *) data);
1973
1974         return dm_report_field_string(rh, field, &name);
1975 }
1976
1977 static int _dm_uuid_disp(struct dm_report *rh,
1978                          struct dm_pool *mem __attribute((unused)),
1979                          struct dm_report_field *field,
1980                          const void *data, void *private __attribute((unused)))
1981 {
1982         const char *uuid = dm_task_get_uuid((const struct dm_task *) data);
1983
1984         if (!uuid || !*uuid)
1985                 uuid = "";
1986
1987         return dm_report_field_string(rh, field, &uuid);
1988 }
1989
1990 static int _dm_read_ahead_disp(struct dm_report *rh,
1991                                struct dm_pool *mem __attribute((unused)),
1992                                struct dm_report_field *field, const void *data,
1993                                void *private __attribute((unused)))
1994 {
1995         uint32_t value;
1996
1997         if (!dm_task_get_read_ahead((const struct dm_task *) data, &value))
1998                 value = 0;
1999
2000         return dm_report_field_uint32(rh, field, &value);
2001 }
2002
2003 static int _dm_info_status_disp(struct dm_report *rh,
2004                                 struct dm_pool *mem __attribute((unused)),
2005                                 struct dm_report_field *field, const void *data,
2006                                 void *private __attribute((unused)))
2007 {
2008         char buf[5];
2009         const char *s = buf;
2010         const struct dm_info *info = data;
2011
2012         buf[0] = info->live_table ? 'L' : '-';
2013         buf[1] = info->inactive_table ? 'I' : '-';
2014         buf[2] = info->suspended ? 's' : '-';
2015         buf[3] = info->read_only ? 'r' : 'w';
2016         buf[4] = '\0';
2017
2018         return dm_report_field_string(rh, field, &s);
2019 }
2020
2021 static int _dm_info_table_loaded_disp(struct dm_report *rh,
2022                                       struct dm_pool *mem __attribute((unused)),
2023                                       struct dm_report_field *field,
2024                                       const void *data,
2025                                       void *private __attribute((unused)))
2026 {
2027         const struct dm_info *info = data;
2028
2029         if (info->live_table) {
2030                 if (info->inactive_table)
2031                         dm_report_field_set_value(field, "Both", NULL);
2032                 else
2033                         dm_report_field_set_value(field, "Live", NULL);
2034                 return 1;
2035         }
2036
2037         if (info->inactive_table)
2038                 dm_report_field_set_value(field, "Inactive", NULL);
2039         else
2040                 dm_report_field_set_value(field, "None", NULL);
2041
2042         return 1;
2043 }
2044
2045 static int _dm_info_suspended_disp(struct dm_report *rh,
2046                                    struct dm_pool *mem __attribute((unused)),
2047                                    struct dm_report_field *field,
2048                                    const void *data,
2049                                    void *private __attribute((unused)))
2050 {
2051         const struct dm_info *info = data;
2052
2053         if (info->suspended)
2054                 dm_report_field_set_value(field, "Suspended", NULL);
2055         else
2056                 dm_report_field_set_value(field, "Active", NULL);
2057
2058         return 1;
2059 }
2060
2061 static int _dm_info_read_only_disp(struct dm_report *rh,
2062                                    struct dm_pool *mem __attribute((unused)),
2063                                    struct dm_report_field *field,
2064                                    const void *data,
2065                                    void *private __attribute((unused)))
2066 {
2067         const struct dm_info *info = data;
2068
2069         if (info->read_only)
2070                 dm_report_field_set_value(field, "Read-only", NULL);
2071         else
2072                 dm_report_field_set_value(field, "Writeable", NULL);
2073
2074         return 1;
2075 }
2076
2077
2078 static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
2079                                struct dm_report_field *field, const void *data,
2080                                void *private)
2081 {
2082         char buf[DM_MAX_TYPE_NAME], *repstr;
2083         struct dm_info *info = (struct dm_info *) data;
2084
2085         if (!dm_pool_begin_object(mem, 8)) {
2086                 log_error("dm_pool_begin_object failed");
2087                 return 0;
2088         }
2089
2090         if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2091                         info->major, info->minor) < 0) {
2092                 log_error("dm_pool_alloc failed");
2093                 goto out_abandon;
2094         }
2095
2096         if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
2097                 log_error("dm_pool_grow_object failed");
2098                 goto out_abandon;
2099         }
2100
2101         repstr = dm_pool_end_object(mem);
2102         dm_report_field_set_value(field, repstr, repstr);
2103         return 1;
2104
2105       out_abandon:
2106         dm_pool_abandon_object(mem);
2107         return 0;
2108 }
2109
2110 static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem,
2111                           struct dm_report_field *field, const void *data,
2112                           void *private, unsigned inverted)
2113 {
2114         struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
2115         void *t = NULL;
2116         const char *name;
2117         int first_node = 1;
2118         char *repstr;
2119
2120         if (!dm_pool_begin_object(mem, 16)) {
2121                 log_error("dm_pool_begin_object failed");
2122                 return 0;
2123         }
2124
2125         while ((parent = dm_tree_next_child(&t, node, inverted))) {
2126                 name = dm_tree_node_get_name(parent);
2127                 if (!name || !*name)
2128                         continue;
2129                 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2130                         log_error("dm_pool_grow_object failed");
2131                         goto out_abandon;
2132                 }
2133                 if (!dm_pool_grow_object(mem, name, 0)) {
2134                         log_error("dm_pool_grow_object failed");
2135                         goto out_abandon;
2136                 }
2137                 if (first_node)
2138                         first_node = 0;
2139         }
2140
2141         if (!dm_pool_grow_object(mem, "\0", 1)) {
2142                 log_error("dm_pool_grow_object failed");
2143                 goto out_abandon;
2144         }
2145
2146         repstr = dm_pool_end_object(mem);
2147         dm_report_field_set_value(field, repstr, repstr);
2148         return 1;
2149
2150       out_abandon:
2151         dm_pool_abandon_object(mem);
2152         return 0;
2153 }
2154
2155 static int _dm_deps_names_disp(struct dm_report *rh,
2156                                       struct dm_pool *mem,
2157                                       struct dm_report_field *field,
2158                                       const void *data, void *private)
2159 {
2160         return _dm_tree_names(rh, mem, field, data, private, 0);
2161 }
2162
2163 static int _dm_tree_parents_names_disp(struct dm_report *rh,
2164                                        struct dm_pool *mem,
2165                                        struct dm_report_field *field,
2166                                        const void *data, void *private)
2167 {
2168         return _dm_tree_names(rh, mem, field, data, private, 1);
2169 }
2170
2171 static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem,
2172                                       struct dm_report_field *field,
2173                                       const void *data, void *private)
2174 {
2175         struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
2176         void *t = NULL;
2177         const struct dm_info *info;
2178         int first_node = 1;
2179         char buf[DM_MAX_TYPE_NAME], *repstr;
2180
2181         if (!dm_pool_begin_object(mem, 16)) {
2182                 log_error("dm_pool_begin_object failed");
2183                 return 0;
2184         }
2185
2186         while ((parent = dm_tree_next_child(&t, node, 1))) {
2187                 info = dm_tree_node_get_info(parent);
2188                 if (!info->major && !info->minor)
2189                         continue;
2190                 if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2191                         log_error("dm_pool_grow_object failed");
2192                         goto out_abandon;
2193                 }
2194                 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2195                                 info->major, info->minor) < 0) {
2196                         log_error("dm_snprintf failed");
2197                         goto out_abandon;
2198                 }
2199                 if (!dm_pool_grow_object(mem, buf, 0)) {
2200                         log_error("dm_pool_grow_object failed");
2201                         goto out_abandon;
2202                 }
2203                 if (first_node)
2204                         first_node = 0;
2205         }
2206
2207         if (!dm_pool_grow_object(mem, "\0", 1)) {
2208                 log_error("dm_pool_grow_object failed");
2209                 goto out_abandon;
2210         }
2211
2212         repstr = dm_pool_end_object(mem);
2213         dm_report_field_set_value(field, repstr, repstr);
2214         return 1;
2215
2216       out_abandon:
2217         dm_pool_abandon_object(mem);
2218         return 0;
2219 }
2220
2221 static int _dm_tree_parents_count_disp(struct dm_report *rh,
2222                                        struct dm_pool *mem,
2223                                        struct dm_report_field *field,
2224                                        const void *data, void *private)
2225 {
2226         struct dm_tree_node *node = (struct dm_tree_node *) data;
2227         int num_parent = dm_tree_node_num_children(node, 1);
2228
2229         return dm_report_field_int(rh, field, &num_parent);
2230 }
2231
2232 static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
2233                          struct dm_report_field *field, const void *data,
2234                          void *private)
2235 {
2236         struct dm_deps *deps = (struct dm_deps *) data;
2237         int i;
2238         char buf[DM_MAX_TYPE_NAME], *repstr;
2239
2240         if (!dm_pool_begin_object(mem, 16)) {
2241                 log_error("dm_pool_begin_object failed");
2242                 return 0;
2243         }
2244
2245         for (i = 0; i < deps->count; i++) {
2246                 if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2247                        (int) MAJOR(deps->device[i]),
2248                        (int) MINOR(deps->device[i])) < 0) {
2249                         log_error("dm_snprintf failed");
2250                         goto out_abandon;
2251                 }
2252                 if (!dm_pool_grow_object(mem, buf, 0)) {
2253                         log_error("dm_pool_grow_object failed");
2254                         goto out_abandon;
2255                 }
2256                 if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
2257                         log_error("dm_pool_grow_object failed");
2258                         goto out_abandon;
2259                 }
2260         }
2261
2262         if (!dm_pool_grow_object(mem, "\0", 1)) {
2263                 log_error("dm_pool_grow_object failed");
2264                 goto out_abandon;
2265         }
2266
2267         repstr = dm_pool_end_object(mem);
2268         dm_report_field_set_value(field, repstr, repstr);
2269         return 1;
2270
2271       out_abandon:
2272         dm_pool_abandon_object(mem);
2273         return 0;
2274 }
2275
2276 static int _dm_subsystem_disp(struct dm_report *rh,
2277                                struct dm_pool *mem __attribute((unused)),
2278                                struct dm_report_field *field, const void *data,
2279                                void *private __attribute((unused)))
2280 {
2281         return dm_report_field_string(rh, field, (const char **) data);
2282 }
2283
2284 static int _dm_vg_name_disp(struct dm_report *rh,
2285                              struct dm_pool *mem __attribute((unused)),
2286                              struct dm_report_field *field, const void *data,
2287                              void *private __attribute((unused)))
2288 {
2289
2290         return dm_report_field_string(rh, field, (const char **) data);
2291 }
2292
2293 static int _dm_lv_name_disp(struct dm_report *rh,
2294                              struct dm_pool *mem __attribute((unused)),
2295                              struct dm_report_field *field, const void *data,
2296                              void *private __attribute((unused)))
2297
2298 {
2299         return dm_report_field_string(rh, field, (const char **) data);
2300 }
2301
2302 static int _dm_lv_layer_name_disp(struct dm_report *rh,
2303                                    struct dm_pool *mem __attribute((unused)),
2304                                    struct dm_report_field *field, const void *data,
2305                                    void *private __attribute((unused)))
2306
2307 {
2308         return dm_report_field_string(rh, field, (const char **) data);
2309 }
2310
2311 static void *_task_get_obj(void *obj)
2312 {
2313         return ((struct dmsetup_report_obj *)obj)->task;
2314 }
2315
2316 static void *_info_get_obj(void *obj)
2317 {
2318         return ((struct dmsetup_report_obj *)obj)->info;
2319 }
2320
2321 static void *_deps_get_obj(void *obj)
2322 {
2323         return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task);
2324 }
2325
2326 static void *_tree_get_obj(void *obj)
2327 {
2328         return ((struct dmsetup_report_obj *)obj)->tree_node;
2329 }
2330
2331 static void *_split_name_get_obj(void *obj)
2332 {
2333         return ((struct dmsetup_report_obj *)obj)->split_name;
2334 }
2335
2336 static const struct dm_report_object_type _report_types[] = {
2337         { DR_TASK, "Mapped Device Name", "", _task_get_obj },
2338         { DR_INFO, "Mapped Device Information", "", _info_get_obj },
2339         { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj },
2340         { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj },
2341         { DR_NAME, "Mapped Device Name Components", "", _split_name_get_obj },
2342         { 0, "", "", NULL },
2343 };
2344
2345 /* Column definitions */
2346 #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
2347 #define STR (DM_REPORT_FIELD_TYPE_STRING)
2348 #define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
2349 #define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},
2350 #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
2351
2352 static const struct dm_report_field_type _report_fields[] = {
2353 /* *INDENT-OFF* */
2354 FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
2355 FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
2356
2357 /* FIXME Next one should be INFO */
2358 FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
2359
2360 FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
2361 FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
2362 FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
2363 FIELD_F(INFO, STR, "Read-only", 9, dm_info_read_only, "readonly", "Whether the device is read-only or writeable.")
2364 FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers")
2365 FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
2366 FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
2367 FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
2368 FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
2369 FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
2370
2371 FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
2372 FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
2373 FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
2374
2375 FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
2376 FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
2377 FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one.")
2378
2379 FIELD_O(NAME, dm_split_name, STR, "Subsys", subsystem, 6, dm_subsystem, "subsystem", "Userspace subsystem responsible for this device.")
2380 FIELD_O(NAME, dm_split_name, STR, "VG", vg_name, 4, dm_vg_name, "vg_name", "LVM Volume Group name.")
2381 FIELD_O(NAME, dm_split_name, STR, "LV", lv_name, 4, dm_lv_name, "lv_name", "LVM Logical Volume name.")
2382 FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_layer", "LVM device layer.")
2383
2384 {0, 0, 0, 0, "", "", NULL, NULL},
2385 /* *INDENT-ON* */
2386 };
2387
2388 #undef STR
2389 #undef NUM
2390 #undef FIELD_O
2391 #undef FIELD_F
2392
2393 static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
2394 static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
2395
2396 static int _report_init(struct command *c)
2397 {
2398         char *options = (char *) default_report_options;
2399         const char *keys = "";
2400         const char *separator = " ";
2401         int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
2402         int quoted = 1, columns_as_rows = 0;
2403         uint32_t flags = 0;
2404         size_t len = 0;
2405         int r = 0;
2406
2407         if (!strcmp(c->name, "splitname"))
2408                 options = (char *) splitname_report_options;
2409
2410         /* emulate old dmsetup behaviour */
2411         if (_switches[NOHEADINGS_ARG]) {
2412                 separator = ":";
2413                 aligned = 0;
2414                 headings = 0;
2415         }
2416
2417         if (_switches[UNBUFFERED_ARG])
2418                 buffered = 0;
2419
2420         if (_switches[ROWS_ARG])
2421                 columns_as_rows = 1;
2422
2423         if (_switches[UNQUOTED_ARG])
2424                 quoted = 0;
2425
2426         if (_switches[NAMEPREFIXES_ARG]) {
2427                 aligned = 0;
2428                 field_prefixes = 1;
2429         }
2430
2431         if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
2432                 if (*_string_args[OPTIONS_ARG] != '+')
2433                         options = _string_args[OPTIONS_ARG];
2434                 else {
2435                         len = strlen(default_report_options) +
2436                               strlen(_string_args[OPTIONS_ARG]) + 1;
2437                         if (!(options = dm_malloc(len))) {
2438                                 err("Failed to allocate option string.");
2439                                 return 0;
2440                         }
2441                         if (dm_snprintf(options, len, "%s,%s",
2442                                         default_report_options,
2443                                         &_string_args[OPTIONS_ARG][1]) < 0) {
2444                                 err("snprintf failed");
2445                                 goto out;
2446                         }
2447                 }
2448         }
2449
2450         if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
2451                 keys = _string_args[SORT_ARG];
2452                 buffered = 1;
2453                 if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
2454                         err("--sort is not yet supported with status and table");
2455                         goto out;
2456                 }
2457         }
2458
2459         if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
2460                 separator = _string_args[SEPARATOR_ARG];
2461                 aligned = 0;
2462         }
2463
2464         if (aligned)
2465                 flags |= DM_REPORT_OUTPUT_ALIGNED;
2466
2467         if (buffered)
2468                 flags |= DM_REPORT_OUTPUT_BUFFERED;
2469
2470         if (headings)
2471                 flags |= DM_REPORT_OUTPUT_HEADINGS;
2472
2473         if (field_prefixes)
2474                 flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
2475
2476         if (!quoted)
2477                 flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
2478
2479         if (columns_as_rows)
2480                 flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
2481
2482         if (!(_report = dm_report_init(&_report_type,
2483                                        _report_types, _report_fields,
2484                                        options, separator, flags, keys, NULL)))
2485                 goto out;
2486
2487         if ((_report_type & DR_TREE) && !_build_whole_deptree()) {
2488                 err("Internal device dependency tree creation failed.");
2489                 goto out;
2490         }
2491
2492         if (field_prefixes)
2493                 dm_report_set_output_field_name_prefix(_report, "dm_");
2494
2495         r = 1;
2496
2497 out:
2498         if (len)
2499                 dm_free(options);
2500
2501         return r;
2502 }
2503
2504 /*
2505  * List devices
2506  */
2507 static int _ls(int argc, char **argv, void *data)
2508 {
2509         if ((_switches[TARGET_ARG] && _target) ||
2510             (_switches[EXEC_ARG] && _command))
2511                 return _status(argc, argv, data);
2512         else if ((_switches[TREE_ARG]))
2513                 return _display_tree(argc, argv, data);
2514         else
2515                 return _process_all(argc, argv, 0, _display_name);
2516 }
2517
2518 static int _help(int argc, char **argv, void *data);
2519
2520 /*
2521  * Dispatch table
2522  */
2523 static struct command _commands[] = {
2524         {"help", "[-c|-C|--columns]", 0, 0, _help},
2525         {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
2526           "\t                  [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
2527           "\t                  [-u|uuid <uuid>]\n"
2528           "\t                  [--notable | --table <table> | <table_file>]",
2529          1, 2, _create},
2530         {"remove", "[-f|--force] <device>", 0, 1, _remove},
2531         {"remove_all", "[-f|--force]", 0, 0, _remove_all},
2532         {"suspend", "[--noflush] <device>", 0, 1, _suspend},
2533         {"resume", "<device>", 0, 1, _resume},
2534         {"load", "<device> [<table_file>]", 0, 2, _load},
2535         {"clear", "<device>", 0, 1, _clear},
2536         {"reload", "<device> [<table_file>]", 0, 2, _load},
2537         {"rename", "<device> <new_name>", 1, 2, _rename},
2538         {"message", "<device> <sector> <message>", 2, -1, _message},
2539         {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
2540         {"info", "[<device>]", 0, 1, _info},
2541         {"deps", "[<device>]", 0, 1, _deps},
2542         {"status", "[<device>] [--target <target_type>]", 0, 1, _status},
2543         {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
2544         {"wait", "<device> [<event_nr>]", 0, 2, _wait},
2545         {"mknodes", "[<device>]", 0, 1, _mknodes},
2546         {"udevflags", "<cookie>", 1, 1, _udevflags},
2547         {"udevcomplete", "<cookie>", 1, 1, _udevcomplete},
2548         {"udevcomplete_all", "", 0, 0, _udevcomplete_all},
2549         {"udevcookies", "", 0, 0, _udevcookies},
2550         {"targets", "", 0, 0, _targets},
2551         {"version", "", 0, 0, _version},
2552         {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
2553         {"splitname", "<device> [<subsystem>]", 1, 2, _splitname},
2554         {NULL, NULL, 0, 0, NULL}
2555 };
2556
2557 static void _usage(FILE *out)
2558 {
2559         int i;
2560
2561         fprintf(out, "Usage:\n\n");
2562         fprintf(out, "dmsetup [--version] [-v|--verbose [-v|--verbose ...]]\n"
2563                 "        [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
2564                 "        [--noudevsync] [-y|--yes] [--readahead [+]<sectors>|auto|none]\n"
2565                 "        [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
2566                 "        [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
2567         for (i = 0; _commands[i].name; i++)
2568                 fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
2569         fprintf(out, "\n<device> may be device name or -u <uuid> or "
2570                      "-j <major> -m <minor>\n");
2571         fprintf(out, "<fields> are comma-separated.  Use 'help -c' for list.\n");
2572         fprintf(out, "Table_file contents may be supplied on stdin.\n");
2573         fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
2574                      "                  [no]device, active, open, rw and uuid.\n");
2575         fprintf(out, "\n");
2576         return;
2577 }
2578
2579 static void _losetup_usage(FILE *out)
2580 {
2581         fprintf(out, "Usage:\n\n");
2582         fprintf(out, "losetup [-d|-a] [-e encryption] "
2583                      "[-o offset] [-f|loop_device] [file]\n\n");
2584 }
2585
2586 static int _help(int argc __attribute((unused)),
2587                  char **argv __attribute((unused)),
2588                  void *data __attribute((unused)))
2589 {
2590         _usage(stderr);
2591
2592         if (_switches[COLS_ARG]) {
2593                 _switches[OPTIONS_ARG] = 1;
2594                 _string_args[OPTIONS_ARG] = (char *) "help";
2595                 _switches[SORT_ARG] = 0;
2596         
2597                 (void) _report_init(NULL);
2598         }
2599
2600         return 1;
2601 }
2602
2603 static struct command *_find_command(const char *name)
2604 {
2605         int i;
2606
2607         for (i = 0; _commands[i].name; i++)
2608                 if (!strcmp(_commands[i].name, name))
2609                         return _commands + i;
2610
2611         return NULL;
2612 }
2613
2614 static int _process_tree_options(const char *options)
2615 {
2616         const char *s, *end;
2617         struct winsize winsz;
2618         size_t len;
2619
2620         /* Symbol set default */
2621         if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
2622                 _tsym = &_tsym_utf;
2623         else
2624                 _tsym = &_tsym_ascii;
2625
2626         /* Default */
2627         _tree_switches[TR_DEVICE] = 1;
2628         _tree_switches[TR_TRUNCATE] = 1;
2629
2630         /* parse */
2631         for (s = options; s && *s; s++) {
2632                 len = 0;
2633                 for (end = s; *end && *end != ','; end++, len++)
2634                         ;
2635                 if (!strncmp(s, "device", len))
2636                         _tree_switches[TR_DEVICE] = 1;
2637                 else if (!strncmp(s, "nodevice", len))
2638                         _tree_switches[TR_DEVICE] = 0;
2639                 else if (!strncmp(s, "status", len))
2640                         _tree_switches[TR_STATUS] = 1;
2641                 else if (!strncmp(s, "table", len))
2642                         _tree_switches[TR_TABLE] = 1;
2643                 else if (!strncmp(s, "active", len))
2644                         _tree_switches[TR_ACTIVE] = 1;
2645                 else if (!strncmp(s, "open", len))
2646                         _tree_switches[TR_OPENCOUNT] = 1;
2647                 else if (!strncmp(s, "uuid", len))
2648                         _tree_switches[TR_UUID] = 1;
2649                 else if (!strncmp(s, "rw", len))
2650                         _tree_switches[TR_RW] = 1;
2651                 else if (!strncmp(s, "utf", len))
2652                         _tsym = &_tsym_utf;
2653                 else if (!strncmp(s, "vt100", len))
2654                         _tsym = &_tsym_vt100;
2655                 else if (!strncmp(s, "ascii", len))
2656                         _tsym = &_tsym_ascii;
2657                 else if (!strncmp(s, "inverted", len))
2658                         _tree_switches[TR_BOTTOMUP] = 1;
2659                 else if (!strncmp(s, "compact", len))
2660                         _tree_switches[TR_COMPACT] = 1;
2661                 else if (!strncmp(s, "notrunc", len))
2662                         _tree_switches[TR_TRUNCATE] = 0;
2663                 else {
2664                         fprintf(stderr, "Tree options not recognised: %s\n", s);
2665                         return 0;
2666                 }
2667                 if (!*end)
2668                         break;
2669                 s = end;
2670         }
2671
2672         /* Truncation doesn't work well with vt100 drawing char */
2673         if (_tsym != &_tsym_vt100)
2674                 if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
2675                         _termwidth = winsz.ws_col - 3;
2676
2677         return 1;
2678 }
2679
2680 /*
2681  * Returns the full absolute path, or NULL if the path could
2682  * not be resolved.
2683  */
2684 static char *_get_abspath(const char *path)
2685 {
2686         char *_path;
2687
2688 #ifdef HAVE_CANONICALIZE_FILE_NAME
2689         _path = canonicalize_file_name(path);
2690 #else
2691         /* FIXME Provide alternative */
2692 #endif
2693         return _path;
2694 }
2695
2696 static char *parse_loop_device_name(const char *dev, const char *dev_dir)
2697 {
2698         char *buf;
2699         char *device;
2700
2701         if (!(buf = dm_malloc(PATH_MAX)))
2702                 return NULL;
2703
2704         if (dev[0] == '/') {
2705                 if (!(device = _get_abspath(dev)))
2706                         goto error;
2707
2708                 if (strncmp(device, dev_dir, strlen(dev_dir)))
2709                         goto error;
2710
2711                 /* If dev_dir does not end in a slash, ensure that the
2712                    following byte in the device string is "/".  */
2713                 if (dev_dir[strlen(dev_dir) - 1] != '/' &&
2714                     device[strlen(dev_dir)] != '/')
2715                         goto error;
2716
2717                 strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
2718                 dm_free(device);
2719
2720         } else {
2721                 /* check for device number */
2722                 if (!strncmp(dev, "loop", strlen("loop")))
2723                         strncpy(buf, dev, (size_t) PATH_MAX);
2724                 else
2725                         goto error;
2726         }
2727
2728         return buf;
2729
2730 error:
2731         return NULL;
2732 }
2733
2734 /*
2735  *  create a table for a mapped device using the loop target.
2736  */
2737 static int _loop_table(char *table, size_t tlen, char *file,
2738                        char *dev __attribute((unused)), off_t off)
2739 {
2740         struct stat fbuf;
2741         off_t size, sectors;
2742         int fd = -1;
2743 #ifdef HAVE_SYS_STATVFS_H
2744         struct statvfs fsbuf;
2745         off_t blksize;
2746 #endif
2747
2748         if (!_switches[READ_ONLY])
2749                 fd = open(file, O_RDWR);
2750
2751         if (fd < 0) {
2752                 _switches[READ_ONLY]++;
2753                 fd = open(file, O_RDONLY);
2754         }
2755
2756         if (fd < 0)
2757                 goto error;
2758
2759         if (fstat(fd, &fbuf))
2760                 goto error;
2761
2762         size = (fbuf.st_size - off);
2763         sectors = size >> SECTOR_SHIFT;
2764
2765         if (_switches[VERBOSE_ARG])
2766                 fprintf(stderr, "losetup: set loop size to %llukB "
2767                         "(%llu sectors)\n", (long long unsigned) sectors >> 1,
2768                         (long long unsigned) sectors);
2769
2770 #ifdef HAVE_SYS_STATVFS_H
2771         if (fstatvfs(fd, &fsbuf))
2772                 goto error;
2773
2774         /* FIXME Fragment size currently unused */
2775         blksize = fsbuf.f_frsize;
2776 #endif
2777
2778         close(fd);
2779
2780         if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
2781                         (long long unsigned)sectors, file, off) < 0)
2782                 return 0;
2783
2784         if (_switches[VERBOSE_ARG] > 1)
2785                 fprintf(stderr, "Table: %s\n", table);
2786
2787         return 1;
2788
2789 error:
2790         if (fd > -1)
2791                 close(fd);
2792         return 0;
2793 }
2794
2795 static int _process_losetup_switches(const char *base, int *argc, char ***argv,
2796                                      const char *dev_dir)
2797 {
2798         static int ind;
2799         int c;
2800         int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
2801         char *device_name = NULL;
2802         char *loop_file = NULL;
2803         off_t offset = 0;
2804
2805 #ifdef HAVE_GETOPTLONG
2806         static struct option long_options[] = {
2807                 {0, 0, 0, 0}
2808         };
2809 #endif
2810
2811         optarg = 0;
2812         optind = OPTIND_INIT;
2813         while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
2814                                             long_options, NULL)) != -1 ) {
2815                 if (c == ':' || c == '?')
2816                         return 0;
2817                 if (c == 'a')
2818                         show_all++;
2819                 if (c == 'd')
2820                         delete++;
2821                 if (c == 'e')
2822                         encrypt_loop++;
2823                 if (c == 'f')
2824                         find++;
2825                 if (c == 'o')
2826                         offset = atoi(optarg);
2827                 if (c == 'v')
2828                         _switches[VERBOSE_ARG]++;
2829         }
2830
2831         *argv += optind ;
2832         *argc -= optind ;
2833
2834         if (encrypt_loop){
2835                 fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
2836                                 "in this version.\n", base);
2837                 return 0;
2838         }
2839
2840         if (show_all) {
2841                 fprintf(stderr, "%s: Sorry, show all is not yet implemented "
2842                                 "in this version.\n", base);
2843                 return 0;
2844         }
2845
2846         if (find) {
2847                 fprintf(stderr, "%s: Sorry, find is not yet implemented "
2848                                 "in this version.\n", base);
2849                 if (!*argc)
2850                         return 0;
2851         }
2852
2853         if (!*argc) {
2854                 fprintf(stderr, "%s: Please specify loop_device.\n", base);
2855                 _losetup_usage(stderr);
2856                 return 0;
2857         }
2858
2859         if (!(device_name = parse_loop_device_name((*argv)[0], dev_dir))) {
2860                 fprintf(stderr, "%s: Could not parse loop_device %s\n",
2861                         base, (*argv)[0]);
2862                 _losetup_usage(stderr);
2863                 return 0;
2864         }
2865
2866         if (delete) {
2867                 *argc = 2;
2868
2869                 (*argv)[1] = device_name;
2870                 (*argv)[0] = (char *) "remove";
2871
2872                 return 1;
2873         }
2874
2875         if (*argc != 2) {
2876                 fprintf(stderr, "%s: Too few arguments\n", base);
2877                 _losetup_usage(stderr);
2878                 dm_free(device_name);
2879                 return 0;
2880         }
2881
2882         /* FIXME move these to make them available to native dmsetup */
2883         if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
2884                 fprintf(stderr, "%s: Could not parse loop file name %s\n",
2885                         base, (*argv)[1]);
2886                 _losetup_usage(stderr);
2887                 dm_free(device_name);
2888                 return 0;
2889         }
2890
2891         /* FIXME Missing free */
2892         _table = dm_malloc(LOOP_TABLE_SIZE);
2893         if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
2894                 fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
2895                 dm_free(device_name);
2896                 return 0;
2897         }
2898         _switches[TABLE_ARG]++;
2899
2900         (*argv)[0] = (char *) "create";
2901         (*argv)[1] = device_name ;
2902
2903         return 1;
2904 }
2905
2906 static int _process_switches(int *argc, char ***argv, const char *dev_dir)
2907 {
2908         char *base, *namebase, *s;
2909         static int ind;
2910         int c, r;
2911
2912 #ifdef HAVE_GETOPTLONG
2913         static struct option long_options[] = {
2914                 {"readonly", 0, &ind, READ_ONLY},
2915                 {"columns", 0, &ind, COLS_ARG},
2916                 {"exec", 1, &ind, EXEC_ARG},
2917                 {"force", 0, &ind, FORCE_ARG},
2918                 {"gid", 1, &ind, GID_ARG},
2919                 {"inactive", 0, &ind, INACTIVE_ARG},
2920                 {"major", 1, &ind, MAJOR_ARG},
2921                 {"minor", 1, &ind, MINOR_ARG},
2922                 {"mode", 1, &ind, MODE_ARG},
2923                 {"nameprefixes", 0, &ind, NAMEPREFIXES_ARG},
2924                 {"noflush", 0, &ind, NOFLUSH_ARG},
2925                 {"noheadings", 0, &ind, NOHEADINGS_ARG},
2926                 {"nolockfs", 0, &ind, NOLOCKFS_ARG},
2927                 {"noopencount", 0, &ind, NOOPENCOUNT_ARG},
2928                 {"notable", 0, &ind, NOTABLE_ARG},
2929                 {"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
2930                 {"options", 1, &ind, OPTIONS_ARG},
2931                 {"readahead", 1, &ind, READAHEAD_ARG},
2932                 {"rows", 0, &ind, ROWS_ARG},
2933                 {"separator", 1, &ind, SEPARATOR_ARG},
2934                 {"showkeys", 0, &ind, SHOWKEYS_ARG},
2935                 {"sort", 1, &ind, SORT_ARG},
2936                 {"table", 1, &ind, TABLE_ARG},
2937                 {"target", 1, &ind, TARGET_ARG},
2938                 {"tree", 0, &ind, TREE_ARG},
2939                 {"uid", 1, &ind, UID_ARG},
2940                 {"uuid", 1, &ind, UUID_ARG},
2941                 {"unbuffered", 0, &ind, UNBUFFERED_ARG},
2942                 {"unquoted", 0, &ind, UNQUOTED_ARG},
2943                 {"verbose", 1, &ind, VERBOSE_ARG},
2944                 {"version", 0, &ind, VERSION_ARG},
2945                 {"yes", 0, &ind, YES_ARG},
2946                 {0, 0, 0, 0}
2947         };
2948 #else
2949         struct option long_options;
2950 #endif
2951
2952         /*
2953          * Zero all the index counts.
2954          */
2955         memset(&_switches, 0, sizeof(_switches));
2956         memset(&_int_args, 0, sizeof(_int_args));
2957         _read_ahead_flags = 0;
2958
2959         namebase = strdup((*argv)[0]);
2960         base = basename(namebase);
2961
2962         if (!strcmp(base, "devmap_name")) {
2963                 free(namebase);
2964                 _switches[COLS_ARG]++;
2965                 _switches[NOHEADINGS_ARG]++;
2966                 _switches[OPTIONS_ARG]++;
2967                 _switches[MAJOR_ARG]++;
2968                 _switches[MINOR_ARG]++;
2969                 _string_args[OPTIONS_ARG] = (char *) "name";
2970
2971                 if (*argc == 3) {
2972                         _int_args[MAJOR_ARG] = atoi((*argv)[1]);
2973                         _int_args[MINOR_ARG] = atoi((*argv)[2]);
2974                         *argc -= 2;
2975                         *argv += 2;
2976                 } else if ((*argc == 2) &&
2977                            (2 == sscanf((*argv)[1], "%i:%i",
2978                                         &_int_args[MAJOR_ARG],
2979                                         &_int_args[MINOR_ARG]))) {
2980                         *argc -= 1;
2981                         *argv += 1;
2982                 } else {
2983                         fprintf(stderr, "Usage: devmap_name <major> <minor>\n");
2984                         return 0;
2985                 }
2986
2987                 (*argv)[0] = (char *) "info";
2988                 return 1;
2989         }
2990
2991         if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
2992                 r = _process_losetup_switches(base, argc, argv, dev_dir);
2993                 free(namebase);
2994                 return r;
2995         }
2996
2997         free(namebase);
2998
2999         optarg = 0;
3000         optind = OPTIND_INIT;
3001         while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:j:m:M:no:O:ru:U:vy",
3002                                             long_options, NULL)) != -1) {
3003                 if (c == ':' || c == '?')
3004                         return 0;
3005                 if (c == 'c' || c == 'C' || ind == COLS_ARG)
3006                         _switches[COLS_ARG]++;
3007                 if (c == 'f' || ind == FORCE_ARG)
3008                         _switches[FORCE_ARG]++;
3009                 if (c == 'r' || ind == READ_ONLY)
3010                         _switches[READ_ONLY]++;
3011                 if (c == 'j' || ind == MAJOR_ARG) {
3012                         _switches[MAJOR_ARG]++;
3013                         _int_args[MAJOR_ARG] = atoi(optarg);
3014                 }
3015                 if (c == 'm' || ind == MINOR_ARG) {
3016                         _switches[MINOR_ARG]++;
3017                         _int_args[MINOR_ARG] = atoi(optarg);
3018                 }
3019                 if (c == 'n' || ind == NOTABLE_ARG)
3020                         _switches[NOTABLE_ARG]++;
3021                 if (c == 'o' || ind == OPTIONS_ARG) {
3022                         _switches[OPTIONS_ARG]++;
3023                         _string_args[OPTIONS_ARG] = optarg;
3024                 }
3025                 if (ind == SEPARATOR_ARG) {
3026                         _switches[SEPARATOR_ARG]++;
3027                         _string_args[SEPARATOR_ARG] = optarg;
3028                 }
3029                 if (c == 'O' || ind == SORT_ARG) {
3030                         _switches[SORT_ARG]++;
3031                         _string_args[SORT_ARG] = optarg;
3032                 }
3033                 if (c == 'v' || ind == VERBOSE_ARG)
3034                         _switches[VERBOSE_ARG]++;
3035                 if (c == 'u' || ind == UUID_ARG) {
3036                         _switches[UUID_ARG]++;
3037                         _uuid = optarg;
3038                 }
3039                 if (c == 'y' || ind == YES_ARG)
3040                         _switches[YES_ARG]++;
3041                 if (ind == NOUDEVSYNC_ARG)
3042                         _switches[NOUDEVSYNC_ARG]++;
3043                 if (c == 'G' || ind == GID_ARG) {
3044                         _switches[GID_ARG]++;
3045                         _int_args[GID_ARG] = atoi(optarg);
3046                 }
3047                 if (c == 'U' || ind == UID_ARG) {
3048                         _switches[UID_ARG]++;
3049                         _int_args[UID_ARG] = atoi(optarg);
3050                 }
3051                 if (c == 'M' || ind == MODE_ARG) {
3052                         _switches[MODE_ARG]++;
3053                         /* FIXME Accept modes as per chmod */
3054                         _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
3055                 }
3056                 if ((ind == EXEC_ARG)) {
3057                         _switches[EXEC_ARG]++;
3058                         _command = optarg;
3059                 }
3060                 if ((ind == TARGET_ARG)) {
3061                         _switches[TARGET_ARG]++;
3062                         _target = optarg;
3063                 }
3064                 if ((ind == INACTIVE_ARG))
3065                         _switches[INACTIVE_ARG]++;
3066                 if ((ind == NAMEPREFIXES_ARG))
3067                         _switches[NAMEPREFIXES_ARG]++;
3068                 if ((ind == NOFLUSH_ARG))
3069                         _switches[NOFLUSH_ARG]++;
3070                 if ((ind == NOHEADINGS_ARG))
3071                         _switches[NOHEADINGS_ARG]++;
3072                 if ((ind == NOLOCKFS_ARG))
3073                         _switches[NOLOCKFS_ARG]++;
3074                 if ((ind == NOOPENCOUNT_ARG))
3075                         _switches[NOOPENCOUNT_ARG]++;
3076                 if ((ind == READAHEAD_ARG)) {
3077                         _switches[READAHEAD_ARG]++;
3078                         if (!strcasecmp(optarg, "auto"))
3079                                 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
3080                         else if (!strcasecmp(optarg, "none"))
3081                                 _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
3082                         else {
3083                                 for (s = optarg; isspace(*s); s++)
3084                                         ;
3085                                 if (*s == '+')
3086                                         _read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
3087                                 _int_args[READAHEAD_ARG] = atoi(optarg);
3088                                 if (_int_args[READAHEAD_ARG] < -1) {
3089                                         log_error("Negative read ahead value "
3090                                                   "(%d) is not understood.",
3091                                                   _int_args[READAHEAD_ARG]);
3092                                         return 0;
3093                                 }
3094                         }
3095                 }
3096                 if ((ind == ROWS_ARG))
3097                         _switches[ROWS_ARG]++;
3098                 if ((ind == SHOWKEYS_ARG))
3099                         _switches[SHOWKEYS_ARG]++;
3100                 if ((ind == TABLE_ARG)) {
3101                         _switches[TABLE_ARG]++;
3102                         _table = optarg;
3103                 }
3104                 if ((ind == TREE_ARG))
3105                         _switches[TREE_ARG]++;
3106                 if ((ind == UNQUOTED_ARG))
3107                         _switches[UNQUOTED_ARG]++;
3108                 if ((ind == VERSION_ARG))
3109                         _switches[VERSION_ARG]++;
3110         }
3111
3112         if (_switches[VERBOSE_ARG] > 1)
3113                 dm_log_init_verbose(_switches[VERBOSE_ARG] - 1);
3114
3115         if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) ||
3116             (!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) {
3117                 fprintf(stderr, "Please specify both major number and "
3118                                 "minor number.\n");
3119                 return 0;
3120         }
3121
3122         if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
3123                 return 0;
3124
3125         if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
3126                 fprintf(stderr, "--table and --notable are incompatible.\n");
3127                 return 0;
3128         }
3129
3130         *argv += optind;
3131         *argc -= optind;
3132         return 1;
3133 }
3134
3135 int main(int argc, char **argv)
3136 {
3137         struct command *c;
3138         int r = 1;
3139         const char *dev_dir;
3140
3141         (void) setlocale(LC_ALL, "");
3142
3143         dev_dir = getenv ("DM_DEV_DIR");
3144         if (dev_dir && *dev_dir) {
3145                 if (!dm_set_dev_dir(dev_dir)) {
3146                         fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n");
3147                         goto out;
3148                 }
3149         } else
3150                 dev_dir = DEFAULT_DM_DEV_DIR;
3151
3152         if (!_process_switches(&argc, &argv, dev_dir)) {
3153                 fprintf(stderr, "Couldn't process command line.\n");
3154                 goto out;
3155         }
3156
3157         if (_switches[VERSION_ARG]) {
3158                 c = _find_command("version");
3159                 goto doit;
3160         }
3161
3162         if (argc == 0) {
3163                 _usage(stderr);
3164                 goto out;
3165         }
3166
3167         if (!(c = _find_command(argv[0]))) {
3168                 fprintf(stderr, "Unknown command\n");
3169                 _usage(stderr);
3170                 goto out;
3171         }
3172
3173         if (argc < c->min_args + 1 ||
3174             (c->max_args >= 0 && argc > c->max_args + 1)) {
3175                 fprintf(stderr, "Incorrect number of arguments\n");
3176                 _usage(stderr);
3177                 goto out;
3178         }
3179
3180         if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname"))
3181                 _switches[COLS_ARG]++;
3182
3183         if (_switches[COLS_ARG] && !_report_init(c))
3184                 goto out;
3185
3186         if (_switches[NOUDEVSYNC_ARG])
3187                 dm_udev_set_sync_support(0);
3188
3189       doit:
3190         if (!c->fn(argc, argv, NULL)) {
3191                 fprintf(stderr, "Command failed\n");
3192                 goto out;
3193         }
3194
3195         r = 0;
3196
3197 out:
3198         if (_report) {
3199                 dm_report_output(_report);
3200                 dm_report_free(_report);
3201         }
3202
3203         if (_dtree)
3204                 dm_tree_free(_dtree);
3205
3206         return r;
3207 }