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 int parse_prop(const char *arg, const struct prop_handler *props,
36 const struct prop_handler **prop_ret)
38 const struct prop_handler *prop = props;
40 for (; prop->name; prop++) {
41 if (!strcmp(prop->name, arg)) {
50 static int get_fsid(const char *path, u8 *fsid, int silent)
54 struct btrfs_ioctl_fs_info_args args;
56 fd = open(path, O_RDONLY);
60 error("failed to open %s: %s", path,
65 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
71 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
80 static int check_btrfs_object(const char *object)
83 u8 fsid[BTRFS_FSID_SIZE];
85 ret = get_fsid(object, fsid, 0);
93 static int check_is_root(const char *object)
96 u8 fsid[BTRFS_FSID_SIZE];
97 u8 fsid2[BTRFS_FSID_SIZE];
101 rp = realpath(object, NULL);
106 if (!strcmp(rp, "/")) {
111 tmp = malloc(strlen(object) + 5);
117 if (tmp[strlen(tmp) - 1] != '/')
121 ret = get_fsid(object, fsid, 0);
123 error("get_fsid for %s failed: %s", object, strerror(-ret));
127 ret = get_fsid(tmp, fsid2, 1);
128 if (ret == -ENOTTY) {
131 } else if (ret == -ENOTDIR) {
134 } else if (ret < 0) {
135 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
139 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
152 static int count_bits(int v)
154 unsigned int tmp = (unsigned int)v;
165 static int autodetect_object_types(const char *object, int *types_out)
172 is_btrfs_object = check_btrfs_object(object);
174 ret = lstat(object, &st);
180 if (is_btrfs_object) {
181 types |= prop_object_inode;
182 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
183 types |= prop_object_subvol;
185 ret = check_is_root(object);
189 types |= prop_object_root;
192 if (S_ISBLK(st.st_mode))
193 types |= prop_object_dev;
202 static int print_prop_help(const struct prop_handler *prop)
204 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
208 static int dump_prop(const struct prop_handler *prop,
216 if ((types & type) && (prop->types & type)) {
218 ret = prop->handler(type, object, prop->name, NULL);
220 ret = print_prop_help(prop);
225 static int dump_props(int types, const char *object, int name_and_help)
230 const struct prop_handler *prop;
232 for (i = 0; prop_handlers[i].name; i++) {
233 prop = &prop_handlers[i];
234 for (j = 1; j < __prop_object_max; j <<= 1) {
235 ret = dump_prop(prop, object, types, j, name_and_help);
249 static int setget_prop(int types, const char *object,
250 const char *name, const char *value)
253 const struct prop_handler *prop = NULL;
255 ret = parse_prop(name, prop_handlers, &prop);
257 error("unknown property: %s", name);
262 types &= prop->types;
264 error("object is not compatible with property: %s", prop->name);
269 if (count_bits(types) > 1) {
270 error("type of object is ambiguous, please use option -t");
275 if (value && prop->read_only) {
276 error("property is read-only property: %s",
282 ret = prop->handler(types, object, name, value);
294 static void parse_args(int argc, char **argv,
295 const char * const *usage_str,
296 int *types, char **object,
297 char **name, char **value)
300 char *type_str = NULL;
304 int c = getopt(argc, argv, "t:");
319 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
320 *types = prop_object_subvol;
321 } else if (!strcmp(type_str, "f") ||
322 !strcmp(type_str, "filesystem")) {
323 *types = prop_object_root;
324 } else if (!strcmp(type_str, "i") ||
325 !strcmp(type_str, "inode")) {
326 *types = prop_object_inode;
327 } else if (!strcmp(type_str, "d") ||
328 !strcmp(type_str, "device")) {
329 *types = prop_object_dev;
331 error("invalid object type: %s", type_str);
336 if (object && optind < argc)
337 *object = argv[optind++];
338 if (name && optind < argc)
339 *name = argv[optind++];
340 if (value && optind < argc)
341 *value = argv[optind++];
343 if (optind != argc) {
344 error("unexpected agruments found");
348 if (!*types && object && *object) {
349 ret = autodetect_object_types(*object, types);
351 error("failed to detect object type: %s",
356 error("object is not a btrfs object: %s", *object);
362 static const char * const cmd_property_get_usage[] = {
363 "btrfs property get [-t <type>] <object> [<name>]",
364 "Gets a property from a btrfs object.",
365 "If no name is specified, all properties for the given object are",
367 "A filesystem object can be a the filesystem itself, a subvolume,",
368 "an inode or a device. The '-t <type>' option can be used to explicitly",
369 "specify what type of object you meant. This is only needed when a",
370 "property could be set for more then one object type. Possible types",
371 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
375 static int cmd_property_get(int argc, char **argv)
382 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
383 usage(cmd_property_get_usage);
385 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
388 error("invalid arguments");
389 usage(cmd_property_get_usage);
393 ret = setget_prop(types, object, name, NULL);
395 ret = dump_props(types, object, 0);
400 static const char * const cmd_property_set_usage[] = {
401 "btrfs property set [-t <type>] <object> <name> <value>",
402 "Sets a property on a btrfs object.",
403 "Please see the help of 'btrfs property get' for a description of",
404 "objects and object types.",
408 static int cmd_property_set(int argc, char **argv)
416 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
417 usage(cmd_property_set_usage);
419 parse_args(argc, argv, cmd_property_set_usage, &types,
420 &object, &name, &value);
421 if (!object || !name || !value) {
422 error("invalid arguments");
423 usage(cmd_property_set_usage);
426 ret = setget_prop(types, object, name, value);
431 static const char * const cmd_property_list_usage[] = {
432 "btrfs property list [-t <type>] <object>",
433 "Lists available properties with their descriptions for the given object.",
434 "Please see the help of 'btrfs property get' for a description of",
435 "objects and object types.",
439 static int cmd_property_list(int argc, char **argv)
445 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
446 usage(cmd_property_list_usage);
448 parse_args(argc, argv, cmd_property_list_usage,
449 &types, &object, NULL, NULL);
451 error("invalid arguments");
452 usage(cmd_property_list_usage);
455 ret = dump_props(types, object, 1);
460 static const char property_cmd_group_info[] =
461 "modify properties of filesystem objects";
463 const struct cmd_group property_cmd_group = {
464 property_cmd_group_usage, property_cmd_group_info, {
465 { "get", cmd_property_get,
466 cmd_property_get_usage, NULL, 0 },
467 { "set", cmd_property_set,
468 cmd_property_set_usage, NULL, 0 },
469 { "list", cmd_property_list,
470 cmd_property_list_usage, NULL, 0 },
475 int cmd_property(int argc, char **argv)
477 return handle_command_group(&property_cmd_group, argc, argv);