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