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
8 * This file is part of the device-mapper userspace tools.
10 * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/
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.
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
22 #define _FILE_OFFSET_BITS 64
24 #include "configure.h"
26 #include "dm-logging.h"
38 #include <sys/param.h>
46 #ifdef UDEV_SYNC_SUPPORT
47 # include <sys/types.h>
52 /* FIXME Unused so far */
53 #undef HAVE_SYS_STATVFS_H
55 #ifdef HAVE_SYS_STATVFS_H
56 # include <sys/statvfs.h>
59 #ifdef HAVE_SYS_IOCTL_H
60 # include <sys/ioctl.h>
67 #ifdef HAVE_GETOPTLONG
69 # define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
70 # define OPTIND_INIT 0
76 # define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
77 # define OPTIND_INIT 1
80 #ifndef TEMP_FAILURE_RETRY
81 # define TEMP_FAILURE_RETRY(expression) \
83 ({ long int __result; \
84 do __result = (long int) (expression); \
85 while (__result == -1L && errno == EINTR); \
92 # define MAJOR(x) major((x))
93 # define MINOR(x) minor((x))
94 # define MKDEV(x,y) makedev((x),(y))
97 #define LINE_SIZE 4096
99 #define LOOP_TABLE_SIZE (PATH_MAX + 255)
101 #define DEFAULT_DM_DEV_DIR "/dev"
103 /* FIXME Should be imported */
104 #ifndef DM_MAX_TYPE_NAME
105 # define DM_MAX_TYPE_NAME 16
108 /* FIXME Should be elsewhere */
109 #define SECTOR_SHIFT 9L
111 #define err(msg, x...) fprintf(stderr, msg "\n", ##x)
114 * We have only very simple switches ATM.
156 DR_TREE
= 8, /* Complete dependency tree required */
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
;
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
;
177 typedef int (*command_fn
) (int argc
, char **argv
, void *data
);
187 static int _parse_line(struct dm_task
*dmt
, char *buffer
, const char *file
,
190 char ttype
[LINE_SIZE
], *ptr
, *comment
;
191 unsigned long long start
, size
;
194 /* trim trailing space */
195 for (ptr
= buffer
+ strlen(buffer
) - 1; ptr
>= buffer
; ptr
--)
196 if (!isspace((int) *ptr
))
201 /* trim leading space */
202 for (ptr
= buffer
; *ptr
&& isspace((int) *ptr
); ptr
++)
205 if (!*ptr
|| *ptr
== '#')
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
);
215 if ((comment
= strchr(ptr
, (int) '#')))
218 if (!dm_task_add_target(dmt
, start
, size
, ttype
, ptr
))
224 static int _parse_file(struct dm_task
*dmt
, const char *file
)
227 size_t buffer_size
= 0;
231 /* one-line table on cmdline */
233 return _parse_line(dmt
, _table
, "", ++line
);
235 /* OK for empty stdin */
237 if (!(fp
= fopen(file
, "r"))) {
238 err("Couldn't open '%s' for reading", file
);
245 buffer_size
= LINE_SIZE
;
246 if (!(buffer
= dm_malloc(buffer_size
))) {
247 err("Failed to malloc line buffer.");
251 while (fgets(buffer
, (int) buffer_size
, fp
))
253 while (getline(&buffer
, &buffer_size
, fp
) > 0)
255 if (!_parse_line(dmt
, buffer
, file
? : "on stdin", ++line
))
266 if (file
&& fclose(fp
))
267 fprintf(stderr
, "%s: fclose failed: %s", file
, strerror(errno
));
272 struct dm_split_name
{
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
;
287 static struct dm_task
*_get_deps_task(int major
, int minor
)
292 if (!(dmt
= dm_task_create(DM_DEVICE_DEPS
)))
295 if (!dm_task_set_major(dmt
, major
) ||
296 !dm_task_set_minor(dmt
, minor
))
299 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
302 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
305 if (!dm_task_run(dmt
))
308 if (!dm_task_get_info(dmt
, &info
))
317 dm_task_destroy(dmt
);
321 static char *_extract_uuid_prefix(const char *uuid
, const int separator
)
324 char *uuid_prefix
= NULL
;
328 ptr
= strchr(uuid
, separator
);
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.");
336 memcpy(uuid_prefix
, uuid
, len
);
337 uuid_prefix
[len
] = '\0';
342 static struct dm_split_name
*_get_split_name(const char *uuid
, const char *name
,
345 struct dm_split_name
*split_name
;
347 if (!(split_name
= dm_malloc(sizeof(*split_name
)))) {
348 log_error("Failed to allocate memory to split device name "
353 split_name
->subsystem
= _extract_uuid_prefix(uuid
, separator
);
354 split_name
->vg_name
= split_name
->lv_name
=
355 split_name
->lv_layer
= (char *) "";
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 "
367 static void _destroy_split_name(struct dm_split_name
*split_name
)
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.
373 if (!strcmp(split_name
->subsystem
, "LVM"))
374 dm_free(split_name
->vg_name
);
376 dm_free(split_name
->subsystem
);
380 static int _display_info_cols(struct dm_task
*dmt
, struct dm_info
*info
)
382 struct dmsetup_report_obj obj
;
386 fprintf(stderr
, "Device does not exist.\n");
392 obj
.deps_task
= NULL
;
393 obj
.split_name
= NULL
;
395 if (_report_type
& DR_TREE
)
396 obj
.tree_node
= dm_tree_find_node(_dtree
, info
->major
, info
->minor
);
398 if (_report_type
& DR_DEPS
)
399 obj
.deps_task
= _get_deps_task(info
->major
, info
->minor
);
401 if (_report_type
& DR_NAME
)
402 obj
.split_name
= _get_split_name(dm_task_get_uuid(dmt
), dm_task_get_name(dmt
), '-');
404 if (!dm_report_object(_report
, &obj
))
411 dm_task_destroy(obj
.deps_task
);
413 _destroy_split_name(obj
.split_name
);
417 static void _display_info_long(struct dm_task
*dmt
, struct dm_info
*info
)
423 printf("Device does not exist.\n");
427 printf("Name: %s\n", dm_task_get_name(dmt
));
429 printf("State: %s%s\n",
430 info
->suspended
? "SUSPENDED" : "ACTIVE",
431 info
->read_only
? " (READ-ONLY)" : "");
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
);
437 if (!info
->live_table
&& !info
->inactive_table
)
438 printf("Tables present: None\n");
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" : "");
445 if (info
->open_count
!= -1)
446 printf("Open count: %d\n", info
->open_count
);
448 printf("Event number: %" PRIu32
"\n", info
->event_nr
);
449 printf("Major, minor: %d, %d\n", info
->major
, info
->minor
);
451 if (info
->target_count
!= -1)
452 printf("Number of targets: %d\n", info
->target_count
);
454 if ((uuid
= dm_task_get_uuid(dmt
)) && *uuid
)
455 printf("UUID: %s\n", uuid
);
460 static int _display_info(struct dm_task
*dmt
)
464 if (!dm_task_get_info(dmt
, &info
))
467 if (!_switches
[COLS_ARG
])
468 _display_info_long(dmt
, &info
);
470 /* FIXME return code */
471 _display_info_cols(dmt
, &info
);
473 return info
.exists
? 1 : 0;
476 static int _set_task_device(struct dm_task
*dmt
, const char *name
, int optional
)
479 if (!dm_task_set_name(dmt
, name
))
481 } else if (_switches
[UUID_ARG
]) {
482 if (!dm_task_set_uuid(dmt
, _uuid
))
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
]))
488 } else if (!optional
) {
489 fprintf(stderr
, "No device specified.\n");
496 static int _load(int argc
, char **argv
, void *data
__attribute((unused
)))
500 const char *file
= NULL
;
501 const char *name
= NULL
;
503 if (_switches
[NOTABLE_ARG
]) {
504 err("--notable only available when creating new device\n");
508 if (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
]) {
510 err("Please specify device.\n");
516 } else if (argc
> 2) {
517 err("Too many command line arguments.\n");
524 if (!(dmt
= dm_task_create(DM_DEVICE_RELOAD
)))
527 if (!_set_task_device(dmt
, name
, 0))
530 if (!_switches
[NOTABLE_ARG
] && !_parse_file(dmt
, file
))
533 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
536 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
539 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
542 if (!dm_task_run(dmt
))
547 if (_switches
[VERBOSE_ARG
])
548 r
= _display_info(dmt
);
551 dm_task_destroy(dmt
);
556 static int _create(int argc
, char **argv
, void *data
__attribute((unused
)))
560 const char *file
= NULL
;
566 if (!(dmt
= dm_task_create(DM_DEVICE_CREATE
)))
569 if (!dm_task_set_name(dmt
, argv
[1]))
572 if (_switches
[UUID_ARG
] && !dm_task_set_uuid(dmt
, _uuid
))
575 if (!_switches
[NOTABLE_ARG
] && !_parse_file(dmt
, file
))
578 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
581 if (_switches
[MAJOR_ARG
] && !dm_task_set_major(dmt
, _int_args
[MAJOR_ARG
]))
584 if (_switches
[MINOR_ARG
] && !dm_task_set_minor(dmt
, _int_args
[MINOR_ARG
]))
587 if (_switches
[UID_ARG
] && !dm_task_set_uid(dmt
, _int_args
[UID_ARG
]))
590 if (_switches
[GID_ARG
] && !dm_task_set_gid(dmt
, _int_args
[GID_ARG
]))
593 if (_switches
[MODE_ARG
] && !dm_task_set_mode(dmt
, _int_args
[MODE_ARG
]))
596 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
599 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
602 if (_switches
[READAHEAD_ARG
] &&
603 !dm_task_set_read_ahead(dmt
, _int_args
[READAHEAD_ARG
],
607 if (_switches
[NOTABLE_ARG
])
608 dm_udev_set_sync_support(0);
610 if (!dm_task_set_cookie(dmt
, &cookie
, 0) ||
616 if (_switches
[VERBOSE_ARG
])
617 r
= _display_info(dmt
);
620 (void) dm_udev_wait(cookie
);
621 dm_task_destroy(dmt
);
626 static int _rename(int argc
, char **argv
, void *data
__attribute((unused
)))
632 if (!(dmt
= dm_task_create(DM_DEVICE_RENAME
)))
635 /* FIXME Kernel doesn't support uuid or device number here yet */
636 if (!_set_task_device(dmt
, (argc
== 3) ? argv
[1] : NULL
, 0))
639 if (!dm_task_set_newname(dmt
, argv
[argc
- 1]))
642 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
645 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
648 if (!dm_task_set_cookie(dmt
, &cookie
, 0) ||
655 (void) dm_udev_wait(cookie
);
656 dm_task_destroy(dmt
);
661 static int _message(int argc
, char **argv
, void *data
__attribute((unused
)))
668 if (!(dmt
= dm_task_create(DM_DEVICE_TARGET_MSG
)))
671 if (_switches
[UUID_ARG
] || _switches
[MAJOR_ARG
]) {
672 if (!_set_task_device(dmt
, NULL
, 0))
675 if (!_set_task_device(dmt
, argv
[1], 0))
681 if (!dm_task_set_sector(dmt
, (uint64_t) atoll(argv
[1])))
688 err("No message supplied.\n");
690 for (i
= 0; i
< argc
; i
++)
691 sz
+= strlen(argv
[i
]) + 1;
693 if (!(str
= dm_malloc(sz
))) {
694 err("message string allocation failed");
700 for (i
= 0; i
< argc
; i
++) {
703 strcat(str
, argv
[i
]);
706 if (!dm_task_set_message(dmt
, str
))
711 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
714 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
717 if (!dm_task_run(dmt
))
723 dm_task_destroy(dmt
);
728 static int _setgeometry(int argc
, char **argv
, void *data
__attribute((unused
)))
733 if (!(dmt
= dm_task_create(DM_DEVICE_SET_GEOMETRY
)))
736 if (_switches
[UUID_ARG
] || _switches
[MAJOR_ARG
]) {
737 if (!_set_task_device(dmt
, NULL
, 0))
740 if (!_set_task_device(dmt
, argv
[1], 0))
746 if (!dm_task_set_geometry(dmt
, argv
[1], argv
[2], argv
[3], argv
[4]))
749 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
752 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
756 if (!dm_task_run(dmt
))
762 dm_task_destroy(dmt
);
767 static int _splitname(int argc
, char **argv
, void *data
__attribute((unused
)))
769 struct dmsetup_report_obj obj
;
774 obj
.deps_task
= NULL
;
775 obj
.tree_node
= NULL
;
776 obj
.split_name
= _get_split_name((argc
== 3) ? argv
[2] : "LVM",
779 r
= dm_report_object(_report
, &obj
);
780 _destroy_split_name(obj
.split_name
);
785 static uint32_t _get_cookie_value(char *str_value
)
787 unsigned long int value
;
790 if (!(value
= strtoul(str_value
, &p
, 0)) ||
792 (value
== ULONG_MAX
&& errno
== ERANGE
) ||
793 value
> 0xFFFFFFFF) {
794 err("Incorrect cookie value");
798 return (uint32_t) value
;
801 static int _udevflags(int args
, char **argv
, void *data
__attribute((unused
)))
806 static const char *dm_flag_names
[] = {"DISABLE_DM_RULES",
807 "DISABLE_SUBSYSTEM_RULES",
808 "DISABLE_DISK_RULES",
809 "DISABLE_OTHER_RULES",
813 if (!(cookie
= _get_cookie_value(argv
[1])))
816 flags
= cookie
>> DM_UDEV_FLAGS_SHIFT
;
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)
824 * This is just a fallback. Each new DM flag
825 * should have its symbolic name assigned.
827 printf("DM_UDEV_FLAG%d='1'\n", i
);
830 * We can't assign symbolic names to subsystem
831 * flags. Their semantics vary based on the
832 * subsystem that is currently used.
834 printf("DM_SUBSYSTEM_UDEV_FLAG%d='1'\n",
835 i
- DM_UDEV_FLAGS_SHIFT
/ 2);
841 static int _udevcomplete(int argc
, char **argv
, void *data
__attribute((unused
)))
845 if (!(cookie
= _get_cookie_value(argv
[1])))
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
855 if (!(cookie
&= ~DM_UDEV_FLAGS_MASK
))
858 cookie
|= DM_COOKIE_MAGIC
<< DM_UDEV_FLAGS_SHIFT
;
860 return dm_udev_complete(cookie
);
863 #ifndef UDEV_SYNC_SUPPORT
864 static const char _cmd_not_supported
[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
866 static int _udevcomplete_all(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
868 log_error(_cmd_not_supported
);
873 static int _udevcookies(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
875 log_error(_cmd_not_supported
);
880 #else /* UDEV_SYNC_SUPPORT */
882 static char _yes_no_prompt(const char *prompt
, ...)
888 if (c
== '\n' || !c
) {
889 va_start(ap
, prompt
);
894 if ((c
= getchar()) == EOF
) {
900 if ((c
== 'y') || (c
== 'n'))
902 } while (!ret
|| c
!= '\n');
910 static int _udevcomplete_all(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
913 struct seminfo sinfo
;
914 struct semid_ds sdata
;
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
);
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
);
930 if ((max_id
= semctl(0, 0, SEM_INFO
, &sinfo
)) < 0) {
931 log_sys_error("semctl", "SEM_INFO");
935 for (id
= 0; id
<= max_id
; id
++) {
936 if ((sid
= semctl(id
, 0, SEM_STAT
, &sdata
)) < 0)
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
);
952 log_print("%d semaphores with keys prefixed by "
953 "%" PRIu16
" (0x%" PRIx16
") destroyed.",
954 counter
, DM_COOKIE_MAGIC
, DM_COOKIE_MAGIC
);
959 static int _udevcookies(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
962 struct seminfo sinfo
;
963 struct semid_ds sdata
;
967 if ((max_id
= semctl(0, 0, SEM_INFO
, &sinfo
)) < 0) {
968 log_sys_error("sem_ctl", "SEM_INFO");
972 printf("cookie semid value last_semop_time\n");
974 for (id
= 0; id
<= max_id
; id
++) {
975 if ((sid
= semctl(id
, 0, SEM_STAT
, &sdata
)) < 0)
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
,
987 time_str
= ctime((const time_t *) &sdata
.sem_otime
);
989 printf("0x%-10x %-10d %-10d %s", sdata
.sem_perm
.__key
,
990 sid
, val
, time_str
? time_str
: "unknown\n");
996 #endif /* UDEV_SYNC_SUPPORT */
998 static int _version(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
1002 if (dm_get_library_version(version
, sizeof(version
)))
1003 printf("Library version: %s\n", version
);
1005 if (!dm_driver_version(version
, sizeof(version
)))
1008 printf("Driver version: %s\n", version
);
1013 static int _simple(int task
, const char *name
, uint32_t event_nr
, int display
)
1015 uint32_t cookie
= 0;
1016 int udev_wait_flag
= task
== DM_DEVICE_RESUME
||
1017 task
== DM_DEVICE_REMOVE
;
1020 struct dm_task
*dmt
;
1022 if (!(dmt
= dm_task_create(task
)))
1025 if (!_set_task_device(dmt
, name
, 0))
1028 if (event_nr
&& !dm_task_set_event_nr(dmt
, event_nr
))
1031 if (_switches
[NOFLUSH_ARG
] && !dm_task_no_flush(dmt
))
1034 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1037 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1040 if (_switches
[NOLOCKFS_ARG
] && !dm_task_skip_lockfs(dmt
))
1043 if (_switches
[READAHEAD_ARG
] &&
1044 !dm_task_set_read_ahead(dmt
, _int_args
[READAHEAD_ARG
],
1048 if (udev_wait_flag
&& !dm_task_set_cookie(dmt
, &cookie
, 0))
1051 r
= dm_task_run(dmt
);
1053 if (r
&& display
&& _switches
[VERBOSE_ARG
])
1054 r
= _display_info(dmt
);
1058 (void) dm_udev_wait(cookie
);
1060 dm_task_destroy(dmt
);
1064 static int _suspend(int argc
, char **argv
, void *data
__attribute((unused
)))
1066 return _simple(DM_DEVICE_SUSPEND
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1069 static int _resume(int argc
, char **argv
, void *data
__attribute((unused
)))
1071 return _simple(DM_DEVICE_RESUME
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1074 static int _clear(int argc
, char **argv
, void *data
__attribute((unused
)))
1076 return _simple(DM_DEVICE_CLEAR
, argc
> 1 ? argv
[1] : NULL
, 0, 1);
1079 static int _wait(int argc
, char **argv
, void *data
__attribute((unused
)))
1081 const char *name
= NULL
;
1083 if (!_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
]) {
1085 err("No device specified.");
1092 return _simple(DM_DEVICE_WAITEVENT
, name
,
1093 (argc
> 1) ? (uint32_t) atoi(argv
[argc
- 1]) : 0, 1);
1096 static int _process_all(int argc
, char **argv
, int silent
,
1097 int (*fn
) (int argc
, char **argv
, void *data
))
1100 struct dm_names
*names
;
1103 struct dm_task
*dmt
;
1105 if (!(dmt
= dm_task_create(DM_DEVICE_LIST
)))
1108 if (!dm_task_run(dmt
)) {
1113 if (!(names
= dm_task_get_names(dmt
))) {
1120 printf("No devices found\n");
1125 names
= (void *) names
+ next
;
1126 if (!fn(argc
, argv
, (void *) names
))
1132 dm_task_destroy(dmt
);
1136 static uint64_t _get_device_size(const char *name
)
1138 uint64_t start
, length
, size
= UINT64_C(0);
1139 struct dm_info info
;
1140 char *target_type
, *params
;
1141 struct dm_task
*dmt
;
1144 if (!(dmt
= dm_task_create(DM_DEVICE_TABLE
)))
1147 if (!_set_task_device(dmt
, name
, 0))
1150 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1153 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1156 if (!dm_task_run(dmt
))
1159 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
1163 next
= dm_get_next_target(dmt
, next
, &start
, &length
,
1164 &target_type
, ¶ms
);
1169 dm_task_destroy(dmt
);
1173 static int _error_device(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
)
1175 struct dm_names
*names
= (struct dm_names
*) data
;
1176 struct dm_task
*dmt
;
1186 size
= _get_device_size(name
);
1188 if (!(dmt
= dm_task_create(DM_DEVICE_RELOAD
)))
1191 if (!_set_task_device(dmt
, name
, 0))
1194 if (!dm_task_add_target(dmt
, UINT64_C(0), size
, "error", ""))
1197 if (_switches
[READ_ONLY
] && !dm_task_set_ro(dmt
))
1200 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1203 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1206 if (!dm_task_run(dmt
))
1209 if (!_simple(DM_DEVICE_RESUME
, name
, 0, 0)) {
1210 _simple(DM_DEVICE_CLEAR
, name
, 0, 0);
1217 dm_task_destroy(dmt
);
1221 static int _remove(int argc
, char **argv
, void *data
__attribute((unused
)))
1225 if (_switches
[FORCE_ARG
] && argc
> 1)
1226 r
= _error_device(argc
, argv
, NULL
);
1228 return _simple(DM_DEVICE_REMOVE
, argc
> 1 ? argv
[1] : NULL
, 0, 0);
1231 static int _count_devices(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
1238 static int _remove_all(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
1242 /* Remove all closed devices */
1243 r
= _simple(DM_DEVICE_REMOVE_ALL
, "", 0, 0) | dm_mknodes(NULL
);
1245 if (!_switches
[FORCE_ARG
])
1249 r
|= _process_all(argc
, argv
, 1, _count_devices
);
1251 /* No devices left? */
1255 r
|= _process_all(argc
, argv
, 1, _error_device
);
1256 r
|= _simple(DM_DEVICE_REMOVE_ALL
, "", 0, 0) | dm_mknodes(NULL
);
1259 r
|= _process_all(argc
, argv
, 1, _count_devices
);
1263 fprintf(stderr
, "Unable to remove %d device(s).\n", _num_devices
);
1268 static void _display_dev(struct dm_task
*dmt
, const char *name
)
1270 struct dm_info info
;
1272 if (dm_task_get_info(dmt
, &info
))
1273 printf("%s\t(%u, %u)\n", name
, info
.major
, info
.minor
);
1276 static int _mknodes(int argc
, char **argv
, void *data
__attribute((unused
)))
1278 return dm_mknodes(argc
> 1 ? argv
[1] : NULL
);
1281 static int _exec_command(const char *name
)
1284 static char path
[PATH_MAX
];
1285 static char *args
[ARGS_MAX
+ 1];
1286 static int argc
= 0;
1293 if (!dm_mknodes(name
))
1296 n
= snprintf(path
, sizeof(path
), "%s/%s", dm_dir(), name
);
1297 if (n
< 0 || n
> (int) sizeof(path
) - 1)
1302 while (argc
< ARGS_MAX
) {
1303 while (*c
&& isspace(*c
))
1308 while (*c
&& !isspace(*c
))
1319 if (argc
== ARGS_MAX
) {
1320 err("Too many args to --exec\n");
1325 args
[argc
++] = path
;
1329 if (!(pid
= fork())) {
1330 execvp(args
[0], args
);
1332 } else if (pid
< (pid_t
) 0)
1335 TEMP_FAILURE_RETRY(waitpid(pid
, NULL
, 0));
1340 static int _status(int argc
, char **argv
, void *data
)
1343 struct dm_task
*dmt
;
1345 uint64_t start
, length
;
1346 char *target_type
= NULL
;
1349 struct dm_names
*names
= (struct dm_names
*) data
;
1350 const char *name
= NULL
;
1353 struct dm_info info
;
1358 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1359 return _process_all(argc
, argv
, 0, _status
);
1364 if (!strcmp(argv
[0], "table"))
1365 cmd
= DM_DEVICE_TABLE
;
1367 cmd
= DM_DEVICE_STATUS
;
1369 if (!strcmp(argv
[0], "ls"))
1372 if (!(dmt
= dm_task_create(cmd
)))
1375 if (!_set_task_device(dmt
, name
, 0))
1378 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1381 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1384 if (!dm_task_run(dmt
))
1387 if (!dm_task_get_info(dmt
, &info
) || !info
.exists
)
1391 name
= dm_task_get_name(dmt
);
1393 /* Fetch targets and print 'em */
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
)))
1402 if (!_switches
[EXEC_ARG
] || !_command
||
1403 _switches
[VERBOSE_ARG
])
1404 _display_dev(dmt
, name
);
1406 } else if (!_switches
[EXEC_ARG
] || !_command
||
1407 _switches
[VERBOSE_ARG
]) {
1408 if (!matched
&& _switches
[VERBOSE_ARG
])
1410 if (data
&& !_switches
[VERBOSE_ARG
])
1411 printf("%s: ", name
);
1413 /* Suppress encryption key */
1414 if (!_switches
[SHOWKEYS_ARG
] &&
1415 cmd
== DM_DEVICE_TABLE
&&
1416 !strcmp(target_type
, "crypt")) {
1418 while (*c
&& *c
!= ' ')
1422 while (*c
&& *c
!= ' ')
1425 printf("%" PRIu64
" %" PRIu64
" %s %s",
1426 start
, length
, target_type
, params
);
1433 if (data
&& _switches
[VERBOSE_ARG
] && matched
&& !ls_only
)
1436 if (matched
&& _switches
[EXEC_ARG
] && _command
&& !_exec_command(name
))
1442 dm_task_destroy(dmt
);
1446 /* Show target names and their version numbers */
1447 static int _targets(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
__attribute((unused
)))
1450 struct dm_task
*dmt
;
1451 struct dm_versions
*target
;
1452 struct dm_versions
*last_target
;
1454 if (!(dmt
= dm_task_create(DM_DEVICE_LIST_VERSIONS
)))
1457 if (!dm_task_run(dmt
))
1460 target
= dm_task_get_versions(dmt
);
1462 /* Fetch targets and print 'em */
1464 last_target
= target
;
1466 printf("%-16s v%d.%d.%d\n", target
->name
, target
->version
[0],
1467 target
->version
[1], target
->version
[2]);
1469 target
= (void *) target
+ target
->next
;
1470 } while (last_target
!= target
);
1475 dm_task_destroy(dmt
);
1479 static int _info(int argc
, char **argv
, void *data
)
1483 struct dm_task
*dmt
;
1484 struct dm_names
*names
= (struct dm_names
*) data
;
1490 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1491 return _process_all(argc
, argv
, 0, _info
);
1496 if (!(dmt
= dm_task_create(DM_DEVICE_INFO
)))
1499 if (!_set_task_device(dmt
, name
, 0))
1502 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1505 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1508 if (!dm_task_run(dmt
))
1511 r
= _display_info(dmt
);
1514 dm_task_destroy(dmt
);
1518 static int _deps(int argc
, char **argv
, void *data
)
1522 struct dm_deps
*deps
;
1523 struct dm_task
*dmt
;
1524 struct dm_info info
;
1525 struct dm_names
*names
= (struct dm_names
*) data
;
1531 if (argc
== 1 && !_switches
[UUID_ARG
] && !_switches
[MAJOR_ARG
])
1532 return _process_all(argc
, argv
, 0, _deps
);
1537 if (!(dmt
= dm_task_create(DM_DEVICE_DEPS
)))
1540 if (!_set_task_device(dmt
, name
, 0))
1543 if (_switches
[NOOPENCOUNT_ARG
] && !dm_task_no_open_count(dmt
))
1546 if (_switches
[INACTIVE_ARG
] && !dm_task_query_inactive_table(dmt
))
1549 if (!dm_task_run(dmt
))
1552 if (!dm_task_get_info(dmt
, &info
))
1555 if (!(deps
= dm_task_get_deps(dmt
)))
1559 printf("Device does not exist.\n");
1564 if (_switches
[VERBOSE_ARG
])
1567 if (data
&& !_switches
[VERBOSE_ARG
])
1568 printf("%s: ", name
);
1569 printf("%d dependencies\t:", deps
->count
);
1571 for (i
= 0; i
< deps
->count
; i
++)
1573 (int) MAJOR(deps
->device
[i
]),
1574 (int) MINOR(deps
->device
[i
]));
1577 if (data
&& _switches
[VERBOSE_ARG
])
1583 dm_task_destroy(dmt
);
1587 static int _display_name(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
)
1589 struct dm_names
*names
= (struct dm_names
*) data
;
1591 printf("%s\t(%d, %d)\n", names
->name
,
1592 (int) MAJOR(names
->dev
), (int) MINOR(names
->dev
));
1602 TR_DEVICE
=0, /* display device major:minor number */
1615 static int _tree_switches
[NUM_TREEMODE
];
1617 #define TR_PRINT_ATTRIBUTE ( _tree_switches[TR_ACTIVE] || \
1618 _tree_switches[TR_RW] || \
1619 _tree_switches[TR_OPENCOUNT] || \
1620 _tree_switches[TR_UUID] )
1622 #define TR_PRINT_TARGETS ( _tree_switches[TR_TABLE] || \
1623 _tree_switches[TR_STATUS] )
1625 /* Compact - fewer newlines */
1626 #define TR_PRINT_COMPACT (_tree_switches[TR_COMPACT] && \
1627 !TR_PRINT_ATTRIBUTE && \
1630 /* FIXME Get rid of this */
1631 #define MAX_DEPTH 100
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 */
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 */
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
; /* -+- */
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
1681 *_tsym
= &_tsym_ascii
;
1684 * Tree drawing functions.
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;
1693 static void _out_char(const unsigned c
)
1695 /* Only first UTF-8 char counts */
1696 _cur_x
+= ((c
& 0xc0) != 0x80);
1698 if (!_tree_switches
[TR_TRUNCATE
]) {
1704 if (_cur_x
<= _termwidth
)
1707 if (_cur_x
== _termwidth
+ 1 && ((c
& 0xc0) != 0x80)) {
1708 if (_last_char
|| (c
& 0x80)) {
1719 static void _out_string(const char *str
)
1722 _out_char((unsigned char) *str
++);
1725 /* non-negative integers only */
1726 static unsigned _out_int(unsigned num
)
1728 unsigned digits
= 0;
1737 for (divi
= 1; num
/ divi
; divi
*= 10)
1740 for (divi
/= 10; divi
; divi
/= 10)
1741 _out_char('0' + (num
/ divi
) % 10);
1746 static void _out_newline(void)
1748 if (_last_char
&& _cur_x
== _termwidth
)
1749 putchar(_last_char
);
1755 static void _out_prefix(unsigned depth
)
1759 for (d
= 0; d
< depth
; d
++) {
1760 for (x
= _tree_width
[d
] + 1; x
> 0; x
--)
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
);
1773 static void _display_tree_attributes(struct dm_tree_node
*node
)
1777 const struct dm_info
*info
;
1779 uuid
= dm_tree_node_get_uuid(node
);
1780 info
= dm_tree_node_get_info(node
);
1785 if (_tree_switches
[TR_ACTIVE
]) {
1786 _out_string(attr
++ ? ", " : " [");
1787 _out_string(info
->suspended
? "SUSPENDED" : "ACTIVE");
1790 if (_tree_switches
[TR_RW
]) {
1791 _out_string(attr
++ ? ", " : " [");
1792 _out_string(info
->read_only
? "RO" : "RW");
1795 if (_tree_switches
[TR_OPENCOUNT
]) {
1796 _out_string(attr
++ ? ", " : " [");
1797 (void) _out_int((unsigned) info
->open_count
);
1800 if (_tree_switches
[TR_UUID
]) {
1801 _out_string(attr
++ ? ", " : " [");
1802 _out_string(uuid
&& *uuid
? uuid
: "");
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
)
1815 const struct dm_info
*info
;
1816 int first_on_line
= 0;
1818 /* Sub-tree for targets has 2 more depth */
1819 if (depth
+ 2 > MAX_DEPTH
)
1822 name
= dm_tree_node_get_name(node
);
1824 if ((!name
|| !*name
) && !_tree_switches
[TR_DEVICE
])
1827 /* Indicate whether there are more nodes at this depth */
1828 _tree_more
[depth
] = !last_child
;
1829 _tree_width
[depth
] = 0;
1834 if (!TR_PRINT_COMPACT
|| first_on_line
)
1837 /* Remember the starting point for compact */
1840 if (TR_PRINT_COMPACT
&& !first_on_line
)
1841 _out_string(_tree_more
[depth
] ? _tsym
->first_3
: _tsym
->single_3
);
1847 info
= dm_tree_node_get_info(node
);
1849 if (_tree_switches
[TR_DEVICE
]) {
1850 _out_string(name
? " (" : "(");
1851 (void) _out_int(info
->major
);
1853 (void) _out_int(info
->minor
);
1857 /* display additional info */
1858 if (TR_PRINT_ATTRIBUTE
)
1859 _display_tree_attributes(node
);
1861 if (TR_PRINT_COMPACT
)
1862 _tree_width
[depth
] = _cur_x
- offset
;
1864 if (!TR_PRINT_COMPACT
|| !has_children
)
1867 if (TR_PRINT_TARGETS
) {
1868 _tree_more
[depth
+ 1] = has_children
;
1869 // FIXME _display_tree_targets(name, depth + 2);
1874 * Walk the dependency tree
1876 static void _display_tree_walk_children(struct dm_tree_node
*node
,
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
;
1885 next_child
= dm_tree_next_child(&handle
, node
, inverted
);
1887 while ((child
= next_child
)) {
1888 next_child
= dm_tree_next_child(&handle
, node
, inverted
);
1890 dm_tree_node_num_children(child
, inverted
) ? 1 : 0;
1892 _display_tree_node(child
, depth
, first_child
,
1893 next_child
? 0U : 1U, has_children
);
1896 _display_tree_walk_children(child
, depth
+ 1);
1902 static int _add_dep(int argc
__attribute((unused
)), char **argv
__attribute((unused
)), void *data
)
1904 struct dm_names
*names
= (struct dm_names
*) data
;
1906 if (!dm_tree_add_dev(_dtree
, (unsigned) MAJOR(names
->dev
), (unsigned) MINOR(names
->dev
)))
1913 * Create and walk dependency tree
1915 static int _build_whole_deptree(void)
1920 if (!(_dtree
= dm_tree_create()))
1923 if (!_process_all(0, NULL
, 0, _add_dep
))
1929 static int _display_tree(int argc
__attribute((unused
)),
1930 char **argv
__attribute((unused
)),
1931 void *data
__attribute((unused
)))
1933 if (!_build_whole_deptree())
1936 _display_tree_walk_children(dm_tree_find_node(_dtree
, 0, 0), 0);
1942 * Report device information
1945 /* dm specific display functions */
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
)))
1952 const int32_t value
= *(const int32_t *)data
;
1954 return dm_report_field_int32(rh
, field
, &value
);
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
)))
1962 const uint32_t value
= *(const int32_t *)data
;
1964 return dm_report_field_uint32(rh
, field
, &value
);
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
)))
1972 const char *name
= dm_task_get_name((const struct dm_task
*) data
);
1974 return dm_report_field_string(rh
, field
, &name
);
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
)))
1982 const char *uuid
= dm_task_get_uuid((const struct dm_task
*) data
);
1984 if (!uuid
|| !*uuid
)
1987 return dm_report_field_string(rh
, field
, &uuid
);
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
)))
1997 if (!dm_task_get_read_ahead((const struct dm_task
*) data
, &value
))
2000 return dm_report_field_uint32(rh
, field
, &value
);
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
)))
2009 const char *s
= buf
;
2010 const struct dm_info
*info
= data
;
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';
2018 return dm_report_field_string(rh
, field
, &s
);
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
,
2025 void *private __attribute((unused
)))
2027 const struct dm_info
*info
= data
;
2029 if (info
->live_table
) {
2030 if (info
->inactive_table
)
2031 dm_report_field_set_value(field
, "Both", NULL
);
2033 dm_report_field_set_value(field
, "Live", NULL
);
2037 if (info
->inactive_table
)
2038 dm_report_field_set_value(field
, "Inactive", NULL
);
2040 dm_report_field_set_value(field
, "None", NULL
);
2045 static int _dm_info_suspended_disp(struct dm_report
*rh
,
2046 struct dm_pool
*mem
__attribute((unused
)),
2047 struct dm_report_field
*field
,
2049 void *private __attribute((unused
)))
2051 const struct dm_info
*info
= data
;
2053 if (info
->suspended
)
2054 dm_report_field_set_value(field
, "Suspended", NULL
);
2056 dm_report_field_set_value(field
, "Active", NULL
);
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
,
2065 void *private __attribute((unused
)))
2067 const struct dm_info
*info
= data
;
2069 if (info
->read_only
)
2070 dm_report_field_set_value(field
, "Read-only", NULL
);
2072 dm_report_field_set_value(field
, "Writeable", NULL
);
2078 static int _dm_info_devno_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2079 struct dm_report_field
*field
, const void *data
,
2082 char buf
[DM_MAX_TYPE_NAME
], *repstr
;
2083 struct dm_info
*info
= (struct dm_info
*) data
;
2085 if (!dm_pool_begin_object(mem
, 8)) {
2086 log_error("dm_pool_begin_object failed");
2090 if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2091 info
->major
, info
->minor
) < 0) {
2092 log_error("dm_pool_alloc failed");
2096 if (!dm_pool_grow_object(mem
, buf
, strlen(buf
) + 1)) {
2097 log_error("dm_pool_grow_object failed");
2101 repstr
= dm_pool_end_object(mem
);
2102 dm_report_field_set_value(field
, repstr
, repstr
);
2106 dm_pool_abandon_object(mem
);
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
)
2114 struct dm_tree_node
*node
= (struct dm_tree_node
*) data
, *parent
;
2120 if (!dm_pool_begin_object(mem
, 16)) {
2121 log_error("dm_pool_begin_object failed");
2125 while ((parent
= dm_tree_next_child(&t
, node
, inverted
))) {
2126 name
= dm_tree_node_get_name(parent
);
2127 if (!name
|| !*name
)
2129 if (!first_node
&& !dm_pool_grow_object(mem
, ",", 1)) {
2130 log_error("dm_pool_grow_object failed");
2133 if (!dm_pool_grow_object(mem
, name
, 0)) {
2134 log_error("dm_pool_grow_object failed");
2141 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2142 log_error("dm_pool_grow_object failed");
2146 repstr
= dm_pool_end_object(mem
);
2147 dm_report_field_set_value(field
, repstr
, repstr
);
2151 dm_pool_abandon_object(mem
);
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)
2160 return _dm_tree_names(rh
, mem
, field
, data
, private, 0);
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)
2168 return _dm_tree_names(rh
, mem
, field
, data
, private, 1);
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)
2175 struct dm_tree_node
*node
= (struct dm_tree_node
*) data
, *parent
;
2177 const struct dm_info
*info
;
2179 char buf
[DM_MAX_TYPE_NAME
], *repstr
;
2181 if (!dm_pool_begin_object(mem
, 16)) {
2182 log_error("dm_pool_begin_object failed");
2186 while ((parent
= dm_tree_next_child(&t
, node
, 1))) {
2187 info
= dm_tree_node_get_info(parent
);
2188 if (!info
->major
&& !info
->minor
)
2190 if (!first_node
&& !dm_pool_grow_object(mem
, ",", 1)) {
2191 log_error("dm_pool_grow_object failed");
2194 if (dm_snprintf(buf
, sizeof(buf
), "%d:%d",
2195 info
->major
, info
->minor
) < 0) {
2196 log_error("dm_snprintf failed");
2199 if (!dm_pool_grow_object(mem
, buf
, 0)) {
2200 log_error("dm_pool_grow_object failed");
2207 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2208 log_error("dm_pool_grow_object failed");
2212 repstr
= dm_pool_end_object(mem
);
2213 dm_report_field_set_value(field
, repstr
, repstr
);
2217 dm_pool_abandon_object(mem
);
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)
2226 struct dm_tree_node
*node
= (struct dm_tree_node
*) data
;
2227 int num_parent
= dm_tree_node_num_children(node
, 1);
2229 return dm_report_field_int(rh
, field
, &num_parent
);
2232 static int _dm_deps_disp(struct dm_report
*rh
, struct dm_pool
*mem
,
2233 struct dm_report_field
*field
, const void *data
,
2236 struct dm_deps
*deps
= (struct dm_deps
*) data
;
2238 char buf
[DM_MAX_TYPE_NAME
], *repstr
;
2240 if (!dm_pool_begin_object(mem
, 16)) {
2241 log_error("dm_pool_begin_object failed");
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");
2252 if (!dm_pool_grow_object(mem
, buf
, 0)) {
2253 log_error("dm_pool_grow_object failed");
2256 if (i
+ 1 < deps
->count
&& !dm_pool_grow_object(mem
, ",", 1)) {
2257 log_error("dm_pool_grow_object failed");
2262 if (!dm_pool_grow_object(mem
, "\0", 1)) {
2263 log_error("dm_pool_grow_object failed");
2267 repstr
= dm_pool_end_object(mem
);
2268 dm_report_field_set_value(field
, repstr
, repstr
);
2272 dm_pool_abandon_object(mem
);
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
)))
2281 return dm_report_field_string(rh
, field
, (const char **) data
);
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
)))
2290 return dm_report_field_string(rh
, field
, (const char **) data
);
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
)))
2299 return dm_report_field_string(rh
, field
, (const char **) data
);
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
)))
2308 return dm_report_field_string(rh
, field
, (const char **) data
);
2311 static void *_task_get_obj(void *obj
)
2313 return ((struct dmsetup_report_obj
*)obj
)->task
;
2316 static void *_info_get_obj(void *obj
)
2318 return ((struct dmsetup_report_obj
*)obj
)->info
;
2321 static void *_deps_get_obj(void *obj
)
2323 return dm_task_get_deps(((struct dmsetup_report_obj
*)obj
)->deps_task
);
2326 static void *_tree_get_obj(void *obj
)
2328 return ((struct dmsetup_report_obj
*)obj
)->tree_node
;
2331 static void *_split_name_get_obj(void *obj
)
2333 return ((struct dmsetup_report_obj
*)obj
)->split_name
;
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
},
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},
2352 static const struct dm_report_field_type _report_fields
[] = {
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.")
2357 /* FIXME Next one should be INFO */
2358 FIELD_F(TASK
, NUM
, "RAhead", 6, dm_read_ahead
, "read_ahead", "Read ahead in sectors.")
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.")
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.")
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.")
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.")
2384 {0, 0, 0, 0, "", "", NULL
, NULL
},
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";
2396 static int _report_init(struct command
*c
)
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;
2407 if (!strcmp(c
->name
, "splitname"))
2408 options
= (char *) splitname_report_options
;
2410 /* emulate old dmsetup behaviour */
2411 if (_switches
[NOHEADINGS_ARG
]) {
2417 if (_switches
[UNBUFFERED_ARG
])
2420 if (_switches
[ROWS_ARG
])
2421 columns_as_rows
= 1;
2423 if (_switches
[UNQUOTED_ARG
])
2426 if (_switches
[NAMEPREFIXES_ARG
]) {
2431 if (_switches
[OPTIONS_ARG
] && _string_args
[OPTIONS_ARG
]) {
2432 if (*_string_args
[OPTIONS_ARG
] != '+')
2433 options
= _string_args
[OPTIONS_ARG
];
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.");
2441 if (dm_snprintf(options
, len
, "%s,%s",
2442 default_report_options
,
2443 &_string_args
[OPTIONS_ARG
][1]) < 0) {
2444 err("snprintf failed");
2450 if (_switches
[SORT_ARG
] && _string_args
[SORT_ARG
]) {
2451 keys
= _string_args
[SORT_ARG
];
2453 if (c
&& (!strcmp(c
->name
, "status") || !strcmp(c
->name
, "table"))) {
2454 err("--sort is not yet supported with status and table");
2459 if (_switches
[SEPARATOR_ARG
] && _string_args
[SEPARATOR_ARG
]) {
2460 separator
= _string_args
[SEPARATOR_ARG
];
2465 flags
|= DM_REPORT_OUTPUT_ALIGNED
;
2468 flags
|= DM_REPORT_OUTPUT_BUFFERED
;
2471 flags
|= DM_REPORT_OUTPUT_HEADINGS
;
2474 flags
|= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
;
2477 flags
|= DM_REPORT_OUTPUT_FIELD_UNQUOTED
;
2479 if (columns_as_rows
)
2480 flags
|= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS
;
2482 if (!(_report
= dm_report_init(&_report_type
,
2483 _report_types
, _report_fields
,
2484 options
, separator
, flags
, keys
, NULL
)))
2487 if ((_report_type
& DR_TREE
) && !_build_whole_deptree()) {
2488 err("Internal device dependency tree creation failed.");
2493 dm_report_set_output_field_name_prefix(_report
, "dm_");
2507 static int _ls(int argc
, char **argv
, void *data
)
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
);
2515 return _process_all(argc
, argv
, 0, _display_name
);
2518 static int _help(int argc
, char **argv
, void *data
);
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>]",
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
}
2557 static void _usage(FILE *out
)
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");
2579 static void _losetup_usage(FILE *out
)
2581 fprintf(out
, "Usage:\n\n");
2582 fprintf(out
, "losetup [-d|-a] [-e encryption] "
2583 "[-o offset] [-f|loop_device] [file]\n\n");
2586 static int _help(int argc
__attribute((unused
)),
2587 char **argv
__attribute((unused
)),
2588 void *data
__attribute((unused
)))
2592 if (_switches
[COLS_ARG
]) {
2593 _switches
[OPTIONS_ARG
] = 1;
2594 _string_args
[OPTIONS_ARG
] = (char *) "help";
2595 _switches
[SORT_ARG
] = 0;
2597 (void) _report_init(NULL
);
2603 static struct command
*_find_command(const char *name
)
2607 for (i
= 0; _commands
[i
].name
; i
++)
2608 if (!strcmp(_commands
[i
].name
, name
))
2609 return _commands
+ i
;
2614 static int _process_tree_options(const char *options
)
2616 const char *s
, *end
;
2617 struct winsize winsz
;
2620 /* Symbol set default */
2621 if (!strcmp(nl_langinfo(CODESET
), "UTF-8"))
2624 _tsym
= &_tsym_ascii
;
2627 _tree_switches
[TR_DEVICE
] = 1;
2628 _tree_switches
[TR_TRUNCATE
] = 1;
2631 for (s
= options
; s
&& *s
; s
++) {
2633 for (end
= s
; *end
&& *end
!= ','; end
++, len
++)
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
))
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;
2664 fprintf(stderr
, "Tree options not recognised: %s\n", s
);
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;
2681 * Returns the full absolute path, or NULL if the path could
2684 static char *_get_abspath(const char *path
)
2688 #ifdef HAVE_CANONICALIZE_FILE_NAME
2689 _path
= canonicalize_file_name(path
);
2691 /* FIXME Provide alternative */
2696 static char *parse_loop_device_name(const char *dev
, const char *dev_dir
)
2701 if (!(buf
= dm_malloc(PATH_MAX
)))
2704 if (dev
[0] == '/') {
2705 if (!(device
= _get_abspath(dev
)))
2708 if (strncmp(device
, dev_dir
, strlen(dev_dir
)))
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
)] != '/')
2717 strncpy(buf
, strrchr(device
, '/') + 1, (size_t) PATH_MAX
);
2721 /* check for device number */
2722 if (!strncmp(dev
, "loop", strlen("loop")))
2723 strncpy(buf
, dev
, (size_t) PATH_MAX
);
2735 * create a table for a mapped device using the loop target.
2737 static int _loop_table(char *table
, size_t tlen
, char *file
,
2738 char *dev
__attribute((unused
)), off_t off
)
2741 off_t size
, sectors
;
2743 #ifdef HAVE_SYS_STATVFS_H
2744 struct statvfs fsbuf
;
2748 if (!_switches
[READ_ONLY
])
2749 fd
= open(file
, O_RDWR
);
2752 _switches
[READ_ONLY
]++;
2753 fd
= open(file
, O_RDONLY
);
2759 if (fstat(fd
, &fbuf
))
2762 size
= (fbuf
.st_size
- off
);
2763 sectors
= size
>> SECTOR_SHIFT
;
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
);
2770 #ifdef HAVE_SYS_STATVFS_H
2771 if (fstatvfs(fd
, &fsbuf
))
2774 /* FIXME Fragment size currently unused */
2775 blksize
= fsbuf
.f_frsize
;
2780 if (dm_snprintf(table
, tlen
, "%llu %llu loop %s %llu\n", 0ULL,
2781 (long long unsigned)sectors
, file
, off
) < 0)
2784 if (_switches
[VERBOSE_ARG
] > 1)
2785 fprintf(stderr
, "Table: %s\n", table
);
2795 static int _process_losetup_switches(const char *base
, int *argc
, char ***argv
,
2796 const char *dev_dir
)
2800 int encrypt_loop
= 0, delete = 0, find
= 0, show_all
= 0;
2801 char *device_name
= NULL
;
2802 char *loop_file
= NULL
;
2805 #ifdef HAVE_GETOPTLONG
2806 static struct option long_options
[] = {
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
== '?')
2826 offset
= atoi(optarg
);
2828 _switches
[VERBOSE_ARG
]++;
2835 fprintf(stderr
, "%s: Sorry, cryptoloop is not yet implemented "
2836 "in this version.\n", base
);
2841 fprintf(stderr
, "%s: Sorry, show all is not yet implemented "
2842 "in this version.\n", base
);
2847 fprintf(stderr
, "%s: Sorry, find is not yet implemented "
2848 "in this version.\n", base
);
2854 fprintf(stderr
, "%s: Please specify loop_device.\n", base
);
2855 _losetup_usage(stderr
);
2859 if (!(device_name
= parse_loop_device_name((*argv
)[0], dev_dir
))) {
2860 fprintf(stderr
, "%s: Could not parse loop_device %s\n",
2862 _losetup_usage(stderr
);
2869 (*argv
)[1] = device_name
;
2870 (*argv
)[0] = (char *) "remove";
2876 fprintf(stderr
, "%s: Too few arguments\n", base
);
2877 _losetup_usage(stderr
);
2878 dm_free(device_name
);
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",
2886 _losetup_usage(stderr
);
2887 dm_free(device_name
);
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
);
2898 _switches
[TABLE_ARG
]++;
2900 (*argv
)[0] = (char *) "create";
2901 (*argv
)[1] = device_name
;
2906 static int _process_switches(int *argc
, char ***argv
, const char *dev_dir
)
2908 char *base
, *namebase
, *s
;
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
},
2949 struct option long_options
;
2953 * Zero all the index counts.
2955 memset(&_switches
, 0, sizeof(_switches
));
2956 memset(&_int_args
, 0, sizeof(_int_args
));
2957 _read_ahead_flags
= 0;
2959 namebase
= strdup((*argv
)[0]);
2960 base
= basename(namebase
);
2962 if (!strcmp(base
, "devmap_name")) {
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";
2972 _int_args
[MAJOR_ARG
] = atoi((*argv
)[1]);
2973 _int_args
[MINOR_ARG
] = atoi((*argv
)[2]);
2976 } else if ((*argc
== 2) &&
2977 (2 == sscanf((*argv
)[1], "%i:%i",
2978 &_int_args
[MAJOR_ARG
],
2979 &_int_args
[MINOR_ARG
]))) {
2983 fprintf(stderr
, "Usage: devmap_name <major> <minor>\n");
2987 (*argv
)[0] = (char *) "info";
2991 if (!strcmp(base
, "losetup") || !strcmp(base
, "dmlosetup")){
2992 r
= _process_losetup_switches(base
, argc
, argv
, dev_dir
);
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
== '?')
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
);
3015 if (c
== 'm' || ind
== MINOR_ARG
) {
3016 _switches
[MINOR_ARG
]++;
3017 _int_args
[MINOR_ARG
] = atoi(optarg
);
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
;
3025 if (ind
== SEPARATOR_ARG
) {
3026 _switches
[SEPARATOR_ARG
]++;
3027 _string_args
[SEPARATOR_ARG
] = optarg
;
3029 if (c
== 'O' || ind
== SORT_ARG
) {
3030 _switches
[SORT_ARG
]++;
3031 _string_args
[SORT_ARG
] = optarg
;
3033 if (c
== 'v' || ind
== VERBOSE_ARG
)
3034 _switches
[VERBOSE_ARG
]++;
3035 if (c
== 'u' || ind
== UUID_ARG
) {
3036 _switches
[UUID_ARG
]++;
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
);
3047 if (c
== 'U' || ind
== UID_ARG
) {
3048 _switches
[UID_ARG
]++;
3049 _int_args
[UID_ARG
] = atoi(optarg
);
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);
3056 if ((ind
== EXEC_ARG
)) {
3057 _switches
[EXEC_ARG
]++;
3060 if ((ind
== TARGET_ARG
)) {
3061 _switches
[TARGET_ARG
]++;
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
;
3083 for (s
= optarg
; isspace(*s
); 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
]);
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
]++;
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
]++;
3112 if (_switches
[VERBOSE_ARG
] > 1)
3113 dm_log_init_verbose(_switches
[VERBOSE_ARG
] - 1);
3115 if ((_switches
[MAJOR_ARG
] && !_switches
[MINOR_ARG
]) ||
3116 (!_switches
[MAJOR_ARG
] && _switches
[MINOR_ARG
])) {
3117 fprintf(stderr
, "Please specify both major number and "
3122 if (_switches
[TREE_ARG
] && !_process_tree_options(_string_args
[OPTIONS_ARG
]))
3125 if (_switches
[TABLE_ARG
] && _switches
[NOTABLE_ARG
]) {
3126 fprintf(stderr
, "--table and --notable are incompatible.\n");
3135 int main(int argc
, char **argv
)
3139 const char *dev_dir
;
3141 (void) setlocale(LC_ALL
, "");
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");
3150 dev_dir
= DEFAULT_DM_DEV_DIR
;
3152 if (!_process_switches(&argc
, &argv
, dev_dir
)) {
3153 fprintf(stderr
, "Couldn't process command line.\n");
3157 if (_switches
[VERSION_ARG
]) {
3158 c
= _find_command("version");
3167 if (!(c
= _find_command(argv
[0]))) {
3168 fprintf(stderr
, "Unknown command\n");
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");
3180 if (!_switches
[COLS_ARG
] && !strcmp(c
->name
, "splitname"))
3181 _switches
[COLS_ARG
]++;
3183 if (_switches
[COLS_ARG
] && !_report_init(c
))
3186 if (_switches
[NOUDEVSYNC_ARG
])
3187 dm_udev_set_sync_support(0);
3190 if (!c
->fn(argc
, argv
, NULL
)) {
3191 fprintf(stderr
, "Command failed\n");
3199 dm_report_output(_report
);
3200 dm_report_free(_report
);
3204 dm_tree_free(_dtree
);