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