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");
281 types &= prop->types;
284 "ERROR: object is not compatible with property\n");
289 if (count_bits(types) > 1) {
291 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
296 if (value && prop->read_only) {
297 fprintf(stderr, "ERROR: %s is a read-only property.\n",
303 ret = prop->handler(types, object, name, value);
315 static void parse_args(int argc, char **argv,
316 const char * const *usage_str,
317 int *types, char **object,
318 char **name, char **value)
321 char *type_str = NULL;
325 int c = getopt(argc, argv, "t:");
340 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
341 *types = prop_object_subvol;
342 } else if (!strcmp(type_str, "f") ||
343 !strcmp(type_str, "filesystem")) {
344 *types = prop_object_root;
345 } else if (!strcmp(type_str, "i") ||
346 !strcmp(type_str, "inode")) {
347 *types = prop_object_inode;
348 } else if (!strcmp(type_str, "d") ||
349 !strcmp(type_str, "device")) {
350 *types = prop_object_dev;
352 fprintf(stderr, "ERROR: invalid object type.\n");
357 if (object && optind < argc)
358 *object = argv[optind++];
359 if (name && optind < argc)
360 *name = argv[optind++];
361 if (value && optind < argc)
362 *value = argv[optind++];
364 if (optind != argc) {
365 fprintf(stderr, "ERROR: invalid arguments.\n");
369 if (!*types && object && *object) {
370 ret = autodetect_object_types(*object, types);
373 "ERROR: failed to detect object type. %s\n",
379 "ERROR: object is not a btrfs object.\n");
385 static int cmd_get(int argc, char **argv)
392 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
393 usage(cmd_get_usage);
395 parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
397 fprintf(stderr, "ERROR: invalid arguments.\n");
398 usage(cmd_set_usage);
402 ret = setget_prop(types, object, name, NULL);
404 ret = dump_props(types, object, 0);
409 static int cmd_set(int argc, char **argv)
417 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
418 usage(cmd_set_usage);
420 parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
421 if (!object || !name || !value) {
422 fprintf(stderr, "ERROR: invalid arguments.\n");
423 usage(cmd_set_usage);
426 ret = setget_prop(types, object, name, value);
431 static int cmd_list(int argc, char **argv)
437 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
438 usage(cmd_list_usage);
440 parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
442 fprintf(stderr, "ERROR: invalid arguments.\n");
443 usage(cmd_set_usage);
446 ret = dump_props(types, object, 1);
451 const struct cmd_group property_cmd_group = {
452 property_cmd_group_usage, NULL, {
453 { "get", cmd_get, cmd_get_usage, NULL, 0 },
454 { "set", cmd_set, cmd_set_usage, NULL, 0 },
455 { "list", cmd_list, cmd_list_usage, NULL, 0 },
460 int cmd_property(int argc, char **argv)
462 return handle_command_group(&property_cmd_group, argc, argv);