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