xref: /dragonfly/contrib/lvm2/dist/tools/dmsetup.c (revision 300c4de4a1b8efddbb8c825a33cc38d33c91bd81)
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 
_parse_line(struct dm_task * dmt,char * buffer,const char * file,int line)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 
_parse_file(struct dm_task * dmt,const char * file)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 
_get_deps_task(int major,int minor)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 
_extract_uuid_prefix(const char * uuid,const int separator)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 
_get_split_name(const char * uuid,const char * name,int separator)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 
_destroy_split_name(struct dm_split_name * split_name)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 
_display_info_cols(struct dm_task * dmt,struct dm_info * info)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 
_display_info_long(struct dm_task * dmt,struct dm_info * info)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 
_display_info(struct dm_task * dmt)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 
_set_task_device(struct dm_task * dmt,const char * name,int optional)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 
_load(int argc,char ** argv,void * data __attribute ((unused)))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 
_create(int argc,char ** argv,void * data __attribute ((unused)))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 
_rename(int argc,char ** argv,void * data __attribute ((unused)))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 
_message(int argc,char ** argv,void * data __attribute ((unused)))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 
_setgeometry(int argc,char ** argv,void * data __attribute ((unused)))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 
_splitname(int argc,char ** argv,void * data __attribute ((unused)))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 
_get_cookie_value(char * str_value)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 
_udevflags(int args,char ** argv,void * data __attribute ((unused)))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 
_udevcomplete(int argc,char ** argv,void * data __attribute ((unused)))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 
_udevcomplete_all(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_udevcookies(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_yes_no_prompt(const char * prompt,...)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 
_udevcomplete_all(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_udevcookies(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_version(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_simple(int task,const char * name,uint32_t event_nr,int display)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 
_suspend(int argc,char ** argv,void * data __attribute ((unused)))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 
_resume(int argc,char ** argv,void * data __attribute ((unused)))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 
_clear(int argc,char ** argv,void * data __attribute ((unused)))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 
_wait(int argc,char ** argv,void * data __attribute ((unused)))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 
_process_all(int argc,char ** argv,int silent,int (* fn)(int argc,char ** argv,void * data))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 
_get_device_size(const char * name)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 
_error_device(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data)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 
_remove(int argc,char ** argv,void * data __attribute ((unused)))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 
_count_devices(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_remove_all(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))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 
_display_dev(struct dm_task * dmt,const char * name)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 
_mknodes(int argc,char ** argv,void * data __attribute ((unused)))1276 static int _mknodes(int argc, char **argv, void *data __attribute((unused)))
1277 {
1278           return dm_mknodes(argc > 1 ? argv[1] : NULL);
1279 }
1280 
_exec_command(const char * name)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 
_status(int argc,char ** argv,void * data)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                     params = NULL;
1396                     next = dm_get_next_target(dmt, next, &start, &length,
1397                                                     &target_type, &params);
1398                     /* Skip if target type doesn't match */
1399                     if (_switches[TARGET_ARG] &&
1400                         (!target_type || strcmp(target_type, _target)))
1401                               continue;
1402                     if (ls_only) {
1403                               if (!_switches[EXEC_ARG] || !_command ||
1404                                   _switches[VERBOSE_ARG])
1405                                         _display_dev(dmt, name);
1406                               next = NULL;
1407                     } else if (!_switches[EXEC_ARG] || !_command ||
1408                                  _switches[VERBOSE_ARG]) {
1409                               if (!matched && _switches[VERBOSE_ARG])
1410                                         _display_info(dmt);
1411                               if (data && !_switches[VERBOSE_ARG])
1412                                         printf("%s: ", name);
1413                               if (target_type) {
1414                                         /* Suppress encryption key */
1415                                         if (!_switches[SHOWKEYS_ARG] &&
1416                                             cmd == DM_DEVICE_TABLE &&
1417                                             !strcmp(target_type, "crypt")) {
1418                                                   c = params;
1419                                                   while (*c && *c != ' ')
1420                                                             c++;
1421                                                   if (*c)
1422                                                             c++;
1423                                                   while (*c && *c != ' ')
1424                                                             *c++ = '0';
1425                                         }
1426                                         if (params && strlen(params) > 0) {
1427                                                   printf("%" PRIu64 " %" PRIu64 " %s %s",
1428                                                          start, length, target_type, params);
1429                                         } else {
1430                                                   /* Not implemented by targets */
1431                                                   printf("%" PRIu64 " %" PRIu64 " %s",
1432                                                          start, length, target_type);
1433                                         }
1434                               }
1435                               printf("\n");
1436                     }
1437                     matched = 1;
1438           } while (next);
1439 
1440           if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
1441                     printf("\n");
1442 
1443           if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
1444                     goto out;
1445 
1446           r = 1;
1447 
1448       out:
1449           dm_task_destroy(dmt);
1450           return r;
1451 }
1452 
1453 /* Show target names and their version numbers */
_targets(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))1454 static int _targets(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused)))
1455 {
1456           int r = 0;
1457           struct dm_task *dmt;
1458           struct dm_versions *target;
1459           struct dm_versions *last_target;
1460 
1461           if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
1462                     return 0;
1463 
1464           if (!dm_task_run(dmt))
1465                     goto out;
1466 
1467           target = dm_task_get_versions(dmt);
1468 
1469           /* Fetch targets and print 'em */
1470           do {
1471                     last_target = target;
1472 
1473                     printf("%-16s v%d.%d.%d\n", target->name, target->version[0],
1474                            target->version[1], target->version[2]);
1475 
1476                     target = (void *) target + target->next;
1477           } while (last_target != target);
1478 
1479           r = 1;
1480 
1481       out:
1482           dm_task_destroy(dmt);
1483           return r;
1484 }
1485 
_info(int argc,char ** argv,void * data)1486 static int _info(int argc, char **argv, void *data)
1487 {
1488           int r = 0;
1489 
1490           struct dm_task *dmt;
1491           struct dm_names *names = (struct dm_names *) data;
1492           char *name = NULL;
1493 
1494           if (data)
1495                     name = names->name;
1496           else {
1497                     if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1498                               return _process_all(argc, argv, 0, _info);
1499                     if (argc == 2)
1500                               name = argv[1];
1501           }
1502 
1503           if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
1504                     return 0;
1505 
1506           if (!_set_task_device(dmt, name, 0))
1507                     goto out;
1508 
1509           if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1510                     goto out;
1511 
1512           if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1513                     goto out;
1514 
1515           if (!dm_task_run(dmt))
1516                     goto out;
1517 
1518           r = _display_info(dmt);
1519 
1520       out:
1521           dm_task_destroy(dmt);
1522           return r;
1523 }
1524 
_deps(int argc,char ** argv,void * data)1525 static int _deps(int argc, char **argv, void *data)
1526 {
1527           int r = 0;
1528           uint32_t i;
1529           struct dm_deps *deps;
1530           struct dm_task *dmt;
1531           struct dm_info info;
1532           struct dm_names *names = (struct dm_names *) data;
1533           char *name = NULL;
1534 
1535           if (data)
1536                     name = names->name;
1537           else {
1538                     if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
1539                               return _process_all(argc, argv, 0, _deps);
1540                     if (argc == 2)
1541                               name = argv[1];
1542           }
1543 
1544           if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
1545                     return 0;
1546 
1547           if (!_set_task_device(dmt, name, 0))
1548                     goto out;
1549 
1550           if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
1551                     goto out;
1552 
1553           if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
1554                     goto out;
1555 
1556           if (!dm_task_run(dmt))
1557                     goto out;
1558 
1559           if (!dm_task_get_info(dmt, &info))
1560                     goto out;
1561 
1562           if (!(deps = dm_task_get_deps(dmt)))
1563                     goto out;
1564 
1565           if (!info.exists) {
1566                     printf("Device does not exist.\n");
1567                     r = 1;
1568                     goto out;
1569           }
1570 
1571           if (_switches[VERBOSE_ARG])
1572                     _display_info(dmt);
1573 
1574           if (data && !_switches[VERBOSE_ARG])
1575                     printf("%s: ", name);
1576           printf("%d dependencies\t:", deps->count);
1577 
1578           for (i = 0; i < deps->count; i++)
1579                     printf(" (%d, %d)",
1580                            (int) MAJOR(deps->device[i]),
1581                            (int) MINOR(deps->device[i]));
1582           printf("\n");
1583 
1584           if (data && _switches[VERBOSE_ARG])
1585                     printf("\n");
1586 
1587           r = 1;
1588 
1589       out:
1590           dm_task_destroy(dmt);
1591           return r;
1592 }
1593 
_display_name(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data)1594 static int _display_name(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
1595 {
1596           struct dm_names *names = (struct dm_names *) data;
1597 
1598           printf("%s\t(%d, %d)\n", names->name,
1599                  (int) MAJOR(names->dev), (int) MINOR(names->dev));
1600 
1601           return 1;
1602 }
1603 
1604 /*
1605  * Tree drawing code
1606  */
1607 
1608 enum {
1609           TR_DEVICE=0,        /* display device major:minor number */
1610           TR_TABLE,
1611           TR_STATUS,
1612           TR_ACTIVE,
1613           TR_RW,
1614           TR_OPENCOUNT,
1615           TR_UUID,
1616           TR_COMPACT,
1617           TR_TRUNCATE,
1618           TR_BOTTOMUP,
1619           NUM_TREEMODE,
1620 };
1621 
1622 static int _tree_switches[NUM_TREEMODE];
1623 
1624 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1625                                    _tree_switches[TR_RW] || \
1626                                    _tree_switches[TR_OPENCOUNT] || \
1627                                    _tree_switches[TR_UUID] )
1628 
1629 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1630                                  _tree_switches[TR_STATUS] )
1631 
1632 /* Compact - fewer newlines */
1633 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1634                                 !TR_PRINT_ATTRIBUTE && \
1635                                 !TR_PRINT_TARGETS)
1636 
1637 /* FIXME Get rid of this */
1638 #define MAX_DEPTH 100
1639 
1640 /* Drawing character definition from pstree */
1641 /* [pstree comment] UTF-8 defines by Johan Myreen, updated by Ben Winslow */
1642 #define UTF_V       "\342\224\202"      /* U+2502, Vertical line drawing char */
1643 #define UTF_VR      "\342\224\234"      /* U+251C, Vertical and right */
1644 #define UTF_H       "\342\224\200"      /* U+2500, Horizontal */
1645 #define UTF_UR      "\342\224\224"      /* U+2514, Up and right */
1646 #define UTF_HD      "\342\224\254"      /* U+252C, Horizontal and down */
1647 
1648 #define VT_BEG      "\033(0\017"        /* use graphic chars */
1649 #define VT_END      "\033(B"  /* back to normal char set */
1650 #define VT_V        "x"                 /* see UTF definitions above */
1651 #define VT_VR       "t"
1652 #define VT_H        "q"
1653 #define VT_UR       "m"
1654 #define VT_HD       "w"
1655 
1656 static struct {
1657           const char *empty_2;          /*    */
1658           const char *branch_2;         /* |- */
1659           const char *vert_2; /* |  */
1660           const char *last_2; /* `- */
1661           const char *single_3;         /* --- */
1662           const char *first_3;          /* -+- */
1663 }
1664 _tsym_ascii = {
1665           "  ",
1666           "|-",
1667           "| ",
1668           "`-",
1669           "---",
1670           "-+-"
1671 },
1672 _tsym_utf = {
1673           "  ",
1674           UTF_VR UTF_H,
1675           UTF_V " ",
1676           UTF_UR UTF_H,
1677           UTF_H UTF_H UTF_H,
1678           UTF_H UTF_HD UTF_H
1679 },
1680 _tsym_vt100 = {
1681           "  ",
1682           VT_BEG VT_VR VT_H VT_END,
1683           VT_BEG VT_V VT_END " ",
1684           VT_BEG VT_UR VT_H VT_END,
1685           VT_BEG VT_H VT_H VT_H VT_END,
1686           VT_BEG VT_H VT_HD VT_H VT_END
1687 },
1688 *_tsym = &_tsym_ascii;
1689 
1690 /*
1691  * Tree drawing functions.
1692  */
1693 /* FIXME Get rid of these statics - use dynamic struct */
1694 /* FIXME Explain what these vars are for */
1695 static int _tree_width[MAX_DEPTH], _tree_more[MAX_DEPTH];
1696 static int _termwidth = 80;   /* Maximum output width */
1697 static int _cur_x = 1;                  /* Current horizontal output position */
1698 static char _last_char = 0;
1699 
_out_char(const unsigned c)1700 static void _out_char(const unsigned c)
1701 {
1702           /* Only first UTF-8 char counts */
1703           _cur_x += ((c & 0xc0) != 0x80);
1704 
1705           if (!_tree_switches[TR_TRUNCATE]) {
1706                     putchar((int) c);
1707                     return;
1708           }
1709 
1710           /* Truncation? */
1711           if (_cur_x <= _termwidth)
1712                     putchar((int) c);
1713 
1714           if (_cur_x == _termwidth + 1 && ((c & 0xc0) != 0x80)) {
1715                     if (_last_char || (c & 0x80)) {
1716                               putchar('.');
1717                               putchar('.');
1718                               putchar('.');
1719                     } else {
1720                               _last_char = c;
1721                               _cur_x--;
1722                     }
1723           }
1724 }
1725 
_out_string(const char * str)1726 static void _out_string(const char *str)
1727 {
1728           while (*str)
1729                     _out_char((unsigned char) *str++);
1730 }
1731 
1732 /* non-negative integers only */
_out_int(unsigned num)1733 static unsigned _out_int(unsigned num)
1734 {
1735           unsigned digits = 0;
1736           unsigned divi;
1737 
1738           if (!num) {
1739                     _out_char('0');
1740                     return 1;
1741           }
1742 
1743           /* non zero case */
1744           for (divi = 1; num / divi; divi *= 10)
1745                     digits++;
1746 
1747           for (divi /= 10; divi; divi /= 10)
1748                     _out_char('0' + (num / divi) % 10);
1749 
1750           return digits;
1751 }
1752 
_out_newline(void)1753 static void _out_newline(void)
1754 {
1755           if (_last_char && _cur_x == _termwidth)
1756                     putchar(_last_char);
1757           _last_char = 0;
1758           putchar('\n');
1759           _cur_x = 1;
1760 }
1761 
_out_prefix(unsigned depth)1762 static void _out_prefix(unsigned depth)
1763 {
1764           unsigned x, d;
1765 
1766           for (d = 0; d < depth; d++) {
1767                     for (x = _tree_width[d] + 1; x > 0; x--)
1768                               _out_char(' ');
1769 
1770                     _out_string(d == depth - 1 ?
1771                                         !_tree_more[depth] ? _tsym->last_2 : _tsym->branch_2
1772                                  : _tree_more[d + 1] ?
1773                                         _tsym->vert_2 : _tsym->empty_2);
1774           }
1775 }
1776 
1777 /*
1778  * Display tree
1779  */
_display_tree_attributes(struct dm_tree_node * node)1780 static void _display_tree_attributes(struct dm_tree_node *node)
1781 {
1782           int attr = 0;
1783           const char *uuid;
1784           const struct dm_info *info;
1785 
1786           uuid = dm_tree_node_get_uuid(node);
1787           info = dm_tree_node_get_info(node);
1788 
1789           if (!info->exists)
1790                     return;
1791 
1792           if (_tree_switches[TR_ACTIVE]) {
1793                     _out_string(attr++ ? ", " : " [");
1794                     _out_string(info->suspended ? "SUSPENDED" : "ACTIVE");
1795           }
1796 
1797           if (_tree_switches[TR_RW]) {
1798                     _out_string(attr++ ? ", " : " [");
1799                     _out_string(info->read_only ? "RO" : "RW");
1800           }
1801 
1802           if (_tree_switches[TR_OPENCOUNT]) {
1803                     _out_string(attr++ ? ", " : " [");
1804                     (void) _out_int((unsigned) info->open_count);
1805           }
1806 
1807           if (_tree_switches[TR_UUID]) {
1808                     _out_string(attr++ ? ", " : " [");
1809                     _out_string(uuid && *uuid ? uuid : "");
1810           }
1811 
1812           if (attr)
1813                     _out_char(']');
1814 }
1815 
_display_tree_node(struct dm_tree_node * node,unsigned depth,unsigned first_child __attribute ((unused)),unsigned last_child,unsigned has_children)1816 static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
1817                                      unsigned first_child __attribute((unused)),
1818                                      unsigned last_child, unsigned has_children)
1819 {
1820           int offset;
1821           const char *name;
1822           const struct dm_info *info;
1823           int first_on_line = 0;
1824 
1825           /* Sub-tree for targets has 2 more depth */
1826           if (depth + 2 > MAX_DEPTH)
1827                     return;
1828 
1829           name = dm_tree_node_get_name(node);
1830 
1831           if ((!name || !*name) && !_tree_switches[TR_DEVICE])
1832                     return;
1833 
1834           /* Indicate whether there are more nodes at this depth */
1835           _tree_more[depth] = !last_child;
1836           _tree_width[depth] = 0;
1837 
1838           if (_cur_x == 1)
1839                     first_on_line = 1;
1840 
1841           if (!TR_PRINT_COMPACT || first_on_line)
1842                     _out_prefix(depth);
1843 
1844           /* Remember the starting point for compact */
1845           offset = _cur_x;
1846 
1847           if (TR_PRINT_COMPACT && !first_on_line)
1848                     _out_string(_tree_more[depth] ? _tsym->first_3 : _tsym->single_3);
1849 
1850           /* display node */
1851           if (name)
1852                     _out_string(name);
1853 
1854           info = dm_tree_node_get_info(node);
1855 
1856           if (_tree_switches[TR_DEVICE]) {
1857                     _out_string(name ? " (" : "(");
1858                     (void) _out_int(info->major);
1859                     _out_char(':');
1860                     (void) _out_int(info->minor);
1861                     _out_char(')');
1862           }
1863 
1864           /* display additional info */
1865           if (TR_PRINT_ATTRIBUTE)
1866                     _display_tree_attributes(node);
1867 
1868           if (TR_PRINT_COMPACT)
1869                     _tree_width[depth] = _cur_x - offset;
1870 
1871           if (!TR_PRINT_COMPACT || !has_children)
1872                     _out_newline();
1873 
1874           if (TR_PRINT_TARGETS) {
1875                     _tree_more[depth + 1] = has_children;
1876                     // FIXME _display_tree_targets(name, depth + 2);
1877           }
1878 }
1879 
1880 /*
1881  * Walk the dependency tree
1882  */
_display_tree_walk_children(struct dm_tree_node * node,unsigned depth)1883 static void _display_tree_walk_children(struct dm_tree_node *node,
1884                                                   unsigned depth)
1885 {
1886           struct dm_tree_node *child, *next_child;
1887           void *handle = NULL;
1888           uint32_t inverted = _tree_switches[TR_BOTTOMUP];
1889           unsigned first_child = 1;
1890           unsigned has_children;
1891 
1892           next_child = dm_tree_next_child(&handle, node, inverted);
1893 
1894           while ((child = next_child)) {
1895                     next_child = dm_tree_next_child(&handle, node, inverted);
1896                     has_children =
1897                         dm_tree_node_num_children(child, inverted) ? 1 : 0;
1898 
1899                     _display_tree_node(child, depth, first_child,
1900                                            next_child ? 0U : 1U, has_children);
1901 
1902                     if (has_children)
1903                               _display_tree_walk_children(child, depth + 1);
1904 
1905                     first_child = 0;
1906           }
1907 }
1908 
_add_dep(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data)1909 static int _add_dep(int argc __attribute((unused)), char **argv __attribute((unused)), void *data)
1910 {
1911           struct dm_names *names = (struct dm_names *) data;
1912 
1913           if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
1914                     return 0;
1915 
1916           return 1;
1917 }
1918 
1919 /*
1920  * Create and walk dependency tree
1921  */
_build_whole_deptree(void)1922 static int _build_whole_deptree(void)
1923 {
1924           if (_dtree)
1925                     return 1;
1926 
1927           if (!(_dtree = dm_tree_create()))
1928                     return 0;
1929 
1930           if (!_process_all(0, NULL, 0, _add_dep))
1931                     return 0;
1932 
1933           return 1;
1934 }
1935 
_display_tree(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))1936 static int _display_tree(int argc __attribute((unused)),
1937                                char **argv __attribute((unused)),
1938                                void *data __attribute((unused)))
1939 {
1940           if (!_build_whole_deptree())
1941                     return 0;
1942 
1943           _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
1944 
1945           return 1;
1946 }
1947 
1948 /*
1949  * Report device information
1950  */
1951 
1952 /* dm specific display functions */
1953 
_int32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1954 static int _int32_disp(struct dm_report *rh,
1955                            struct dm_pool *mem __attribute((unused)),
1956                            struct dm_report_field *field, const void *data,
1957                            void *private __attribute((unused)))
1958 {
1959           const int32_t value = *(const int32_t *)data;
1960 
1961           return dm_report_field_int32(rh, field, &value);
1962 }
1963 
_uint32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1964 static int _uint32_disp(struct dm_report *rh,
1965                               struct dm_pool *mem __attribute((unused)),
1966                               struct dm_report_field *field, const void *data,
1967                               void *private __attribute((unused)))
1968 {
1969           const uint32_t value = *(const int32_t *)data;
1970 
1971           return dm_report_field_uint32(rh, field, &value);
1972 }
1973 
_dm_name_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1974 static int _dm_name_disp(struct dm_report *rh,
1975                                struct dm_pool *mem __attribute((unused)),
1976                                struct dm_report_field *field, const void *data,
1977                                void *private __attribute((unused)))
1978 {
1979           const char *name = dm_task_get_name((const struct dm_task *) data);
1980 
1981           return dm_report_field_string(rh, field, &name);
1982 }
1983 
_dm_uuid_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1984 static int _dm_uuid_disp(struct dm_report *rh,
1985                                struct dm_pool *mem __attribute((unused)),
1986                                struct dm_report_field *field,
1987                                const void *data, void *private __attribute((unused)))
1988 {
1989           const char *uuid = dm_task_get_uuid((const struct dm_task *) data);
1990 
1991           if (!uuid || !*uuid)
1992                     uuid = "";
1993 
1994           return dm_report_field_string(rh, field, &uuid);
1995 }
1996 
_dm_read_ahead_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1997 static int _dm_read_ahead_disp(struct dm_report *rh,
1998                                      struct dm_pool *mem __attribute((unused)),
1999                                      struct dm_report_field *field, const void *data,
2000                                      void *private __attribute((unused)))
2001 {
2002           uint32_t value;
2003 
2004           if (!dm_task_get_read_ahead((const struct dm_task *) data, &value))
2005                     value = 0;
2006 
2007           return dm_report_field_uint32(rh, field, &value);
2008 }
2009 
_dm_info_status_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2010 static int _dm_info_status_disp(struct dm_report *rh,
2011                                         struct dm_pool *mem __attribute((unused)),
2012                                         struct dm_report_field *field, const void *data,
2013                                         void *private __attribute((unused)))
2014 {
2015           char buf[5];
2016           const char *s = buf;
2017           const struct dm_info *info = data;
2018 
2019           buf[0] = info->live_table ? 'L' : '-';
2020           buf[1] = info->inactive_table ? 'I' : '-';
2021           buf[2] = info->suspended ? 's' : '-';
2022           buf[3] = info->read_only ? 'r' : 'w';
2023           buf[4] = '\0';
2024 
2025           return dm_report_field_string(rh, field, &s);
2026 }
2027 
_dm_info_table_loaded_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2028 static int _dm_info_table_loaded_disp(struct dm_report *rh,
2029                                               struct dm_pool *mem __attribute((unused)),
2030                                               struct dm_report_field *field,
2031                                               const void *data,
2032                                               void *private __attribute((unused)))
2033 {
2034           const struct dm_info *info = data;
2035 
2036           if (info->live_table) {
2037                     if (info->inactive_table)
2038                               dm_report_field_set_value(field, "Both", NULL);
2039                     else
2040                               dm_report_field_set_value(field, "Live", NULL);
2041                     return 1;
2042           }
2043 
2044           if (info->inactive_table)
2045                     dm_report_field_set_value(field, "Inactive", NULL);
2046           else
2047                     dm_report_field_set_value(field, "None", NULL);
2048 
2049           return 1;
2050 }
2051 
_dm_info_suspended_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2052 static int _dm_info_suspended_disp(struct dm_report *rh,
2053                                            struct dm_pool *mem __attribute((unused)),
2054                                            struct dm_report_field *field,
2055                                            const void *data,
2056                                            void *private __attribute((unused)))
2057 {
2058           const struct dm_info *info = data;
2059 
2060           if (info->suspended)
2061                     dm_report_field_set_value(field, "Suspended", NULL);
2062           else
2063                     dm_report_field_set_value(field, "Active", NULL);
2064 
2065           return 1;
2066 }
2067 
_dm_info_read_only_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2068 static int _dm_info_read_only_disp(struct dm_report *rh,
2069                                            struct dm_pool *mem __attribute((unused)),
2070                                            struct dm_report_field *field,
2071                                            const void *data,
2072                                            void *private __attribute((unused)))
2073 {
2074           const struct dm_info *info = data;
2075 
2076           if (info->read_only)
2077                     dm_report_field_set_value(field, "Read-only", NULL);
2078           else
2079                     dm_report_field_set_value(field, "Writeable", NULL);
2080 
2081           return 1;
2082 }
2083 
2084 
_dm_info_devno_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)2085 static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
2086                                      struct dm_report_field *field, const void *data,
2087                                      void *private)
2088 {
2089           char buf[DM_MAX_TYPE_NAME], *repstr;
2090           struct dm_info *info = (struct dm_info *) data;
2091 
2092           if (!dm_pool_begin_object(mem, 8)) {
2093                     log_error("dm_pool_begin_object failed");
2094                     return 0;
2095           }
2096 
2097           if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2098                               info->major, info->minor) < 0) {
2099                     log_error("dm_pool_alloc failed");
2100                     goto out_abandon;
2101           }
2102 
2103           if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
2104                     log_error("dm_pool_grow_object failed");
2105                     goto out_abandon;
2106           }
2107 
2108           repstr = dm_pool_end_object(mem);
2109           dm_report_field_set_value(field, repstr, repstr);
2110           return 1;
2111 
2112       out_abandon:
2113           dm_pool_abandon_object(mem);
2114           return 0;
2115 }
2116 
_dm_tree_names(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private,unsigned inverted)2117 static int _dm_tree_names(struct dm_report *rh, struct dm_pool *mem,
2118                                 struct dm_report_field *field, const void *data,
2119                                 void *private, unsigned inverted)
2120 {
2121           struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
2122           void *t = NULL;
2123           const char *name;
2124           int first_node = 1;
2125           char *repstr;
2126 
2127           if (!dm_pool_begin_object(mem, 16)) {
2128                     log_error("dm_pool_begin_object failed");
2129                     return 0;
2130           }
2131 
2132           while ((parent = dm_tree_next_child(&t, node, inverted))) {
2133                     name = dm_tree_node_get_name(parent);
2134                     if (!name || !*name)
2135                               continue;
2136                     if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2137                               log_error("dm_pool_grow_object failed");
2138                               goto out_abandon;
2139                     }
2140                     if (!dm_pool_grow_object(mem, name, 0)) {
2141                               log_error("dm_pool_grow_object failed");
2142                               goto out_abandon;
2143                     }
2144                     if (first_node)
2145                               first_node = 0;
2146           }
2147 
2148           if (!dm_pool_grow_object(mem, "\0", 1)) {
2149                     log_error("dm_pool_grow_object failed");
2150                     goto out_abandon;
2151           }
2152 
2153           repstr = dm_pool_end_object(mem);
2154           dm_report_field_set_value(field, repstr, repstr);
2155           return 1;
2156 
2157       out_abandon:
2158           dm_pool_abandon_object(mem);
2159           return 0;
2160 }
2161 
_dm_deps_names_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)2162 static int _dm_deps_names_disp(struct dm_report *rh,
2163                                               struct dm_pool *mem,
2164                                               struct dm_report_field *field,
2165                                               const void *data, void *private)
2166 {
2167           return _dm_tree_names(rh, mem, field, data, private, 0);
2168 }
2169 
_dm_tree_parents_names_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)2170 static int _dm_tree_parents_names_disp(struct dm_report *rh,
2171                                                struct dm_pool *mem,
2172                                                struct dm_report_field *field,
2173                                                const void *data, void *private)
2174 {
2175           return _dm_tree_names(rh, mem, field, data, private, 1);
2176 }
2177 
_dm_tree_parents_devs_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)2178 static int _dm_tree_parents_devs_disp(struct dm_report *rh, struct dm_pool *mem,
2179                                               struct dm_report_field *field,
2180                                               const void *data, void *private)
2181 {
2182           struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
2183           void *t = NULL;
2184           const struct dm_info *info;
2185           int first_node = 1;
2186           char buf[DM_MAX_TYPE_NAME], *repstr;
2187 
2188           if (!dm_pool_begin_object(mem, 16)) {
2189                     log_error("dm_pool_begin_object failed");
2190                     return 0;
2191           }
2192 
2193           while ((parent = dm_tree_next_child(&t, node, 1))) {
2194                     info = dm_tree_node_get_info(parent);
2195                     if (!info->major && !info->minor)
2196                               continue;
2197                     if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
2198                               log_error("dm_pool_grow_object failed");
2199                               goto out_abandon;
2200                     }
2201                     if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2202                                         info->major, info->minor) < 0) {
2203                               log_error("dm_snprintf failed");
2204                               goto out_abandon;
2205                     }
2206                     if (!dm_pool_grow_object(mem, buf, 0)) {
2207                               log_error("dm_pool_grow_object failed");
2208                               goto out_abandon;
2209                     }
2210                     if (first_node)
2211                               first_node = 0;
2212           }
2213 
2214           if (!dm_pool_grow_object(mem, "\0", 1)) {
2215                     log_error("dm_pool_grow_object failed");
2216                     goto out_abandon;
2217           }
2218 
2219           repstr = dm_pool_end_object(mem);
2220           dm_report_field_set_value(field, repstr, repstr);
2221           return 1;
2222 
2223       out_abandon:
2224           dm_pool_abandon_object(mem);
2225           return 0;
2226 }
2227 
_dm_tree_parents_count_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)2228 static int _dm_tree_parents_count_disp(struct dm_report *rh,
2229                                                struct dm_pool *mem,
2230                                                struct dm_report_field *field,
2231                                                const void *data, void *private)
2232 {
2233           struct dm_tree_node *node = (struct dm_tree_node *) data;
2234           int num_parent = dm_tree_node_num_children(node, 1);
2235 
2236           return dm_report_field_int(rh, field, &num_parent);
2237 }
2238 
_dm_deps_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)2239 static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
2240                                struct dm_report_field *field, const void *data,
2241                                void *private)
2242 {
2243           struct dm_deps *deps = (struct dm_deps *) data;
2244           int i;
2245           char buf[DM_MAX_TYPE_NAME], *repstr;
2246 
2247           if (!dm_pool_begin_object(mem, 16)) {
2248                     log_error("dm_pool_begin_object failed");
2249                     return 0;
2250           }
2251 
2252           for (i = 0; i < deps->count; i++) {
2253                     if (dm_snprintf(buf, sizeof(buf), "%d:%d",
2254                            (int) MAJOR(deps->device[i]),
2255                            (int) MINOR(deps->device[i])) < 0) {
2256                               log_error("dm_snprintf failed");
2257                               goto out_abandon;
2258                     }
2259                     if (!dm_pool_grow_object(mem, buf, 0)) {
2260                               log_error("dm_pool_grow_object failed");
2261                               goto out_abandon;
2262                     }
2263                     if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
2264                               log_error("dm_pool_grow_object failed");
2265                               goto out_abandon;
2266                     }
2267           }
2268 
2269           if (!dm_pool_grow_object(mem, "\0", 1)) {
2270                     log_error("dm_pool_grow_object failed");
2271                     goto out_abandon;
2272           }
2273 
2274           repstr = dm_pool_end_object(mem);
2275           dm_report_field_set_value(field, repstr, repstr);
2276           return 1;
2277 
2278       out_abandon:
2279           dm_pool_abandon_object(mem);
2280           return 0;
2281 }
2282 
_dm_subsystem_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2283 static int _dm_subsystem_disp(struct dm_report *rh,
2284                                      struct dm_pool *mem __attribute((unused)),
2285                                      struct dm_report_field *field, const void *data,
2286                                      void *private __attribute((unused)))
2287 {
2288           return dm_report_field_string(rh, field, (const char **) data);
2289 }
2290 
_dm_vg_name_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2291 static int _dm_vg_name_disp(struct dm_report *rh,
2292                                    struct dm_pool *mem __attribute((unused)),
2293                                    struct dm_report_field *field, const void *data,
2294                                    void *private __attribute((unused)))
2295 {
2296 
2297           return dm_report_field_string(rh, field, (const char **) data);
2298 }
2299 
_dm_lv_name_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2300 static int _dm_lv_name_disp(struct dm_report *rh,
2301                                    struct dm_pool *mem __attribute((unused)),
2302                                    struct dm_report_field *field, const void *data,
2303                                    void *private __attribute((unused)))
2304 
2305 {
2306           return dm_report_field_string(rh, field, (const char **) data);
2307 }
2308 
_dm_lv_layer_name_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))2309 static int _dm_lv_layer_name_disp(struct dm_report *rh,
2310                                            struct dm_pool *mem __attribute((unused)),
2311                                            struct dm_report_field *field, const void *data,
2312                                            void *private __attribute((unused)))
2313 
2314 {
2315           return dm_report_field_string(rh, field, (const char **) data);
2316 }
2317 
_task_get_obj(void * obj)2318 static void *_task_get_obj(void *obj)
2319 {
2320           return ((struct dmsetup_report_obj *)obj)->task;
2321 }
2322 
_info_get_obj(void * obj)2323 static void *_info_get_obj(void *obj)
2324 {
2325           return ((struct dmsetup_report_obj *)obj)->info;
2326 }
2327 
_deps_get_obj(void * obj)2328 static void *_deps_get_obj(void *obj)
2329 {
2330           return dm_task_get_deps(((struct dmsetup_report_obj *)obj)->deps_task);
2331 }
2332 
_tree_get_obj(void * obj)2333 static void *_tree_get_obj(void *obj)
2334 {
2335           return ((struct dmsetup_report_obj *)obj)->tree_node;
2336 }
2337 
_split_name_get_obj(void * obj)2338 static void *_split_name_get_obj(void *obj)
2339 {
2340           return ((struct dmsetup_report_obj *)obj)->split_name;
2341 }
2342 
2343 static const struct dm_report_object_type _report_types[] = {
2344           { DR_TASK, "Mapped Device Name", "", _task_get_obj },
2345           { DR_INFO, "Mapped Device Information", "", _info_get_obj },
2346           { DR_DEPS, "Mapped Device Relationship Information", "", _deps_get_obj },
2347           { DR_TREE, "Mapped Device Relationship Information", "", _tree_get_obj },
2348           { DR_NAME, "Mapped Device Name Components", "", _split_name_get_obj },
2349           { 0, "", "", NULL },
2350 };
2351 
2352 /* Column definitions */
2353 #define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
2354 #define STR (DM_REPORT_FIELD_TYPE_STRING)
2355 #define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
2356 #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},
2357 #define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
2358 
2359 static const struct dm_report_field_type _report_fields[] = {
2360 /* *INDENT-OFF* */
2361 FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
2362 FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
2363 
2364 /* FIXME Next one should be INFO */
2365 FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
2366 
2367 FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
2368 FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
2369 FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
2370 FIELD_F(INFO, STR, "Read-only", 9, dm_info_read_only, "readonly", "Whether the device is read-only or writeable.")
2371 FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers")
2372 FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
2373 FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
2374 FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
2375 FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
2376 FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
2377 
2378 FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
2379 FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
2380 FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
2381 
2382 FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
2383 FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
2384 FIELD_F(TREE, STR, "RefDevNos", 9, dm_tree_parents_devs, "devnos_using_dev", "List of device numbers of mapped devices using this one.")
2385 
2386 FIELD_O(NAME, dm_split_name, STR, "Subsys", subsystem, 6, dm_subsystem, "subsystem", "Userspace subsystem responsible for this device.")
2387 FIELD_O(NAME, dm_split_name, STR, "VG", vg_name, 4, dm_vg_name, "vg_name", "LVM Volume Group name.")
2388 FIELD_O(NAME, dm_split_name, STR, "LV", lv_name, 4, dm_lv_name, "lv_name", "LVM Logical Volume name.")
2389 FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_layer", "LVM device layer.")
2390 
2391 {0, 0, 0, 0, "", "", NULL, NULL},
2392 /* *INDENT-ON* */
2393 };
2394 
2395 #undef STR
2396 #undef NUM
2397 #undef FIELD_O
2398 #undef FIELD_F
2399 
2400 static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
2401 static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
2402 
_report_init(struct command * c)2403 static int _report_init(struct command *c)
2404 {
2405           char *options = (char *) default_report_options;
2406           const char *keys = "";
2407           const char *separator = " ";
2408           int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
2409           int quoted = 1, columns_as_rows = 0;
2410           uint32_t flags = 0;
2411           size_t len = 0;
2412           int r = 0;
2413 
2414           if (!strcmp(c->name, "splitname"))
2415                     options = (char *) splitname_report_options;
2416 
2417           /* emulate old dmsetup behaviour */
2418           if (_switches[NOHEADINGS_ARG]) {
2419                     separator = ":";
2420                     aligned = 0;
2421                     headings = 0;
2422           }
2423 
2424           if (_switches[UNBUFFERED_ARG])
2425                     buffered = 0;
2426 
2427           if (_switches[ROWS_ARG])
2428                     columns_as_rows = 1;
2429 
2430           if (_switches[UNQUOTED_ARG])
2431                     quoted = 0;
2432 
2433           if (_switches[NAMEPREFIXES_ARG]) {
2434                     aligned = 0;
2435                     field_prefixes = 1;
2436           }
2437 
2438           if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
2439                     if (*_string_args[OPTIONS_ARG] != '+')
2440                               options = _string_args[OPTIONS_ARG];
2441                     else {
2442                               len = strlen(default_report_options) +
2443                                     strlen(_string_args[OPTIONS_ARG]) + 1;
2444                               if (!(options = dm_malloc(len))) {
2445                                         err("Failed to allocate option string.");
2446                                         return 0;
2447                               }
2448                               if (dm_snprintf(options, len, "%s,%s",
2449                                                   default_report_options,
2450                                                   &_string_args[OPTIONS_ARG][1]) < 0) {
2451                                         err("snprintf failed");
2452                                         goto out;
2453                               }
2454                     }
2455           }
2456 
2457           if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
2458                     keys = _string_args[SORT_ARG];
2459                     buffered = 1;
2460                     if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
2461                               err("--sort is not yet supported with status and table");
2462                               goto out;
2463                     }
2464           }
2465 
2466           if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
2467                     separator = _string_args[SEPARATOR_ARG];
2468                     aligned = 0;
2469           }
2470 
2471           if (aligned)
2472                     flags |= DM_REPORT_OUTPUT_ALIGNED;
2473 
2474           if (buffered)
2475                     flags |= DM_REPORT_OUTPUT_BUFFERED;
2476 
2477           if (headings)
2478                     flags |= DM_REPORT_OUTPUT_HEADINGS;
2479 
2480           if (field_prefixes)
2481                     flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
2482 
2483           if (!quoted)
2484                     flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
2485 
2486           if (columns_as_rows)
2487                     flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
2488 
2489           if (!(_report = dm_report_init(&_report_type,
2490                                                _report_types, _report_fields,
2491                                                options, separator, flags, keys, NULL)))
2492                     goto out;
2493 
2494           if ((_report_type & DR_TREE) && !_build_whole_deptree()) {
2495                     err("Internal device dependency tree creation failed.");
2496                     goto out;
2497           }
2498 
2499           if (field_prefixes)
2500                     dm_report_set_output_field_name_prefix(_report, "dm_");
2501 
2502           r = 1;
2503 
2504 out:
2505           if (len)
2506                     dm_free(options);
2507 
2508           return r;
2509 }
2510 
2511 /*
2512  * List devices
2513  */
_ls(int argc,char ** argv,void * data)2514 static int _ls(int argc, char **argv, void *data)
2515 {
2516           if ((_switches[TARGET_ARG] && _target) ||
2517               (_switches[EXEC_ARG] && _command))
2518                     return _status(argc, argv, data);
2519           else if ((_switches[TREE_ARG]))
2520                     return _display_tree(argc, argv, data);
2521           else
2522                     return _process_all(argc, argv, 0, _display_name);
2523 }
2524 
2525 static int _help(int argc, char **argv, void *data);
2526 
2527 /*
2528  * Dispatch table
2529  */
2530 static struct command _commands[] = {
2531           {"help", "[-c|-C|--columns]", 0, 0, _help},
2532           {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
2533             "\t                  [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
2534             "\t                  [-u|uuid <uuid>]\n"
2535             "\t                  [--notable | --table <table> | <table_file>]",
2536            1, 2, _create},
2537           {"remove", "[-f|--force] <device>", 0, 1, _remove},
2538           {"remove_all", "[-f|--force]", 0, 0, _remove_all},
2539           {"suspend", "[--noflush] <device>", 0, 1, _suspend},
2540           {"resume", "<device>", 0, 1, _resume},
2541           {"load", "<device> [<table_file>]", 0, 2, _load},
2542           {"clear", "<device>", 0, 1, _clear},
2543           {"reload", "<device> [<table_file>]", 0, 2, _load},
2544           {"rename", "<device> <new_name>", 1, 2, _rename},
2545           {"message", "<device> <sector> <message>", 2, -1, _message},
2546           {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
2547           {"info", "[<device>]", 0, 1, _info},
2548           {"deps", "[<device>]", 0, 1, _deps},
2549           {"status", "[<device>] [--target <target_type>]", 0, 1, _status},
2550           {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
2551           {"wait", "<device> [<event_nr>]", 0, 2, _wait},
2552           {"mknodes", "[<device>]", 0, 1, _mknodes},
2553           {"udevflags", "<cookie>", 1, 1, _udevflags},
2554           {"udevcomplete", "<cookie>", 1, 1, _udevcomplete},
2555           {"udevcomplete_all", "", 0, 0, _udevcomplete_all},
2556           {"udevcookies", "", 0, 0, _udevcookies},
2557           {"targets", "", 0, 0, _targets},
2558           {"version", "", 0, 0, _version},
2559           {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
2560           {"splitname", "<device> [<subsystem>]", 1, 2, _splitname},
2561           {NULL, NULL, 0, 0, NULL}
2562 };
2563 
_usage(FILE * out)2564 static void _usage(FILE *out)
2565 {
2566           int i;
2567 
2568           fprintf(out, "Usage:\n\n");
2569           fprintf(out, "dmsetup [--version] [-v|--verbose [-v|--verbose ...]]\n"
2570                     "        [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
2571                     "        [--noudevsync] [-y|--yes] [--readahead [+]<sectors>|auto|none]\n"
2572                     "        [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
2573                     "        [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
2574           for (i = 0; _commands[i].name; i++)
2575                     fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
2576           fprintf(out, "\n<device> may be device name or -u <uuid> or "
2577                          "-j <major> -m <minor>\n");
2578           fprintf(out, "<fields> are comma-separated.  Use 'help -c' for list.\n");
2579           fprintf(out, "Table_file contents may be supplied on stdin.\n");
2580           fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
2581                          "                  [no]device, active, open, rw and uuid.\n");
2582           fprintf(out, "\n");
2583           return;
2584 }
2585 
_losetup_usage(FILE * out)2586 static void _losetup_usage(FILE *out)
2587 {
2588           fprintf(out, "Usage:\n\n");
2589           fprintf(out, "losetup [-d|-a] [-e encryption] "
2590                          "[-o offset] [-f|loop_device] [file]\n\n");
2591 }
2592 
_help(int argc __attribute ((unused)),char ** argv __attribute ((unused)),void * data __attribute ((unused)))2593 static int _help(int argc __attribute((unused)),
2594                      char **argv __attribute((unused)),
2595                      void *data __attribute((unused)))
2596 {
2597           _usage(stderr);
2598 
2599           if (_switches[COLS_ARG]) {
2600                     _switches[OPTIONS_ARG] = 1;
2601                     _string_args[OPTIONS_ARG] = (char *) "help";
2602                     _switches[SORT_ARG] = 0;
2603 
2604                     (void) _report_init(NULL);
2605           }
2606 
2607           return 1;
2608 }
2609 
_find_command(const char * name)2610 static struct command *_find_command(const char *name)
2611 {
2612           int i;
2613 
2614           for (i = 0; _commands[i].name; i++)
2615                     if (!strcmp(_commands[i].name, name))
2616                               return _commands + i;
2617 
2618           return NULL;
2619 }
2620 
_process_tree_options(const char * options)2621 static int _process_tree_options(const char *options)
2622 {
2623           const char *s, *end;
2624           struct winsize winsz;
2625           size_t len;
2626 
2627           /* Symbol set default */
2628           if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
2629                     _tsym = &_tsym_utf;
2630           else
2631                     _tsym = &_tsym_ascii;
2632 
2633           /* Default */
2634           _tree_switches[TR_DEVICE] = 1;
2635           _tree_switches[TR_TRUNCATE] = 1;
2636 
2637           /* parse */
2638           for (s = options; s && *s; s++) {
2639                     len = 0;
2640                     for (end = s; *end && *end != ','; end++, len++)
2641                               ;
2642                     if (!strncmp(s, "device", len))
2643                               _tree_switches[TR_DEVICE] = 1;
2644                     else if (!strncmp(s, "nodevice", len))
2645                               _tree_switches[TR_DEVICE] = 0;
2646                     else if (!strncmp(s, "status", len))
2647                               _tree_switches[TR_STATUS] = 1;
2648                     else if (!strncmp(s, "table", len))
2649                               _tree_switches[TR_TABLE] = 1;
2650                     else if (!strncmp(s, "active", len))
2651                               _tree_switches[TR_ACTIVE] = 1;
2652                     else if (!strncmp(s, "open", len))
2653                               _tree_switches[TR_OPENCOUNT] = 1;
2654                     else if (!strncmp(s, "uuid", len))
2655                               _tree_switches[TR_UUID] = 1;
2656                     else if (!strncmp(s, "rw", len))
2657                               _tree_switches[TR_RW] = 1;
2658                     else if (!strncmp(s, "utf", len))
2659                               _tsym = &_tsym_utf;
2660                     else if (!strncmp(s, "vt100", len))
2661                               _tsym = &_tsym_vt100;
2662                     else if (!strncmp(s, "ascii", len))
2663                               _tsym = &_tsym_ascii;
2664                     else if (!strncmp(s, "inverted", len))
2665                               _tree_switches[TR_BOTTOMUP] = 1;
2666                     else if (!strncmp(s, "compact", len))
2667                               _tree_switches[TR_COMPACT] = 1;
2668                     else if (!strncmp(s, "notrunc", len))
2669                               _tree_switches[TR_TRUNCATE] = 0;
2670                     else {
2671                               fprintf(stderr, "Tree options not recognised: %s\n", s);
2672                               return 0;
2673                     }
2674                     if (!*end)
2675                               break;
2676                     s = end;
2677           }
2678 
2679           /* Truncation doesn't work well with vt100 drawing char */
2680           if (_tsym != &_tsym_vt100)
2681                     if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
2682                               _termwidth = winsz.ws_col - 3;
2683 
2684           return 1;
2685 }
2686 
2687 /*
2688  * Returns the full absolute path, or NULL if the path could
2689  * not be resolved.
2690  */
_get_abspath(const char * path)2691 static char *_get_abspath(const char *path)
2692 {
2693           char *_path;
2694 
2695 #ifdef HAVE_CANONICALIZE_FILE_NAME
2696           _path = canonicalize_file_name(path);
2697 #else
2698           /* FIXME Provide alternative */
2699 #endif
2700           return _path;
2701 }
2702 
parse_loop_device_name(const char * dev,const char * dev_dir)2703 static char *parse_loop_device_name(const char *dev, const char *dev_dir)
2704 {
2705           char *buf;
2706           char *device;
2707 
2708           if (!(buf = dm_malloc(PATH_MAX)))
2709                     return NULL;
2710 
2711           if (dev[0] == '/') {
2712                     if (!(device = _get_abspath(dev)))
2713                               goto error;
2714 
2715                     if (strncmp(device, dev_dir, strlen(dev_dir)))
2716                               goto error;
2717 
2718                     /* If dev_dir does not end in a slash, ensure that the
2719                        following byte in the device string is "/".  */
2720                     if (dev_dir[strlen(dev_dir) - 1] != '/' &&
2721                         device[strlen(dev_dir)] != '/')
2722                               goto error;
2723 
2724                     strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
2725                     dm_free(device);
2726 
2727           } else {
2728                     /* check for device number */
2729                     if (!strncmp(dev, "loop", strlen("loop")))
2730                               strncpy(buf, dev, (size_t) PATH_MAX);
2731                     else
2732                               goto error;
2733           }
2734 
2735           return buf;
2736 
2737 error:
2738           return NULL;
2739 }
2740 
2741 /*
2742  *  create a table for a mapped device using the loop target.
2743  */
_loop_table(char * table,size_t tlen,char * file,char * dev __attribute ((unused)),off_t off)2744 static int _loop_table(char *table, size_t tlen, char *file,
2745                            char *dev __attribute((unused)), off_t off)
2746 {
2747           struct stat fbuf;
2748           off_t size, sectors;
2749           int fd = -1;
2750 #ifdef HAVE_SYS_STATVFS_H
2751           struct statvfs fsbuf;
2752           off_t blksize;
2753 #endif
2754 
2755           if (!_switches[READ_ONLY])
2756                     fd = open(file, O_RDWR);
2757 
2758           if (fd < 0) {
2759                     _switches[READ_ONLY]++;
2760                     fd = open(file, O_RDONLY);
2761           }
2762 
2763           if (fd < 0)
2764                     goto error;
2765 
2766           if (fstat(fd, &fbuf))
2767                     goto error;
2768 
2769           size = (fbuf.st_size - off);
2770           sectors = size >> SECTOR_SHIFT;
2771 
2772           if (_switches[VERBOSE_ARG])
2773                     fprintf(stderr, "losetup: set loop size to %llukB "
2774                               "(%llu sectors)\n", (long long unsigned) sectors >> 1,
2775                               (long long unsigned) sectors);
2776 
2777 #ifdef HAVE_SYS_STATVFS_H
2778           if (fstatvfs(fd, &fsbuf))
2779                     goto error;
2780 
2781           /* FIXME Fragment size currently unused */
2782           blksize = fsbuf.f_frsize;
2783 #endif
2784 
2785           close(fd);
2786 
2787           if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
2788                               (long long unsigned)sectors, file, off) < 0)
2789                     return 0;
2790 
2791           if (_switches[VERBOSE_ARG] > 1)
2792                     fprintf(stderr, "Table: %s\n", table);
2793 
2794           return 1;
2795 
2796 error:
2797           if (fd > -1)
2798                     close(fd);
2799           return 0;
2800 }
2801 
_process_losetup_switches(const char * base,int * argc,char *** argv,const char * dev_dir)2802 static int _process_losetup_switches(const char *base, int *argc, char ***argv,
2803                                              const char *dev_dir)
2804 {
2805           static int ind;
2806           int c;
2807           int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
2808           char *device_name = NULL;
2809           char *loop_file = NULL;
2810           off_t offset = 0;
2811 
2812 #ifdef HAVE_GETOPTLONG
2813           static struct option long_options[] = {
2814                     {0, 0, 0, 0}
2815           };
2816 #endif
2817 
2818           optarg = 0;
2819           optind = OPTIND_INIT;
2820           while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
2821                                                       long_options, NULL)) != -1 ) {
2822                     if (c == ':' || c == '?')
2823                               return 0;
2824                     if (c == 'a')
2825                               show_all++;
2826                     if (c == 'd')
2827                               delete++;
2828                     if (c == 'e')
2829                               encrypt_loop++;
2830                     if (c == 'f')
2831                               find++;
2832                     if (c == 'o')
2833                               offset = atoi(optarg);
2834                     if (c == 'v')
2835                               _switches[VERBOSE_ARG]++;
2836           }
2837 
2838           *argv += optind ;
2839           *argc -= optind ;
2840 
2841           if (encrypt_loop){
2842                     fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
2843                                         "in this version.\n", base);
2844                     return 0;
2845           }
2846 
2847           if (show_all) {
2848                     fprintf(stderr, "%s: Sorry, show all is not yet implemented "
2849                                         "in this version.\n", base);
2850                     return 0;
2851           }
2852 
2853           if (find) {
2854                     fprintf(stderr, "%s: Sorry, find is not yet implemented "
2855                                         "in this version.\n", base);
2856                     if (!*argc)
2857                               return 0;
2858           }
2859 
2860           if (!*argc) {
2861                     fprintf(stderr, "%s: Please specify loop_device.\n", base);
2862                     _losetup_usage(stderr);
2863                     return 0;
2864           }
2865 
2866           if (!(device_name = parse_loop_device_name((*argv)[0], dev_dir))) {
2867                     fprintf(stderr, "%s: Could not parse loop_device %s\n",
2868                               base, (*argv)[0]);
2869                     _losetup_usage(stderr);
2870                     return 0;
2871           }
2872 
2873           if (delete) {
2874                     *argc = 2;
2875 
2876                     (*argv)[1] = device_name;
2877                     (*argv)[0] = (char *) "remove";
2878 
2879                     return 1;
2880           }
2881 
2882           if (*argc != 2) {
2883                     fprintf(stderr, "%s: Too few arguments\n", base);
2884                     _losetup_usage(stderr);
2885                     dm_free(device_name);
2886                     return 0;
2887           }
2888 
2889           /* FIXME move these to make them available to native dmsetup */
2890           if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
2891                     fprintf(stderr, "%s: Could not parse loop file name %s\n",
2892                               base, (*argv)[1]);
2893                     _losetup_usage(stderr);
2894                     dm_free(device_name);
2895                     return 0;
2896           }
2897 
2898           /* FIXME Missing free */
2899           _table = dm_malloc(LOOP_TABLE_SIZE);
2900           if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
2901                     fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
2902                     dm_free(device_name);
2903                     return 0;
2904           }
2905           _switches[TABLE_ARG]++;
2906 
2907           (*argv)[0] = (char *) "create";
2908           (*argv)[1] = device_name ;
2909 
2910           return 1;
2911 }
2912 
_process_switches(int * argc,char *** argv,const char * dev_dir)2913 static int _process_switches(int *argc, char ***argv, const char *dev_dir)
2914 {
2915           char *base, *namebase, *s;
2916           static int ind;
2917           int c, r;
2918 
2919 #ifdef HAVE_GETOPTLONG
2920           static struct option long_options[] = {
2921                     {"readonly", 0, &ind, READ_ONLY},
2922                     {"columns", 0, &ind, COLS_ARG},
2923                     {"exec", 1, &ind, EXEC_ARG},
2924                     {"force", 0, &ind, FORCE_ARG},
2925                     {"gid", 1, &ind, GID_ARG},
2926                     {"inactive", 0, &ind, INACTIVE_ARG},
2927                     {"major", 1, &ind, MAJOR_ARG},
2928                     {"minor", 1, &ind, MINOR_ARG},
2929                     {"mode", 1, &ind, MODE_ARG},
2930                     {"nameprefixes", 0, &ind, NAMEPREFIXES_ARG},
2931                     {"noflush", 0, &ind, NOFLUSH_ARG},
2932                     {"noheadings", 0, &ind, NOHEADINGS_ARG},
2933                     {"nolockfs", 0, &ind, NOLOCKFS_ARG},
2934                     {"noopencount", 0, &ind, NOOPENCOUNT_ARG},
2935                     {"notable", 0, &ind, NOTABLE_ARG},
2936                     {"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
2937                     {"options", 1, &ind, OPTIONS_ARG},
2938                     {"readahead", 1, &ind, READAHEAD_ARG},
2939                     {"rows", 0, &ind, ROWS_ARG},
2940                     {"separator", 1, &ind, SEPARATOR_ARG},
2941                     {"showkeys", 0, &ind, SHOWKEYS_ARG},
2942                     {"sort", 1, &ind, SORT_ARG},
2943                     {"table", 1, &ind, TABLE_ARG},
2944                     {"target", 1, &ind, TARGET_ARG},
2945                     {"tree", 0, &ind, TREE_ARG},
2946                     {"uid", 1, &ind, UID_ARG},
2947                     {"uuid", 1, &ind, UUID_ARG},
2948                     {"unbuffered", 0, &ind, UNBUFFERED_ARG},
2949                     {"unquoted", 0, &ind, UNQUOTED_ARG},
2950                     {"verbose", 1, &ind, VERBOSE_ARG},
2951                     {"version", 0, &ind, VERSION_ARG},
2952                     {"yes", 0, &ind, YES_ARG},
2953                     {0, 0, 0, 0}
2954           };
2955 #else
2956           struct option long_options;
2957 #endif
2958 
2959           /*
2960            * Zero all the index counts.
2961            */
2962           memset(&_switches, 0, sizeof(_switches));
2963           memset(&_int_args, 0, sizeof(_int_args));
2964           _read_ahead_flags = 0;
2965 
2966           namebase = strdup((*argv)[0]);
2967           base = basename(namebase);
2968 
2969           if (!strcmp(base, "devmap_name")) {
2970                     free(namebase);
2971                     _switches[COLS_ARG]++;
2972                     _switches[NOHEADINGS_ARG]++;
2973                     _switches[OPTIONS_ARG]++;
2974                     _switches[MAJOR_ARG]++;
2975                     _switches[MINOR_ARG]++;
2976                     _string_args[OPTIONS_ARG] = (char *) "name";
2977 
2978                     if (*argc == 3) {
2979                               _int_args[MAJOR_ARG] = atoi((*argv)[1]);
2980                               _int_args[MINOR_ARG] = atoi((*argv)[2]);
2981                               *argc -= 2;
2982                               *argv += 2;
2983                     } else if ((*argc == 2) &&
2984                                  (2 == sscanf((*argv)[1], "%i:%i",
2985                                                   &_int_args[MAJOR_ARG],
2986                                                   &_int_args[MINOR_ARG]))) {
2987                               *argc -= 1;
2988                               *argv += 1;
2989                     } else {
2990                               fprintf(stderr, "Usage: devmap_name <major> <minor>\n");
2991                               return 0;
2992                     }
2993 
2994                     (*argv)[0] = (char *) "info";
2995                     return 1;
2996           }
2997 
2998           if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
2999                     r = _process_losetup_switches(base, argc, argv, dev_dir);
3000                     free(namebase);
3001                     return r;
3002           }
3003 
3004           free(namebase);
3005 
3006           optarg = 0;
3007           optind = OPTIND_INIT;
3008           while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:j:m:M:no:O:ru:U:vy",
3009                                                       long_options, NULL)) != -1) {
3010                     if (c == ':' || c == '?')
3011                               return 0;
3012                     if (c == 'c' || c == 'C' || ind == COLS_ARG)
3013                               _switches[COLS_ARG]++;
3014                     if (c == 'f' || ind == FORCE_ARG)
3015                               _switches[FORCE_ARG]++;
3016                     if (c == 'r' || ind == READ_ONLY)
3017                               _switches[READ_ONLY]++;
3018                     if (c == 'j' || ind == MAJOR_ARG) {
3019                               _switches[MAJOR_ARG]++;
3020                               _int_args[MAJOR_ARG] = atoi(optarg);
3021                     }
3022                     if (c == 'm' || ind == MINOR_ARG) {
3023                               _switches[MINOR_ARG]++;
3024                               _int_args[MINOR_ARG] = atoi(optarg);
3025                     }
3026                     if (c == 'n' || ind == NOTABLE_ARG)
3027                               _switches[NOTABLE_ARG]++;
3028                     if (c == 'o' || ind == OPTIONS_ARG) {
3029                               _switches[OPTIONS_ARG]++;
3030                               _string_args[OPTIONS_ARG] = optarg;
3031                     }
3032                     if (ind == SEPARATOR_ARG) {
3033                               _switches[SEPARATOR_ARG]++;
3034                               _string_args[SEPARATOR_ARG] = optarg;
3035                     }
3036                     if (c == 'O' || ind == SORT_ARG) {
3037                               _switches[SORT_ARG]++;
3038                               _string_args[SORT_ARG] = optarg;
3039                     }
3040                     if (c == 'v' || ind == VERBOSE_ARG)
3041                               _switches[VERBOSE_ARG]++;
3042                     if (c == 'u' || ind == UUID_ARG) {
3043                               _switches[UUID_ARG]++;
3044                               _uuid = optarg;
3045                     }
3046                     if (c == 'y' || ind == YES_ARG)
3047                               _switches[YES_ARG]++;
3048                     if (ind == NOUDEVSYNC_ARG)
3049                               _switches[NOUDEVSYNC_ARG]++;
3050                     if (c == 'G' || ind == GID_ARG) {
3051                               _switches[GID_ARG]++;
3052                               _int_args[GID_ARG] = atoi(optarg);
3053                     }
3054                     if (c == 'U' || ind == UID_ARG) {
3055                               _switches[UID_ARG]++;
3056                               _int_args[UID_ARG] = atoi(optarg);
3057                     }
3058                     if (c == 'M' || ind == MODE_ARG) {
3059                               _switches[MODE_ARG]++;
3060                               /* FIXME Accept modes as per chmod */
3061                               _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
3062                     }
3063                     if ((ind == EXEC_ARG)) {
3064                               _switches[EXEC_ARG]++;
3065                               _command = optarg;
3066                     }
3067                     if ((ind == TARGET_ARG)) {
3068                               _switches[TARGET_ARG]++;
3069                               _target = optarg;
3070                     }
3071                     if ((ind == INACTIVE_ARG))
3072                               _switches[INACTIVE_ARG]++;
3073                     if ((ind == NAMEPREFIXES_ARG))
3074                               _switches[NAMEPREFIXES_ARG]++;
3075                     if ((ind == NOFLUSH_ARG))
3076                               _switches[NOFLUSH_ARG]++;
3077                     if ((ind == NOHEADINGS_ARG))
3078                               _switches[NOHEADINGS_ARG]++;
3079                     if ((ind == NOLOCKFS_ARG))
3080                               _switches[NOLOCKFS_ARG]++;
3081                     if ((ind == NOOPENCOUNT_ARG))
3082                               _switches[NOOPENCOUNT_ARG]++;
3083                     if ((ind == READAHEAD_ARG)) {
3084                               _switches[READAHEAD_ARG]++;
3085                               if (!strcasecmp(optarg, "auto"))
3086                                         _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
3087                               else if (!strcasecmp(optarg, "none"))
3088                               _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
3089                               else {
3090                                         for (s = optarg; isspace(*s); s++)
3091                                                   ;
3092                                         if (*s == '+')
3093                                                   _read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
3094                                         _int_args[READAHEAD_ARG] = atoi(optarg);
3095                                         if (_int_args[READAHEAD_ARG] < -1) {
3096                                                   log_error("Negative read ahead value "
3097                                                               "(%d) is not understood.",
3098                                                               _int_args[READAHEAD_ARG]);
3099                                                   return 0;
3100                                         }
3101                               }
3102                     }
3103                     if ((ind == ROWS_ARG))
3104                               _switches[ROWS_ARG]++;
3105                     if ((ind == SHOWKEYS_ARG))
3106                               _switches[SHOWKEYS_ARG]++;
3107                     if ((ind == TABLE_ARG)) {
3108                               _switches[TABLE_ARG]++;
3109                               _table = optarg;
3110                     }
3111                     if ((ind == TREE_ARG))
3112                               _switches[TREE_ARG]++;
3113                     if ((ind == UNQUOTED_ARG))
3114                               _switches[UNQUOTED_ARG]++;
3115                     if ((ind == VERSION_ARG))
3116                               _switches[VERSION_ARG]++;
3117           }
3118 
3119           if (_switches[VERBOSE_ARG] > 1)
3120                     dm_log_init_verbose(_switches[VERBOSE_ARG] - 1);
3121 
3122           if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) ||
3123               (!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) {
3124                     fprintf(stderr, "Please specify both major number and "
3125                                         "minor number.\n");
3126                     return 0;
3127           }
3128 
3129           if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
3130                     return 0;
3131 
3132           if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
3133                     fprintf(stderr, "--table and --notable are incompatible.\n");
3134                     return 0;
3135           }
3136 
3137           *argv += optind;
3138           *argc -= optind;
3139           return 1;
3140 }
3141 
main(int argc,char ** argv)3142 int main(int argc, char **argv)
3143 {
3144           struct command *c;
3145           int r = 1;
3146           const char *dev_dir;
3147 
3148           (void) setlocale(LC_ALL, "");
3149 
3150           dev_dir = getenv ("DM_DEV_DIR");
3151           if (dev_dir && *dev_dir) {
3152                     if (!dm_set_dev_dir(dev_dir)) {
3153                               fprintf(stderr, "Invalid DM_DEV_DIR environment variable value.\n");
3154                               goto out;
3155                     }
3156           } else
3157                     dev_dir = DEFAULT_DM_DEV_DIR;
3158 
3159           if (!_process_switches(&argc, &argv, dev_dir)) {
3160                     fprintf(stderr, "Couldn't process command line.\n");
3161                     goto out;
3162           }
3163 
3164           if (_switches[VERSION_ARG]) {
3165                     c = _find_command("version");
3166                     goto doit;
3167           }
3168 
3169           if (argc == 0) {
3170                     _usage(stderr);
3171                     goto out;
3172           }
3173 
3174           if (!(c = _find_command(argv[0]))) {
3175                     fprintf(stderr, "Unknown command\n");
3176                     _usage(stderr);
3177                     goto out;
3178           }
3179 
3180           if (argc < c->min_args + 1 ||
3181               (c->max_args >= 0 && argc > c->max_args + 1)) {
3182                     fprintf(stderr, "Incorrect number of arguments\n");
3183                     _usage(stderr);
3184                     goto out;
3185           }
3186 
3187           if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname"))
3188                     _switches[COLS_ARG]++;
3189 
3190           if (_switches[COLS_ARG] && !_report_init(c))
3191                     goto out;
3192 
3193           if (_switches[NOUDEVSYNC_ARG])
3194                     dm_udev_set_sync_support(0);
3195 
3196       doit:
3197           if (!c->fn(argc, argv, NULL)) {
3198                     fprintf(stderr, "Command failed\n");
3199                     goto out;
3200           }
3201 
3202           r = 0;
3203 
3204 out:
3205           if (_report) {
3206                     dm_report_output(_report);
3207                     dm_report_free(_report);
3208           }
3209 
3210           if (_dtree)
3211                     dm_tree_free(_dtree);
3212 
3213           return r;
3214 }
3215