📄 dmsetup.c
字号:
/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2005-2007 NEC Corporation * * This file is part of the device-mapper userspace tools. * * It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/ * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#define _GNU_SOURCE#define _FILE_OFFSET_BITS 64#include "configure.h"#include "libdevmapper.h"#include "log.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <dirent.h>#include <errno.h>#include <unistd.h>#include <libgen.h>#include <sys/wait.h>#include <unistd.h>#include <sys/param.h>#include <locale.h>#include <langinfo.h>#include <fcntl.h>#include <sys/stat.h>/* FIXME Unused so far */#undef HAVE_SYS_STATVFS_H#ifdef HAVE_SYS_STATVFS_H# include <sys/statvfs.h>#endif#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#if HAVE_TERMIOS_H# include <termios.h>#endif#ifdef HAVE_GETOPTLONG# include <getopt.h># define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))# define OPTIND_INIT 0#elsestruct option {};extern int optind;extern char *optarg;# define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))# define OPTIND_INIT 1#endif#ifndef TEMP_FAILURE_RETRY# define TEMP_FAILURE_RETRY(expression) \ (__extension__ \ ({ long int __result; \ do __result = (long int) (expression); \ while (__result == -1L && errno == EINTR); \ __result; }))#endif#ifdef linux# include "kdev_t.h"#else# define MAJOR(x) major((x))# define MINOR(x) minor((x))# define MKDEV(x,y) makedev((x),(y))#endif#define LINE_SIZE 4096#define ARGS_MAX 256#define LOOP_TABLE_SIZE (PATH_MAX + 255)/* FIXME Should be imported */#ifndef DM_MAX_TYPE_NAME# define DM_MAX_TYPE_NAME 16#endif/* FIXME Should be elsewhere */#define SECTOR_SHIFT 9L#define DEV_PATH "/dev/"#define err(msg, x...) fprintf(stderr, msg "\n", ##x)/* * We have only very simple switches ATM. */enum { READ_ONLY = 0, COLS_ARG, EXEC_ARG, FORCE_ARG, GID_ARG, MAJOR_ARG, MINOR_ARG, MODE_ARG, NOFLUSH_ARG, NOHEADINGS_ARG, NOLOCKFS_ARG, NOOPENCOUNT_ARG, NOTABLE_ARG, OPTIONS_ARG, SEPARATOR_ARG, SHOWKEYS_ARG, SORT_ARG, TABLE_ARG, TARGET_ARG, TREE_ARG, UID_ARG, UNBUFFERED_ARG, UUID_ARG, VERBOSE_ARG, VERSION_ARG, NUM_SWITCHES};typedef enum { DR_TASK = 1, DR_INFO = 2, DR_DEPS = 4, DR_TREE = 8 /* Complete dependency tree required */} report_type_t;static int _switches[NUM_SWITCHES];static int _int_args[NUM_SWITCHES];static char *_string_args[NUM_SWITCHES];static int _num_devices;static char *_uuid;static char *_table;static char *_target;static char *_command;static struct dm_tree *_dtree;static struct dm_report *_report;static report_type_t _report_type;/* * Commands */typedef int (*command_fn) (int argc, char **argv, void *data);struct command { const char *name; const char *help; int min_args; int max_args; command_fn fn;};static int _parse_line(struct dm_task *dmt, char *buffer, const char *file, int line){ char ttype[LINE_SIZE], *ptr, *comment; unsigned long long start, size; int n; /* trim trailing space */ for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr--) if (!isspace((int) *ptr)) break; ptr++; *ptr = '\0'; /* trim leading space */ for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++) ; if (!*ptr || *ptr == '#') return 1; if (sscanf(ptr, "%llu %llu %s %n", &start, &size, ttype, &n) < 3) { err("Invalid format on line %d of table %s", line, file); return 0; } ptr += n; if ((comment = strchr(ptr, (int) '#'))) *comment = '\0'; if (!dm_task_add_target(dmt, start, size, ttype, ptr)) return 0; return 1;}static int _parse_file(struct dm_task *dmt, const char *file){ char *buffer = NULL; size_t buffer_size = 0; FILE *fp; int r = 0, line = 0; /* one-line table on cmdline */ if (_table) return _parse_line(dmt, _table, "", ++line); /* OK for empty stdin */ if (file) { if (!(fp = fopen(file, "r"))) { err("Couldn't open '%s' for reading", file); return 0; } } else fp = stdin;#ifndef HAVE_GETLINE buffer_size = LINE_SIZE; if (!(buffer = dm_malloc(buffer_size))) { err("Failed to malloc line buffer."); return 0; } while (fgets(buffer, (int) buffer_size, fp))#else while (getline(&buffer, &buffer_size, fp) > 0)#endif if (!_parse_line(dmt, buffer, file ? : "on stdin", ++line)) goto out; r = 1; out:#ifndef HAVE_GETLINE dm_free(buffer);#else free(buffer);#endif if (file && fclose(fp)) fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno)); return r;}struct dmsetup_report_obj { struct dm_task *task; struct dm_info *info; struct dm_task *deps_task; struct dm_tree_node *tree_node;};static struct dm_task *_get_deps_task(int major, int minor){ struct dm_task *dmt; struct dm_info info; if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) return NULL; if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) goto err; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto err; if (!dm_task_run(dmt)) goto err; if (!dm_task_get_info(dmt, &info)) goto err; if (!info.exists) goto err; return dmt; err: dm_task_destroy(dmt); return NULL;}static int _display_info_cols(struct dm_task *dmt, struct dm_info *info){ struct dmsetup_report_obj obj; int r = 0; if (!info->exists) { fprintf(stderr, "Device does not exist.\n"); return 0; } obj.task = dmt; obj.info = info; obj.deps_task = NULL; if (_report_type & DR_TREE) obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor); if (_report_type & DR_DEPS) obj.deps_task = _get_deps_task(info->major, info->minor); if (!dm_report_object(_report, &obj)) goto out; r = 1; out: if (obj.deps_task) dm_task_destroy(obj.deps_task); return r;}static void _display_info_long(struct dm_task *dmt, struct dm_info *info){ const char *uuid; if (!info->exists) { printf("Device does not exist.\n"); return; } printf("Name: %s\n", dm_task_get_name(dmt)); printf("State: %s%s\n", info->suspended ? "SUSPENDED" : "ACTIVE", info->read_only ? " (READ-ONLY)" : ""); if (!info->live_table && !info->inactive_table) printf("Tables present: None\n"); else printf("Tables present: %s%s%s\n", info->live_table ? "LIVE" : "", info->live_table && info->inactive_table ? " & " : "", info->inactive_table ? "INACTIVE" : ""); if (info->open_count != -1) printf("Open count: %d\n", info->open_count); printf("Event number: %" PRIu32 "\n", info->event_nr); printf("Major, minor: %d, %d\n", info->major, info->minor); if (info->target_count != -1) printf("Number of targets: %d\n", info->target_count); if ((uuid = dm_task_get_uuid(dmt)) && *uuid) printf("UUID: %s\n", uuid); printf("\n");}static int _display_info(struct dm_task *dmt){ struct dm_info info; if (!dm_task_get_info(dmt, &info)) return 0; if (!_switches[COLS_ARG]) _display_info_long(dmt, &info); else /* FIXME return code */ _display_info_cols(dmt, &info); return info.exists ? 1 : 0;}static int _set_task_device(struct dm_task *dmt, const char *name, int optional){ if (name) { if (!dm_task_set_name(dmt, name)) return 0; } else if (_switches[UUID_ARG]) { if (!dm_task_set_uuid(dmt, _uuid)) return 0; } else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) { if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) || !dm_task_set_minor(dmt, _int_args[MINOR_ARG])) return 0; } else if (!optional) { fprintf(stderr, "No device specified.\n"); return 0; } return 1;}static int _load(int argc, char **argv, void *data __attribute((unused))){ int r = 0; struct dm_task *dmt; const char *file = NULL; const char *name = NULL; if (_switches[NOTABLE_ARG]) { err("--notable only available when creating new device\n"); return 0; } if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (argc == 1) { err("Please specify device.\n"); return 0; } name = argv[1]; argc--; argv++; } else if (argc > 2) { err("Too many command line arguments.\n"); return 0; } if (argc == 2) file = argv[1]; if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) return 0; if (!_set_task_device(dmt, name, 0)) goto out; if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file)) goto out; if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = 1; if (_switches[VERBOSE_ARG]) r = _display_info(dmt); out: dm_task_destroy(dmt); return r;}static int _create(int argc, char **argv, void *data __attribute((unused))){ int r = 0; struct dm_task *dmt; const char *file = NULL; if (argc == 3) file = argv[2]; if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) return 0; if (!dm_task_set_name(dmt, argv[1])) goto out; if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid)) goto out; if (!_switches[NOTABLE_ARG] && !_parse_file(dmt, file)) goto out; if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) goto out; if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG])) goto out; if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG])) goto out; if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG])) goto out; if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG])) goto out; if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG])) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = 1; if (_switches[VERBOSE_ARG]) r = _display_info(dmt); out: dm_task_destroy(dmt); return r;}static int _rename(int argc, char **argv, void *data __attribute((unused))){ int r = 0; struct dm_task *dmt; if (!(dmt = dm_task_create(DM_DEVICE_RENAME))) return 0; /* FIXME Kernel doesn't support uuid or device number here yet */ if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0)) goto out; if (!dm_task_set_newname(dmt, argv[argc - 1])) goto out; if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = 1; out: dm_task_destroy(dmt); return r;}static int _message(int argc, char **argv, void *data __attribute((unused))){ int r = 0, i; size_t sz = 1; struct dm_task *dmt; char *str; if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG))) return 0; if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) { if (!_set_task_device(dmt, NULL, 0)) goto out; } else { if (!_set_task_device(dmt, argv[1], 0)) goto out; argc--; argv++; } if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1]))) goto out; argc -= 2; argv += 2; if (argc <= 0) err("No message supplied.\n"); for (i = 0; i < argc; i++) sz += strlen(argv[i]) + 1; if (!(str = dm_malloc(sz))) { err("message string allocation failed"); goto out; } memset(str, 0, sz); for (i = 0; i < argc; i++) { if (i) strcat(str, " "); strcat(str, argv[i]); } if (!dm_task_set_message(dmt, str)) goto out; dm_free(str); if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; if (!dm_task_run(dmt)) goto out; r = 1; out: dm_task_destroy(dmt); return r;}static int _setgeometry(int argc, char **argv, void *data __attribute((unused))){ int r = 0; struct dm_task *dmt; if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY))) return 0; if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) { if (!_set_task_device(dmt, NULL, 0)) goto out; } else { if (!_set_task_device(dmt, argv[1], 0)) goto out; argc--; argv++; } if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4])) goto out; /* run the task */ if (!dm_task_run(dmt)) goto out; r = 1; out: dm_task_destroy(dmt); return r;}static int _version(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused))){ char version[80]; if (dm_get_library_version(version, sizeof(version))) printf("Library version: %s\n", version); if (!dm_driver_version(version, sizeof(version))) return 0; printf("Driver version: %s\n", version); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -