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