@@ -4,7 +4,7 @@ CFLAGS = -g -O1
objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
root-tree.o dir-item.o file-item.o inode-item.o \
inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \
- volumes.o utils.o btrfs-list.o btrfslabel.o repair.o \
+ volumes.o utils.o btrfs-list.o btrfslabel.o repair.o yesno.o\
send-stream.o send-utils.o qgroup.o
cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \
cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \
@@ -32,6 +32,7 @@
#include "ctree.h"
#include "commands.h"
#include "btrfs-list.h"
+#include "yesno.h"
static const char * const subvolume_cmd_group_usage[] = {
"btrfs subvolume <command> <args>",
@@ -620,22 +621,81 @@ static int cmd_subvol_get_default(int argc, char **argv)
static const char * const cmd_subvol_set_default_usage[] = {
"btrfs subvolume set-default <subvolid> <path>",
+ "btrfs subvolume set-default [-p] [-f] <path>",
"Set the default subvolume of a filesystem",
+ "-p If <path> is not a subvolume, it will enter",
+ " interactive mode, then you can choose to set",
+ " the parent tree of the <path> as default or not.",
+ "-f This option must be used with -p. The interactive",
+ " mode will be skipped and 'yes' will be set.",
NULL
};
static int cmd_subvol_set_default(int argc, char **argv)
{
- int ret=0, fd, e;
- u64 objectid;
+ int ret = 0, fd = -1, e;
+ int parent = 0, force = 0;
+ u64 objectid = -1;
char *path;
- char *subvolid;
+ char *subvolid, *inv;
- if (check_argc_exact(argc, 3))
- usage(cmd_subvol_set_default_usage);
+ optind = 1;
+ while (1) {
+ int c = getopt(argc, argv, "pf");
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case 'p':
+ parent = 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ default:
+ usage_lines(cmd_subvol_set_default_usage, 1);
+ }
+ }
+
+ if (check_argc_min(argc - optind, 1) ||
+ check_argc_max(argc - optind, 3))
+ usage_lines(cmd_subvol_set_default_usage, 1);
+
+ if (force && !parent)
+ usage_lines(cmd_subvol_set_default_usage, 1);
- subvolid = argv[1];
- path = argv[2];
+ if (argc - optind == 2) {
+ subvolid = argv[optind];
+ path = argv[optind + 1];
+
+ objectid = (unsigned long long)strtoll(subvolid, &inv, 0);
+ if (errno == ERANGE || subvolid == inv) {
+ fprintf(stderr,
+ "ERROR: invalid tree id (%s)\n", subvolid);
+ return 30;
+ }
+ } else {
+ path = argv[optind];
+
+ ret = test_issubvolume(path);
+ if (ret < 0) {
+ fprintf(stderr,
+ "ERROR: error accessing '%s'\n", path);
+ return 12;
+ }
+ if (!ret) {
+ fprintf(stderr,
+ "'%s' is not a subvolume, use parent tree instead",
+ path);
+ if (force)
+ fprintf(stderr, "!\n");
+ else {
+ fprintf(stderr, "? (y or n)");
+ if (!yesno())
+ return 13;
+ }
+ }
+ }
fd = open_file_or_dir(path);
if (fd < 0) {
@@ -643,16 +703,35 @@ static int cmd_subvol_set_default(int argc, char **argv)
return 12;
}
- objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
- if (errno == ERANGE) {
- fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
- return 30;
+ /*
+ * When objectid is -1, it means that
+ * subvolume id is not specified by user.
+ * We will set default subvolume by <path>.
+ */
+ if (objectid == -1) {
+ struct btrfs_ioctl_ino_lookup_args args;
+
+ memset(&args, 0, sizeof(args));
+ args.treeid = 0;
+ args.objectid = BTRFS_FIRST_FREE_OBJECTID;
+
+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
+ if (ret) {
+ fprintf(stderr,
+ "ERROR: can't perform the search - %s\n",
+ strerror(errno));
+ return ret;
+ }
+
+ objectid = args.treeid;
}
+
ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
e = errno;
close(fd);
- if( ret < 0 ){
- fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n",
+ if (ret < 0) {
+ fprintf(stderr,
+ "ERROR: unable to set a new default subvolume - %s\n",
strerror(e));
return 30;
}
@@ -708,7 +787,7 @@ const struct cmd_group subvolume_cmd_group = {
{ "get-default", cmd_subvol_get_default,
cmd_subvol_get_default_usage, NULL, 0 },
{ "set-default", cmd_subvol_set_default,
- cmd_subvol_set_default_usage, NULL, 0 },
+ cmd_subvol_set_default_usage, NULL, 0 , 1 },
{ "find-new", cmd_find_new, cmd_find_new_usage, NULL, 0 },
{ 0, 0, 0, 0, 0 }
}
@@ -15,6 +15,8 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
.PP
+\fBbtrfs\fP \fBsubvolume set-default\fP\fI [-p] [-f] <subvolume>\fP
+.PP
\fBbtrfs\fP \fBsubvolume get-default\fP\fI <path>\fP
.PP
\fBbtrfs\fP \fBfilesystem defragment\fP -c[zlib|lzo] [-l \fIlen\fR] \
@@ -155,6 +157,21 @@ Set the subvolume of the filesystem \fI<path>\fR which is mounted as
is returned by the \fBsubvolume list\fR command.
.TP
+\fBsubvolume set-default\fR\fI [-p] [-f] <path>\fR
+Set the subvolume of the filesystem as default. The subvolume is identified
+by \fI<path>\fR. By default(no option is given), it should be a path to
+subvolume, or btrfs returns an error.
+
+\fB-p\fR If \fB-p\fR is given, and \fI<path>\fR is a subvolume, btrfs is the
+same as default. And if <path> is not a subvolume, btrfs enters
+interactive mode, then you can choose to set the parent tree of \fI<path>\fR
+as default or not.
+
+\fB-f\fR \fB-f\fR must be used with \fB-p\fR, and the interactive mode
+will be skipped and 'yes' will be chosen. Given \fB-f\fR option without
+\fB-p\fR, btrfs returns an error.
+.TP
+
\fBsubvolume get-default\fR\fI <path>\fR
Get the default subvolume of the filesystem \fI<path>\fR. The output format
is similar to \fBsubvolume list\fR command.
new file mode 100644
@@ -0,0 +1,56 @@
+/* yesno.c -- read a yes/no response from stdin
+
+ Copyright (C) 1990, 1998, 2001, 2003-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "yesno.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Return true if we read an affirmative line from standard input.
+
+ Since this function uses stdin, it is suggested that the caller not
+ use STDIN_FILENO directly, and also that the line
+ atexit(close_stdin) be added to main(). */
+
+bool yesno(void)
+{
+ bool yes;
+
+#if ENABLE_NLS
+ char *response = NULL;
+ size_t response_size = 0;
+ ssize_t response_len = getline(&response, &response_size, stdin);
+
+ if (response_len <= 0)
+ yes = false;
+ else{
+ response[response_len - 1] = '\0';
+ yes = (0 < rpmatch(response));
+ }
+
+ free(response);
+#else
+ /* Test against "^[yY]", hardcoded to avoid requiring getline,
+ regex, and rpmatch. */
+ int c = getchar();
+ yes = (c == 'y' || c == 'Y');
+ while (c != '\n' && c != EOF)
+ c = getchar();
+#endif
+
+ return yes;
+}
new file mode 100644
@@ -0,0 +1,24 @@
+/* declare yesno
+ Copyright (C) 2004, 2009-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef YESNO_H_
+# define YESNO_H_
+
+# include <stdbool.h>
+
+bool yesno(void);
+
+#endif
This patch introduces another form of btrfs subvolume set-default command. In command "btrfs subvolume set-default", we used subvolume <id> and <path> to set the default subvolume of a filesystem. By the new form, we can use subvolume path to set the default subvolume. The new form: subvolume set-default [-p] [-f] <path> For example: If <path> is a subvolume, no option needed. #btrfs subvolume set-default /mnt/subvol If <path> is not a subvolume, -p option makes btrfs enter interactive mode # btrfs subvolume set-default -p /mnt/subvol/dir '/mnt/subvol/dir' is not a subvolume, use parent tree instead? (y or n)y If interactive is not expected, -f option makes btrfs skip it and 'yes' will be choose # btrfs subvolume set-default -p -f /mnt/subvol/dir Signed-off-by: Cheng Yang <chenyang.fnst@cn.fujitsu.com> --- Makefile | 2 +- cmds-subvolume.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++------- man/btrfs.8.in | 17 +++++++++ yesno.c | 56 ++++++++++++++++++++++++++++ yesno.h | 24 ++++++++++++ 5 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 yesno.c create mode 100644 yesno.h