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