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:
Mark Harmstone 2024-09-30 15:55:10 +01:00 committed by Qu Wenruo
parent 5d2ef32038
commit 59f74c25af
2 changed files with 36 additions and 68 deletions

View File

@ -155,15 +155,26 @@ OPTIONS
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.
-u|--subvol <subdir>:<flags>
-u|--subvol <type>:<subdir>
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
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)
* *ro*: create as readonly subvolume
* *default*: create as default 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
subvolumes, like the following case::

View File

@ -440,7 +440,7 @@ static const char * const mkfs_usage[] = {
"Creation:",
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("-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("-K|--nodiscard", "do not perform whole device TRIM"),
OPTLINE("-f|--force", "force overwrite of existing filesystem"),
@ -1015,48 +1015,6 @@ static void *prepare_one_device(void *ctx)
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)
{
char *file;
@ -1259,6 +1217,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
case 'u': {
struct rootdir_subvol *subvol;
char *colon;
bool valid_prefix = false;
subvol = calloc(1, sizeof(struct rootdir_subvol));
if (!subvol) {
@ -1270,32 +1229,30 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
colon = strstr(optarg, ":");
if (colon) {
/* Make sure we choose the last colon in
* optarg, in case the subvol name
* itself contains a colon. */
do {
char *colon2;
if (!string_has_prefix(optarg, "default:")) {
subvol->is_default = true;
valid_prefix = true;
} else if (!string_has_prefix(optarg, "ro:")) {
subvol->readonly = true;
valid_prefix = true;
} else if (!string_has_prefix(optarg, "rw:")) {
subvol->readonly = false;
valid_prefix = true;
} else if (!string_has_prefix(optarg, "default-ro:")) {
subvol->is_default = true;
subvol->readonly = true;
valid_prefix = true;
}
}
colon2 = strstr(colon + 1, ":");
if (colon2)
colon = colon2;
if (valid_prefix)
subvol->dir = strndup(colon + 1, strlen(colon + 1));
else
break;
} while (true);
subvol->dir = strndup(optarg, colon - optarg);
if (parse_subvol_flags(subvol, colon + 1)) {
ret = 1;
goto error;
}
} else {
subvol->dir = strdup(optarg);
}
if (subvol->is_default) {
if (has_default_subvol) {
error("subvol default flag can only be specified once");
error("default subvol can only be specified once");
ret = 1;
goto error;
}