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>
30 static const char * const property_cmd_group_usage[] = {
31 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
35 static const char * const cmd_get_usage[] = {
36 "btrfs property get [-t <type>] <object> [<name>]",
37 "Gets a property from a btrfs object.",
38 "If no name is specified, all properties for the given object are",
40 "A filesystem object can be a the filesystem itself, a subvolume,",
41 "an inode or a device. The '-t <type>' option can be used to explicitly",
42 "specify what type of object you meant. This is only needed when a",
43 "property could be set for more then one object type. Possible types",
44 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
48 static const char * const cmd_set_usage[] = {
49 "btrfs property set [-t <type>] <object> <name> <value>",
50 "Sets a property on a btrfs object.",
51 "Please see the help of 'btrfs property get' for a description of",
52 "objects and object types.",
56 static const char * const cmd_list_usage[] = {
57 "btrfs property list [-t <type>] <object>",
58 "Lists available properties with their descriptions for the given object.",
59 "Please see the help of 'btrfs property get' for a description of",
60 "objects and object types.",
64 static int parse_prop(const char *arg, const struct prop_handler *props,
65 const struct prop_handler **prop_ret)
67 const struct prop_handler *prop = props;
69 for (; prop->name; prop++) {
70 if (!strcmp(prop->name, arg)) {
79 static int get_fsid(const char *path, u8 *fsid, int silent)
83 struct btrfs_ioctl_fs_info_args args;
85 fd = open(path, O_RDONLY);
89 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
94 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
100 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
109 static int check_btrfs_object(const char *object)
112 u8 fsid[BTRFS_FSID_SIZE];
114 ret = get_fsid(object, fsid, 0);
122 static int check_is_root(const char *object)
125 u8 fsid[BTRFS_FSID_SIZE];
126 u8 fsid2[BTRFS_FSID_SIZE];
129 tmp = malloc(strlen(object) + 5);
135 if (tmp[strlen(tmp) - 1] != '/')
139 ret = get_fsid(object, fsid, 0);
141 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object,
146 ret = get_fsid(tmp, fsid2, 1);
147 if (ret == -ENOTTY) {
150 } else if (ret == -ENOTDIR) {
153 } else if (ret < 0) {
154 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", tmp,
159 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
171 static int count_bits(int v)
173 unsigned int tmp = (unsigned int)v;
184 static int autodetect_object_types(const char *object, int *types_out)
191 is_btrfs_object = check_btrfs_object(object);
193 ret = lstat(object, &st);
199 if (is_btrfs_object) {
200 types |= prop_object_inode;
201 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
202 types |= prop_object_subvol;
204 ret = check_is_root(object);
208 types |= prop_object_root;
211 if (S_ISBLK(st.st_mode))
212 types |= prop_object_dev;
221 static int print_prop_help(const struct prop_handler *prop)
223 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
227 static int dump_prop(const struct prop_handler *prop,
235 if ((types & type) && (prop->types & type)) {
237 ret = prop->handler(type, object, prop->name, NULL);
239 ret = print_prop_help(prop);
244 static int dump_props(int types, const char *object, int name_and_help)
249 const struct prop_handler *prop;
251 for (i = 0; prop_handlers[i].name; i++) {
252 prop = &prop_handlers[i];
253 for (j = 1; j < __prop_object_max; j <<= 1) {
254 ret = dump_prop(prop, object, types, j, name_and_help);
268 static int setget_prop(int types, const char *object,
269 const char *name, const char *value)
272 const struct prop_handler *prop = NULL;
274 ret = parse_prop(name, prop_handlers, &prop);
276 fprintf(stderr, "ERROR: property is unknown\n");
280 fprintf(stderr, "ERROR: parse_prop reported unknown error\n");
285 types &= prop->types;
288 "ERROR: object is not compatible with property\n");
293 if (count_bits(types) > 1) {
295 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
300 if (value && prop->read_only) {
301 fprintf(stderr, "ERROR: %s is a read-only property.\n",
307 ret = prop->handler(types, object, name, value);
319 static void parse_args(int argc, char **argv,
320 const char * const *usage_str,
321 int *types, char **object,
322 char **name, char **value)
325 char *type_str = NULL;
329 int c = getopt(argc, argv, "t:");
344 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
345 *types = prop_object_subvol;
346 } else if (!strcmp(type_str, "f") ||
347 !strcmp(type_str, "filesystem")) {
348 *types = prop_object_root;
349 } else if (!strcmp(type_str, "i") ||
350 !strcmp(type_str, "inode")) {
351 *types = prop_object_inode;
352 } else if (!strcmp(type_str, "d") ||
353 !strcmp(type_str, "device")) {
354 *types = prop_object_dev;
356 fprintf(stderr, "ERROR: invalid object type.\n");
361 if (object && optind < argc)
362 *object = argv[optind++];
363 if (name && optind < argc)
364 *name = argv[optind++];
365 if (value && optind < argc)
366 *value = argv[optind++];
368 if (optind != argc) {
369 fprintf(stderr, "ERROR: invalid arguments.\n");
373 if (!*types && object && *object) {
374 ret = autodetect_object_types(*object, types);
377 "ERROR: failed to detect object type. %s\n",
383 "ERROR: object is not a btrfs object.\n");
389 static int cmd_get(int argc, char **argv)
396 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
397 usage(cmd_get_usage);
399 parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
401 fprintf(stderr, "ERROR: invalid arguments.\n");
402 usage(cmd_set_usage);
406 ret = setget_prop(types, object, name, NULL);
408 ret = dump_props(types, object, 0);
413 static int cmd_set(int argc, char **argv)
421 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
422 usage(cmd_set_usage);
424 parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
425 if (!object || !name || !value) {
426 fprintf(stderr, "ERROR: invalid arguments.\n");
427 usage(cmd_set_usage);
430 ret = setget_prop(types, object, name, value);
435 static int cmd_list(int argc, char **argv)
441 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
442 usage(cmd_list_usage);
444 parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
446 fprintf(stderr, "ERROR: invalid arguments.\n");
447 usage(cmd_set_usage);
450 ret = dump_props(types, object, 1);
455 const struct cmd_group property_cmd_group = {
456 property_cmd_group_usage, NULL, {
457 { "get", cmd_get, cmd_get_usage, NULL, 0 },
458 { "set", cmd_set, cmd_set_usage, NULL, 0 },
459 { "list", cmd_list, cmd_list_usage, NULL, 0 },
464 int cmd_property(int argc, char **argv)
466 return handle_command_group(&property_cmd_group, argc, argv);