mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
dmsetup: Add --concise to dmsetup create.
Add the new concise format to dmsetup create, either as a single command-line parameter or from stdin. Based on patches submitted by Enric Balletbo i Serra <enric.balletbo@collabora.com>.
This commit is contained in:
parent
e6afe9e782
commit
827be01758
@ -1,5 +1,6 @@
|
||||
Version 1.02.143 -
|
||||
=================================
|
||||
Add --concise to dmsetup create for many devices with tables in one command.
|
||||
Accept minor number without major in library when it knows dm major number.
|
||||
Introduce single-line concise table output format: dmsetup table --concise
|
||||
|
||||
|
@ -36,6 +36,17 @@ dmsetup \(em low level logical volume management
|
||||
.
|
||||
.HP
|
||||
.B dmsetup
|
||||
.de CMD_CREATE_CONCISE
|
||||
. ad l
|
||||
. BR create
|
||||
. BR --concise
|
||||
. RI [ concise_device_specification ]
|
||||
. ad b
|
||||
..
|
||||
.CMD_CREATE_CONCISE
|
||||
.
|
||||
.HP
|
||||
.B dmsetup
|
||||
.de CMD_DEPS
|
||||
. ad l
|
||||
. BR deps
|
||||
@ -621,6 +632,16 @@ device the node \fI/dev/mapper/device_name\fP is created.
|
||||
See below for more information on the table format.
|
||||
.
|
||||
.HP
|
||||
.CMD_CREATE_CONCISE
|
||||
.br
|
||||
Creates one or more devices from a concise device specification.
|
||||
Each device is specified by a comma-separated list: name, uuid, minor number, flags, comma-separated table lines.
|
||||
Flags defaults to read-write (rw) or may be read-only (ro).
|
||||
Uuid, minor number and flags are optional so those fields may be empty.
|
||||
A semi-colon separates specifications of different devices.
|
||||
Use a backslash to escape the following character, for example a comma or semi-colon in a name or table. See also CONCISE FORMAT below.
|
||||
.
|
||||
.HP
|
||||
.CMD_DEPS
|
||||
.br
|
||||
Outputs a list of devices referenced by the live table for the specified
|
||||
@ -828,7 +849,7 @@ displayed always.
|
||||
With \fB--concise\fP, the output is presented concisely on a single line.
|
||||
Commas then separate the name, uuid, minor device number, flags ('ro' or 'rw')
|
||||
and the table (if present). Semi-colons separate devices. Backslashes escape
|
||||
any commas, semi-colons or backslashes.
|
||||
any commas, semi-colons or backslashes. See CONCISE FORMAT below.
|
||||
.
|
||||
.HP
|
||||
.CMD_TARGETS
|
||||
@ -1001,6 +1022,55 @@ documentation directory for the device-mapper package.)
|
||||
.br
|
||||
2056320 2875602 linear /dev/hdb 1028160
|
||||
.
|
||||
.SH CONCISE FORMAT
|
||||
.
|
||||
A concise representation of one of more devices.
|
||||
.sp
|
||||
.br
|
||||
- A comma separates the fields of each device.
|
||||
.br
|
||||
- A semi-colon separates devices.
|
||||
.TP
|
||||
The representation of a device takes the form:
|
||||
.sp
|
||||
<name>,<uuid>,<minor>,<flags>,<table>[,<table>+][;<dev_name>,<uuid>,<minor>,<flags>,<table>[,<table>+]]
|
||||
.TP
|
||||
The fields are:
|
||||
.
|
||||
.TP
|
||||
.B name
|
||||
The name of the device.
|
||||
.TP
|
||||
.B uuid
|
||||
The UUID of the device (or empty).
|
||||
.TP
|
||||
.B minor
|
||||
The minor number of the device. If empty, the kernel assigns a suitable minor number.
|
||||
.TP
|
||||
.B flags
|
||||
Supported flags are:
|
||||
.sp
|
||||
.B ro
|
||||
Sets the table being loaded for the device read-only
|
||||
.br
|
||||
.B rw
|
||||
Sets the table being loaded for the device read-write (default)
|
||||
.TP
|
||||
.B table
|
||||
One line of the table. See TABLE FORMAT above.
|
||||
.
|
||||
.SH EXAMPLES
|
||||
.
|
||||
# A simple linear read-only device
|
||||
.br
|
||||
test-linear-small,,,ro,0 2097152 linear /dev/loop0 0, 2097152 2097152 linear /dev/loop1 0
|
||||
.br
|
||||
.sp
|
||||
# Two linear devices
|
||||
.br
|
||||
test-linear-small,,,,0 2097152 linear /dev/loop0 0;test-linear-large,,,, 0 2097152 linear /dev/loop1 0, 2097152 2097152 linear /dev/loop2 0
|
||||
.br
|
||||
.
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.
|
||||
.TP
|
||||
|
253
tools/dmsetup.c
253
tools/dmsetup.c
@ -359,6 +359,23 @@ static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse multiple lines of table */
|
||||
static int _parse_table_lines(struct dm_task *dmt)
|
||||
{
|
||||
char *pos = _table, *next_pos;
|
||||
int line = 0;
|
||||
|
||||
do {
|
||||
/* Identify and terminate each line */
|
||||
if ((next_pos = strchr(_table, '\n')))
|
||||
*next_pos++ = '\0';
|
||||
if (!_parse_line(dmt, pos, "", ++line))
|
||||
return_0;
|
||||
} while ((pos = next_pos));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
@ -366,9 +383,9 @@ static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
FILE *fp;
|
||||
int r = 0, line = 0;
|
||||
|
||||
/* one-line table on cmdline */
|
||||
/* Table on cmdline or from stdin with --concise */
|
||||
if (_table)
|
||||
return _parse_line(dmt, _table, "", ++line);
|
||||
return _parse_table_lines(dmt);
|
||||
|
||||
/* OK for empty stdin */
|
||||
if (file) {
|
||||
@ -1098,21 +1115,17 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _create(CMD_ARGS)
|
||||
static int _create_one_device(const char *name, const char *file)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
const char *file = NULL;
|
||||
uint32_t cookie = 0;
|
||||
uint16_t udev_flags = 0;
|
||||
|
||||
if (argc == 2)
|
||||
file = argv[1];
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
|
||||
return_0;
|
||||
|
||||
if (!dm_task_set_name(dmt, argv[0]))
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto_out;
|
||||
|
||||
if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid))
|
||||
@ -1187,6 +1200,221 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
#define DEFAULT_BUF_SIZE 4096
|
||||
|
||||
static char *_slurp_stdin(void)
|
||||
{
|
||||
char *buf, *pos;
|
||||
size_t bufsize = DEFAULT_BUF_SIZE;
|
||||
size_t total = 0;
|
||||
ssize_t n = 0;
|
||||
|
||||
if (!(buf = dm_malloc(bufsize))) {
|
||||
log_error("Buffer memory allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = buf;
|
||||
do {
|
||||
do
|
||||
n = read(STDIN_FILENO, pos, (size_t) bufsize - total - 1);
|
||||
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
|
||||
if (n < 0) {
|
||||
log_error("Read from stdin aborted: %s", strerror(errno));
|
||||
dm_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!n)
|
||||
break;
|
||||
|
||||
total += n;
|
||||
pos += n;
|
||||
if (total == bufsize - 1) {
|
||||
bufsize *= 2;
|
||||
if (!(buf = dm_realloc(buf, bufsize))) {
|
||||
log_error("Buffer memory extension to %" PRIsize_t " bytes failed.", bufsize);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} while (1);
|
||||
|
||||
buf[total] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int _create_concise(const struct command *cmd, int argc, char **argv)
|
||||
{
|
||||
char *concise_format;
|
||||
char *c, *n;
|
||||
char *fields[5] = { NULL }; /* name,uuid,minor,flags,table */
|
||||
int f = 0;
|
||||
|
||||
if (_switches[TABLE_ARG] || _switches[MINOR_ARG] || _switches[UUID_ARG] ||
|
||||
_switches[NOTABLE_ARG] || _switches[INACTIVE_ARG]){
|
||||
log_error("--concise is incompatible with --[no]table, --minor, --uuid and --inactive.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc)
|
||||
concise_format = argv[0];
|
||||
else if (!(concise_format = _slurp_stdin()))
|
||||
return_0;
|
||||
|
||||
/* Work through input string c, parsing into sets of 5 fields. */
|
||||
/* Strip out any characters quoted by backslashes in-place. */
|
||||
/* Read characters from c and prepare them in situ for final processing at n */
|
||||
c = n = fields[f] = concise_format;
|
||||
|
||||
while (*c) {
|
||||
/* Quoted character? Skip past quote. */
|
||||
if (*c == '\\') {
|
||||
if (!*(++c)) {
|
||||
log_error("Backslash must be followed by another character at end of string.");
|
||||
*n = '\0';
|
||||
log_error("Parsed %d fields: name: %s uuid: %s minor: %s flags: %s table: %s",
|
||||
f + 1, fields[0], fields[1], fields[2], fields[3], fields[4]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Don't interpret next character */
|
||||
*n++ = *c++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Comma marking end of field? */
|
||||
if (*c == ',' && f < 4) {
|
||||
/* Terminate string */
|
||||
*n++ = '\0', c++;
|
||||
|
||||
/* Store start of next field */
|
||||
fields[++f] = n;
|
||||
|
||||
/* Skip any whitespace after field-separating commas */
|
||||
while(isspace(*c))
|
||||
c++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Comma marking end of a table line? */
|
||||
if (*c == ',' && f >= 4) {
|
||||
/* Replace comma with newline to match standard table input format */
|
||||
*n++ = '\n', c++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Semi-colon marking end of device? */
|
||||
if (*c == ';' || *(c + 1) == '\0') {
|
||||
/* End of input? */
|
||||
if (*c != ';')
|
||||
/* Copy final character */
|
||||
*n++ = *c;
|
||||
|
||||
/* Terminate string */
|
||||
*n++ = '\0', c++;
|
||||
|
||||
if (f != 4) {
|
||||
log_error("Five comma-separated fields are required for each device");
|
||||
log_error("Parsed %d fields: name: %s uuid: %s minor: %s flags: %s table: %s",
|
||||
f + 1, fields[0], fields[1], fields[2], fields[3], fields[4]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up parameters the same way as when specified directly on command line */
|
||||
if (*fields[1]) {
|
||||
_switches[UUID_ARG] = 1;
|
||||
_uuid = fields[1];
|
||||
}
|
||||
|
||||
if (*fields[2]) {
|
||||
_switches[MINOR_ARG] = 1;
|
||||
_int_args[MINOR_ARG] = atoi(fields[2]);
|
||||
}
|
||||
|
||||
if (!strcmp(fields[3], "ro"))
|
||||
_switches[READ_ONLY] = 1;
|
||||
else if (*fields[3] && strcmp(fields[3], "rw")) {
|
||||
log_error("Invalid flags parameter '%s' must be 'ro' or 'rw' or empty.", fields[3]);
|
||||
_uuid = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_table = fields[4];
|
||||
|
||||
/* Create the device */
|
||||
if (!_create_one_device(fields[0], NULL)) {
|
||||
_uuid = _table = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Clear parameters ready for any further devices */
|
||||
_switches[UUID_ARG] = 0;
|
||||
_switches[MINOR_ARG] = 0;
|
||||
_switches[READ_ONLY] = 0;
|
||||
_uuid = _table = NULL;
|
||||
|
||||
f = 0;
|
||||
fields[0] = n;
|
||||
fields[1] = fields[2] = fields[3] = fields[4] = NULL;
|
||||
|
||||
/* Skip any whitespace after semi-colons */
|
||||
while(isspace(*c))
|
||||
c++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Normal character */
|
||||
*n++ = *c++;
|
||||
}
|
||||
|
||||
if (fields[0] != n) {
|
||||
*n = '\0';
|
||||
log_error("Incomplete entry: five comma-separated fields are required for each device");
|
||||
log_error("Parsed %d fields: name: %s uuid: %s minor: %s flags: %s table: %s",
|
||||
f + 1, fields[0], fields[1], fields[2], fields[3], fields[4]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
out:
|
||||
if (!argc)
|
||||
dm_free(concise_format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _create(CMD_ARGS)
|
||||
{
|
||||
const char *name;
|
||||
const char *file = NULL;
|
||||
|
||||
if (_switches[CONCISE_ARG]) {
|
||||
if (argc > 1) {
|
||||
log_error("dmsetup create --concise takes at most one argument");
|
||||
return 0;
|
||||
}
|
||||
return _create_concise(cmd, argc, argv);
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please provide a name for the new device.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = argv[0];
|
||||
if (argc == 2)
|
||||
file = argv[1];
|
||||
|
||||
return _create_one_device(name, file);
|
||||
}
|
||||
|
||||
static int _do_rename(const char *name, const char *new_name, const char *new_uuid) {
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
@ -2148,6 +2376,7 @@ static int _status(CMD_ARGS)
|
||||
name = names->name;
|
||||
else {
|
||||
if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
|
||||
/* FIXME Respect deps in concise mode, so they are correctly ordered for recreation */
|
||||
return _process_all(cmd, NULL, argc, argv, 0, _status);
|
||||
name = argv[0];
|
||||
}
|
||||
@ -5930,7 +6159,8 @@ static struct command _dmsetup_commands[] = {
|
||||
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
|
||||
"\t [-u|uuid <uuid>] [--addnodeonresume|--addnodeoncreate]\n"
|
||||
"\t [--readahead {[+]<sectors>|auto|none}]\n"
|
||||
"\t [-n|--notable|--table {<table>|<table_file>}]", 1, 2, 0, 0, _create},
|
||||
"\t [-n|--notable|--table {<table>|<table_file>}]\n"
|
||||
"\tcreate --concise [<concise_device_spec_list>]", 0, 2, 0, 0, _create},
|
||||
{"remove", "[--deferred] [-f|--force] [--retry] <device>...", 0, -1, 1, 0, _remove},
|
||||
{"remove_all", "[-f|--force]", 0, 0, 0, 0, _remove_all},
|
||||
{"suspend", "[--noflush] [--nolockfs] <device>...", 0, -1, 1, 0, _suspend},
|
||||
@ -6022,6 +6252,11 @@ static void _dmsetup_usage(FILE *out)
|
||||
"-j <major> -m <minor>\n");
|
||||
fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
|
||||
fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n");
|
||||
fprintf(out, "<concise_device_specification> has single-device entries separated by semi-colons:\n"
|
||||
" <name>,<uuid>,<minor>,<flags>,<table>\n"
|
||||
" where <flags> is 'ro' or 'rw' (the default) and any of <uuid>, <minor>\n"
|
||||
" and <flags> may be empty. Separate extra table lines with commas.\n"
|
||||
" E.g.: dev1,,,,0 100 linear 253:1 0,100 100 error;dev2,,,ro,0 1 error\n");
|
||||
fprintf(out, "Table_file contents may be supplied on stdin.\n");
|
||||
fprintf(out, "Options are: devno, devname, blkdevname.\n");
|
||||
fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
|
||||
|
Loading…
Reference in New Issue
Block a user