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, ¶ms);
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, ¶ms);
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