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