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