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