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, int silent)
82 struct btrfs_ioctl_fs_info_args args;
84 fd = open(path, O_RDONLY);
88 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
93 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
99 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
108 static int check_btrfs_object(const char *object)
111 u8 fsid[BTRFS_FSID_SIZE];
113 ret = get_fsid(object, fsid, 0);
121 static int check_is_root(const char *object)
124 u8 fsid[BTRFS_FSID_SIZE];
125 u8 fsid2[BTRFS_FSID_SIZE];
128 tmp = malloc(strlen(object) + 5);
134 if (tmp[strlen(tmp) - 1] != '/')
138 ret = get_fsid(object, fsid, 0);
140 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object,
145 ret = get_fsid(tmp, fsid2, 1);
146 if (ret == -ENOTTY) {
149 } else if (ret == -ENOTDIR) {
152 } else if (ret < 0) {
153 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", tmp,
158 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
170 static int count_bits(int v)
172 unsigned int tmp = (unsigned int)v;
183 static int autodetect_object_types(const char *object, int *types_out)
190 is_btrfs_object = check_btrfs_object(object);
192 ret = lstat(object, &st);
198 if (is_btrfs_object) {
199 types |= prop_object_inode;
200 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
201 types |= prop_object_subvol;
203 ret = check_is_root(object);
207 types |= prop_object_root;
210 if (S_ISBLK(st.st_mode))
211 types |= prop_object_dev;
220 static int print_prop_help(const struct prop_handler *prop)
222 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
226 static int dump_prop(const struct prop_handler *prop,
234 if ((types & type) && (prop->types & type)) {
236 ret = prop->handler(type, object, prop->name, NULL);
238 ret = print_prop_help(prop);
243 static int dump_props(int types, const char *object, int name_and_help)
248 const struct prop_handler *prop;
250 for (i = 0; prop_handlers[i].name; i++) {
251 prop = &prop_handlers[i];
252 for (j = 1; j < __prop_object_max; j <<= 1) {
253 ret = dump_prop(prop, object, types, j, name_and_help);
267 static int setget_prop(int types, const char *object,
268 const char *name, const char *value)
271 const struct prop_handler *prop = NULL;
273 ret = parse_prop(name, prop_handlers, &prop);
275 fprintf(stderr, "ERROR: property is unknown\n");
279 fprintf(stderr, "ERROR: parse_prop reported unknown error\n");
284 types &= prop->types;
287 "ERROR: object is not compatible with property\n");
292 if (count_bits(types) > 1) {
294 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
299 if (value && prop->read_only) {
300 fprintf(stderr, "ERROR: %s is a read-only property.\n",
306 ret = prop->handler(types, object, name, value);
318 static void parse_args(int argc, char **argv,
319 const char * const *usage_str,
320 int *types, char **object,
321 char **name, char **value)
324 char *type_str = NULL;
328 int c = getopt(argc, argv, "t:");
343 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
344 *types = prop_object_subvol;
345 } else if (!strcmp(type_str, "f") ||
346 !strcmp(type_str, "filesystem")) {
347 *types = prop_object_root;
348 } else if (!strcmp(type_str, "i") ||
349 !strcmp(type_str, "inode")) {
350 *types = prop_object_inode;
351 } else if (!strcmp(type_str, "d") ||
352 !strcmp(type_str, "device")) {
353 *types = prop_object_dev;
355 fprintf(stderr, "ERROR: invalid object type.\n");
360 if (object && optind < argc)
361 *object = argv[optind++];
362 if (name && optind < argc)
363 *name = argv[optind++];
364 if (value && optind < argc)
365 *value = argv[optind++];
367 if (optind != argc) {
368 fprintf(stderr, "ERROR: invalid arguments.\n");
372 if (!*types && object && *object) {
373 ret = autodetect_object_types(*object, types);
376 "ERROR: failed to detect object type. %s\n",
382 "ERROR: object is not a btrfs object.\n");
388 static int cmd_get(int argc, char **argv)
395 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
396 usage(cmd_get_usage);
398 parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
400 fprintf(stderr, "ERROR: invalid arguments.\n");
401 usage(cmd_set_usage);
405 ret = setget_prop(types, object, name, NULL);
407 ret = dump_props(types, object, 0);
412 static int cmd_set(int argc, char **argv)
420 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
421 usage(cmd_set_usage);
423 parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
424 if (!object || !name || !value) {
425 fprintf(stderr, "ERROR: invalid arguments.\n");
426 usage(cmd_set_usage);
429 ret = setget_prop(types, object, name, value);
434 static int cmd_list(int argc, char **argv)
440 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
441 usage(cmd_list_usage);
443 parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
445 fprintf(stderr, "ERROR: invalid arguments.\n");
446 usage(cmd_set_usage);
449 ret = dump_props(types, object, 1);
454 const struct cmd_group property_cmd_group = {
455 property_cmd_group_usage, NULL, {
456 { "get", cmd_get, cmd_get_usage, NULL, 0 },
457 { "set", cmd_set, cmd_set_usage, NULL, 0 },
458 { "list", cmd_list, cmd_list_usage, NULL, 0 },
463 int cmd_property(int argc, char **argv)
465 return handle_command_group(&property_cmd_group, argc, argv);