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_property_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_property_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_property_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 error("failed to open %s: %s", 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];
130 rp = realpath(object, NULL);
135 if (!strcmp(rp, "/")) {
140 tmp = malloc(strlen(object) + 5);
146 if (tmp[strlen(tmp) - 1] != '/')
150 ret = get_fsid(object, fsid, 0);
152 error("get_fsid for %s failed: %s", object, strerror(-ret));
156 ret = get_fsid(tmp, fsid2, 1);
157 if (ret == -ENOTTY) {
160 } else if (ret == -ENOTDIR) {
163 } else if (ret < 0) {
164 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
168 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
181 static int count_bits(int v)
183 unsigned int tmp = (unsigned int)v;
194 static int autodetect_object_types(const char *object, int *types_out)
201 is_btrfs_object = check_btrfs_object(object);
203 ret = lstat(object, &st);
209 if (is_btrfs_object) {
210 types |= prop_object_inode;
211 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
212 types |= prop_object_subvol;
214 ret = check_is_root(object);
218 types |= prop_object_root;
221 if (S_ISBLK(st.st_mode))
222 types |= prop_object_dev;
231 static int print_prop_help(const struct prop_handler *prop)
233 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
237 static int dump_prop(const struct prop_handler *prop,
245 if ((types & type) && (prop->types & type)) {
247 ret = prop->handler(type, object, prop->name, NULL);
249 ret = print_prop_help(prop);
254 static int dump_props(int types, const char *object, int name_and_help)
259 const struct prop_handler *prop;
261 for (i = 0; prop_handlers[i].name; i++) {
262 prop = &prop_handlers[i];
263 for (j = 1; j < __prop_object_max; j <<= 1) {
264 ret = dump_prop(prop, object, types, j, name_and_help);
278 static int setget_prop(int types, const char *object,
279 const char *name, const char *value)
282 const struct prop_handler *prop = NULL;
284 ret = parse_prop(name, prop_handlers, &prop);
286 error("unknown property: %s", name);
291 types &= prop->types;
293 error("object is not compatible with property: %s", prop->name);
298 if (count_bits(types) > 1) {
299 error("type of object is ambiguous, please use option -t");
304 if (value && prop->read_only) {
305 error("property is read-only property: %s",
311 ret = prop->handler(types, object, name, value);
323 static void parse_args(int argc, char **argv,
324 const char * const *usage_str,
325 int *types, char **object,
326 char **name, char **value)
329 char *type_str = NULL;
333 int c = getopt(argc, argv, "t:");
348 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
349 *types = prop_object_subvol;
350 } else if (!strcmp(type_str, "f") ||
351 !strcmp(type_str, "filesystem")) {
352 *types = prop_object_root;
353 } else if (!strcmp(type_str, "i") ||
354 !strcmp(type_str, "inode")) {
355 *types = prop_object_inode;
356 } else if (!strcmp(type_str, "d") ||
357 !strcmp(type_str, "device")) {
358 *types = prop_object_dev;
360 error("invalid object type: %s", type_str);
365 if (object && optind < argc)
366 *object = argv[optind++];
367 if (name && optind < argc)
368 *name = argv[optind++];
369 if (value && optind < argc)
370 *value = argv[optind++];
372 if (optind != argc) {
373 error("unexpected agruments found");
377 if (!*types && object && *object) {
378 ret = autodetect_object_types(*object, types);
380 error("failed to detect object type: %s",
385 error("object is not a btrfs object: %s", *object);
391 static int cmd_property_get(int argc, char **argv)
398 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
399 usage(cmd_property_get_usage);
401 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
404 error("invalid arguments");
405 usage(cmd_property_set_usage);
409 ret = setget_prop(types, object, name, NULL);
411 ret = dump_props(types, object, 0);
416 static int cmd_property_set(int argc, char **argv)
424 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
425 usage(cmd_property_set_usage);
427 parse_args(argc, argv, cmd_property_set_usage, &types,
428 &object, &name, &value);
429 if (!object || !name || !value) {
430 error("invalid arguments");
431 usage(cmd_property_set_usage);
434 ret = setget_prop(types, object, name, value);
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_set_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);