2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
22 #include <sys/ioctl.h>
29 static const char * const property_cmd_group_usage[] = {
30 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
34 static const char * const cmd_get_usage[] = {
35 "btrfs property get [-t <type>] <object> [<name>]",
36 "Gets a property from a btrfs object.",
37 "If no name is specified, all properties for the given object are",
39 "A filesystem object can be a the filesystem itself, a subvolume,",
40 "an inode or a device. The '-t <type>' option can be used to explicitly",
41 "specify what type of object you meant. This is only needed when a",
42 "property could be set for more then one object type. Possible types",
43 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
47 static const char * const cmd_set_usage[] = {
48 "btrfs property set [-t <type>] <object> <name> <value>",
49 "Sets a property on a btrfs object.",
50 "Please see the help of 'btrfs property get' for a description of",
51 "objects and object types.",
55 static const char * const cmd_list_usage[] = {
56 "btrfs property list [-t <type>] <object>",
57 "Lists available properties with their descriptions for the given object.",
58 "Please see the help of 'btrfs property get' for a description of",
59 "objects and object types.",
63 static int parse_prop(const char *arg, const struct prop_handler *props,
64 const struct prop_handler **prop_ret)
66 const struct prop_handler *prop = props;
68 for (; prop->name; prop++) {
69 if (!strcmp(prop->name, arg)) {
78 static int get_fsid(const char *path, u8 *fsid)
82 struct btrfs_ioctl_fs_info_args args;
84 fd = open(path, O_RDONLY);
87 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
92 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
98 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
107 static int check_btrfs_object(const char *object)
110 u8 fsid[BTRFS_FSID_SIZE];
112 ret = get_fsid(object, fsid);
120 static int check_is_root(const char *object)
123 u8 fsid[BTRFS_FSID_SIZE];
124 u8 fsid2[BTRFS_FSID_SIZE];
127 tmp = malloc(strlen(object) + 5);
133 if (tmp[strlen(tmp) - 1] != '/')
137 ret = get_fsid(object, fsid);
139 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object,
144 ret = get_fsid(tmp, fsid2);
150 if (!memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
162 static int count_bits(int v)
164 unsigned int tmp = (unsigned int)v;
175 static int autodetect_object_types(const char *object, int *types_out)
182 is_btrfs_object = check_btrfs_object(object);
184 ret = lstat(object, &st);
190 if (is_btrfs_object) {
191 types |= prop_object_inode;
192 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
193 types |= prop_object_subvol;
195 ret = check_is_root(object);
199 types |= prop_object_root;
202 if (S_ISBLK(st.st_mode))
203 types |= prop_object_dev;
212 static int print_prop_help(const struct prop_handler *prop)
214 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
218 static int dump_prop(const struct prop_handler *prop,
226 if ((types & type) && (prop->types & type)) {
228 ret = prop->handler(type, object, prop->name, NULL);
230 ret = print_prop_help(prop);
235 static int dump_props(int types, const char *object, int name_and_help)
240 const struct prop_handler *prop;
242 for (i = 0; prop_handlers[i].name; i++) {
243 prop = &prop_handlers[i];
244 for (j = 1; j < __prop_object_max; j <<= 1) {
245 ret = dump_prop(prop, object, types, j, name_and_help);
259 static int setget_prop(int types, const char *object,
260 const char *name, const char *value)
263 const struct prop_handler *prop = NULL;
265 ret = parse_prop(name, prop_handlers, &prop);
267 fprintf(stderr, "ERROR: property is unknown\n");
271 fprintf(stderr, "ERROR: parse_prop reported unknown error\n");
276 types &= prop->types;
279 "ERROR: object is not compatible with property\n");
284 if (count_bits(types) > 1) {
286 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
291 if (value && prop->read_only) {
292 fprintf(stderr, "ERROR: %s is a read-only property.\n",
298 ret = prop->handler(types, object, name, value);
310 static void parse_args(int argc, char **argv,
311 const char * const *usage_str,
312 int *types, char **object,
313 char **name, char **value)
316 char *type_str = NULL;
320 int c = getopt(argc, argv, "t:");
336 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
337 *types = prop_object_subvol;
338 } else if (!strcmp(type_str, "f") ||
339 !strcmp(type_str, "filesystem")) {
340 *types = prop_object_root;
341 } else if (!strcmp(type_str, "i") ||
342 !strcmp(type_str, "inode")) {
343 *types = prop_object_inode;
344 } else if (!strcmp(type_str, "d") ||
345 !strcmp(type_str, "device")) {
346 *types = prop_object_dev;
348 fprintf(stderr, "ERROR: invalid object type.\n");
353 if (object && optind < argc)
354 *object = argv[optind++];
355 if (name && optind < argc)
356 *name = argv[optind++];
357 if (value && optind < argc)
358 *value = argv[optind++];
360 if (optind != argc) {
361 fprintf(stderr, "ERROR: invalid arguments.\n");
365 if (!*types && object && *object) {
366 ret = autodetect_object_types(*object, types);
369 "ERROR: failed to detect object type. %s\n",
375 "ERROR: object is not a btrfs object.\n");
381 static int cmd_get(int argc, char **argv)
388 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
389 usage(cmd_get_usage);
391 parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
393 fprintf(stderr, "ERROR: invalid arguments.\n");
394 usage(cmd_set_usage);
398 ret = setget_prop(types, object, name, NULL);
400 ret = dump_props(types, object, 0);
405 static int cmd_set(int argc, char **argv)
413 if (check_argc_min(argc, 4) || check_argc_max(argc, 5))
414 usage(cmd_set_usage);
416 parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
417 if (!object || !name || !value) {
418 fprintf(stderr, "ERROR: invalid arguments.\n");
419 usage(cmd_set_usage);
422 ret = setget_prop(types, object, name, value);
427 static int cmd_list(int argc, char **argv)
433 if (check_argc_min(argc, 2) || check_argc_max(argc, 3))
434 usage(cmd_list_usage);
436 parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
438 fprintf(stderr, "ERROR: invalid arguments.\n");
439 usage(cmd_set_usage);
442 ret = dump_props(types, object, 1);
447 const struct cmd_group property_cmd_group = {
448 property_cmd_group_usage, NULL, {
449 { "get", cmd_get, cmd_get_usage, NULL, 0 },
450 { "set", cmd_set, cmd_set_usage, NULL, 0 },
451 { "list", cmd_list, cmd_list_usage, NULL, 0 },
456 int cmd_property(int argc, char **argv)
458 return handle_command_group(&property_cmd_group, argc, argv);