btrfs-progs: mkfs: rework --subvol CLI option
Change mkfs.btrfs --subvol so that instead of being of the form --subvol DIR:FLAGS, it's instead --subvol MODIFIER:DIR, with MODIFIER being ro, rw, default, or ro-default. Signed-off-by: Mark Harmstone <maharmstone@fb.com>
This commit is contained in:
parent
5d2ef32038
commit
59f74c25af
|
@ -155,15 +155,26 @@ OPTIONS
|
||||||
contain the files from *rootdir*. Since version 4.14.1 the filesystem size is
|
contain the files from *rootdir*. Since version 4.14.1 the filesystem size is
|
||||||
not minimized. Please see option *--shrink* if you need that functionality.
|
not minimized. Please see option *--shrink* if you need that functionality.
|
||||||
|
|
||||||
-u|--subvol <subdir>:<flags>
|
-u|--subvol <type>:<subdir>
|
||||||
Specify that *subdir* is to be created as a subvolume rather than a regular
|
Specify that *subdir* is to be created as a subvolume rather than a regular
|
||||||
directory. The option *--rootdir* must also be specified, and *subdir* must be an
|
directory. The option *--rootdir* must also be specified, and *subdir* must be an
|
||||||
existing subdirectory within it. This option can be specified multiple times.
|
existing subdirectory within it. This option can be specified multiple times.
|
||||||
|
|
||||||
*flags* is an optional comma-separated list of modifiers. Valid choices are:
|
*type* is an optional additional modifier. Valid choices are:
|
||||||
|
|
||||||
* *default*: create as default subvolume (this can only be specified once)
|
* *default*: create as default subvolume
|
||||||
* *ro*: create as readonly subvolume
|
* *ro*: create as read-only subvolume
|
||||||
|
* *rw*: create as read-write subvolume (the default)
|
||||||
|
* *default-ro*: create as read-only default subvolume
|
||||||
|
|
||||||
|
Only one of *default* and *default-ro* may be specified.
|
||||||
|
|
||||||
|
If you wish to create a subvolume with a name containing a colon and you don't
|
||||||
|
want this to be parsed as containing a modifier, you can prefix the path with `./`:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mkfs.btrfs --rootdir dir --subvol ./ro:subdir /dev/loop0
|
||||||
|
|
||||||
If there are hard links inside *rootdir* and *subdir* will split the
|
If there are hard links inside *rootdir* and *subdir* will split the
|
||||||
subvolumes, like the following case::
|
subvolumes, like the following case::
|
||||||
|
|
85
mkfs/main.c
85
mkfs/main.c
|
@ -440,7 +440,7 @@ static const char * const mkfs_usage[] = {
|
||||||
"Creation:",
|
"Creation:",
|
||||||
OPTLINE("-b|--byte-count SIZE", "set size of each device to SIZE (filesystem size is sum of all device sizes)"),
|
OPTLINE("-b|--byte-count SIZE", "set size of each device to SIZE (filesystem size is sum of all device sizes)"),
|
||||||
OPTLINE("-r|--rootdir DIR", "copy files from DIR to the image root directory"),
|
OPTLINE("-r|--rootdir DIR", "copy files from DIR to the image root directory"),
|
||||||
OPTLINE("-u|--subvol SUBDIR:FLAGS", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
|
OPTLINE("-u|--subvol TYPE:SUBDIR", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
|
||||||
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
|
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
|
||||||
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
|
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
|
||||||
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
|
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
|
||||||
|
@ -1015,48 +1015,6 @@ static void *prepare_one_device(void *ctx)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_subvol_flags(struct rootdir_subvol *subvol, const char *flags)
|
|
||||||
{
|
|
||||||
char *buf, *orig_buf;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
buf = orig_buf = strdup(flags);
|
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
error_msg(ERROR_MSG_MEMORY, NULL);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
char *comma = strstr(buf, ",");
|
|
||||||
|
|
||||||
if (comma)
|
|
||||||
*comma = 0;
|
|
||||||
|
|
||||||
if (!strcmp(buf, "default")) {
|
|
||||||
subvol->is_default = true;
|
|
||||||
} else if (!strcmp(buf, "ro")) {
|
|
||||||
subvol->readonly = true;
|
|
||||||
} else if (buf[0] != 0) {
|
|
||||||
error("unrecognized subvol flag \"%s\"", buf);
|
|
||||||
ret = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (comma)
|
|
||||||
buf = comma + 1;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(orig_buf);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BOX_MAIN(mkfs)(int argc, char **argv)
|
int BOX_MAIN(mkfs)(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *file;
|
char *file;
|
||||||
|
@ -1259,6 +1217,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
|
||||||
case 'u': {
|
case 'u': {
|
||||||
struct rootdir_subvol *subvol;
|
struct rootdir_subvol *subvol;
|
||||||
char *colon;
|
char *colon;
|
||||||
|
bool valid_prefix = false;
|
||||||
|
|
||||||
subvol = calloc(1, sizeof(struct rootdir_subvol));
|
subvol = calloc(1, sizeof(struct rootdir_subvol));
|
||||||
if (!subvol) {
|
if (!subvol) {
|
||||||
|
@ -1270,32 +1229,30 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
|
||||||
colon = strstr(optarg, ":");
|
colon = strstr(optarg, ":");
|
||||||
|
|
||||||
if (colon) {
|
if (colon) {
|
||||||
/* Make sure we choose the last colon in
|
if (!string_has_prefix(optarg, "default:")) {
|
||||||
* optarg, in case the subvol name
|
subvol->is_default = true;
|
||||||
* itself contains a colon. */
|
valid_prefix = true;
|
||||||
do {
|
} else if (!string_has_prefix(optarg, "ro:")) {
|
||||||
char *colon2;
|
subvol->readonly = true;
|
||||||
|
valid_prefix = true;
|
||||||
colon2 = strstr(colon + 1, ":");
|
} else if (!string_has_prefix(optarg, "rw:")) {
|
||||||
|
subvol->readonly = false;
|
||||||
if (colon2)
|
valid_prefix = true;
|
||||||
colon = colon2;
|
} else if (!string_has_prefix(optarg, "default-ro:")) {
|
||||||
else
|
subvol->is_default = true;
|
||||||
break;
|
subvol->readonly = true;
|
||||||
} while (true);
|
valid_prefix = true;
|
||||||
|
|
||||||
subvol->dir = strndup(optarg, colon - optarg);
|
|
||||||
if (parse_subvol_flags(subvol, colon + 1)) {
|
|
||||||
ret = 1;
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
subvol->dir = strdup(optarg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid_prefix)
|
||||||
|
subvol->dir = strndup(colon + 1, strlen(colon + 1));
|
||||||
|
else
|
||||||
|
subvol->dir = strdup(optarg);
|
||||||
|
|
||||||
if (subvol->is_default) {
|
if (subvol->is_default) {
|
||||||
if (has_default_subvol) {
|
if (has_default_subvol) {
|
||||||
error("subvol default flag can only be specified once");
|
error("default subvol can only be specified once");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue