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