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