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>
31 static const char * const property_cmd_group_usage[] = {
32 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
36 static int parse_prop(const char *arg, const struct prop_handler *props,
37 const struct prop_handler **prop_ret)
39 const struct prop_handler *prop = props;
41 for (; prop->name; prop++) {
42 if (!strcmp(prop->name, arg)) {
51 static int get_fsid(const char *path, u8 *fsid, int silent)
55 struct btrfs_ioctl_fs_info_args args;
57 fd = open(path, O_RDONLY);
61 error("failed to open %s: %s", path,
66 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
72 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
81 static int check_btrfs_object(const char *object)
84 u8 fsid[BTRFS_FSID_SIZE];
86 ret = get_fsid(object, fsid, 0);
94 static int check_is_root(const char *object)
97 u8 fsid[BTRFS_FSID_SIZE];
98 u8 fsid2[BTRFS_FSID_SIZE];
102 rp = realpath(object, NULL);
107 if (!strcmp(rp, "/")) {
112 tmp = malloc(strlen(object) + 5);
118 if (tmp[strlen(tmp) - 1] != '/')
122 ret = get_fsid(object, fsid, 0);
124 error("get_fsid for %s failed: %s", object, strerror(-ret));
128 ret = get_fsid(tmp, fsid2, 1);
129 if (ret == -ENOTTY) {
132 } else if (ret == -ENOTDIR) {
135 } else if (ret < 0) {
136 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
140 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
153 static int count_bits(int v)
155 unsigned int tmp = (unsigned int)v;
166 static int autodetect_object_types(const char *object, int *types_out)
173 is_btrfs_object = check_btrfs_object(object);
175 ret = lstat(object, &st);
181 if (is_btrfs_object) {
182 types |= prop_object_inode;
183 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
184 types |= prop_object_subvol;
186 ret = check_is_root(object);
190 types |= prop_object_root;
193 if (S_ISBLK(st.st_mode))
194 types |= prop_object_dev;
203 static int dump_prop(const struct prop_handler *prop,
211 if ((types & type) && (prop->types & type)) {
213 ret = prop->handler(type, object, prop->name, NULL);
215 printf("%-20s%s\n", prop->name, prop->desc);
220 static int dump_props(int types, const char *object, int name_and_help)
225 const struct prop_handler *prop;
227 for (i = 0; prop_handlers[i].name; i++) {
228 prop = &prop_handlers[i];
229 for (j = 1; j < __prop_object_max; j <<= 1) {
230 ret = dump_prop(prop, object, types, j, name_and_help);
244 static int setget_prop(int types, const char *object,
245 const char *name, const char *value)
248 const struct prop_handler *prop = NULL;
250 ret = parse_prop(name, prop_handlers, &prop);
252 error("unknown property: %s", name);
257 types &= prop->types;
259 error("object is not compatible with property: %s", prop->name);
264 if (count_bits(types) > 1) {
265 error("type of object is ambiguous, please use option -t");
270 if (value && prop->read_only) {
271 error("property is read-only property: %s",
277 ret = prop->handler(types, object, name, value);
289 static void parse_args(int argc, char **argv,
290 const char * const *usage_str,
291 int *types, char **object,
292 char **name, char **value, int min_nonopt_args)
295 char *type_str = NULL;
296 int max_nonopt_args = 1;
300 int c = getopt(argc, argv, "t:");
318 if (check_argc_min(argc - optind, min_nonopt_args) ||
319 check_argc_max(argc - optind, max_nonopt_args))
324 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
325 *types = prop_object_subvol;
326 } else if (!strcmp(type_str, "f") ||
327 !strcmp(type_str, "filesystem")) {
328 *types = prop_object_root;
329 } else if (!strcmp(type_str, "i") ||
330 !strcmp(type_str, "inode")) {
331 *types = prop_object_inode;
332 } else if (!strcmp(type_str, "d") ||
333 !strcmp(type_str, "device")) {
334 *types = prop_object_dev;
336 error("invalid object type: %s", type_str);
341 *object = argv[optind++];
343 *name = argv[optind++];
345 *value = argv[optind++];
348 ret = autodetect_object_types(*object, types);
350 error("failed to detect object type: %s",
355 error("object is not a btrfs object: %s", *object);
361 static const char * const cmd_property_get_usage[] = {
362 "btrfs property get [-t <type>] <object> [<name>]",
363 "Gets a property from a btrfs object.",
364 "If no name is specified, all properties for the given object are",
366 "A filesystem object can be a the filesystem itself, a subvolume,",
367 "an inode or a device. The '-t <type>' option can be used to explicitly",
368 "specify what type of object you meant. This is only needed when a",
369 "property could be set for more then one object type. Possible types",
370 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
374 static int cmd_property_get(int argc, char **argv)
381 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
385 ret = setget_prop(types, object, name, NULL);
387 ret = dump_props(types, object, 0);
392 static const char * const cmd_property_set_usage[] = {
393 "btrfs property set [-t <type>] <object> <name> <value>",
394 "Sets a property on a btrfs object.",
395 "Please see the help of 'btrfs property get' for a description of",
396 "objects and object types.",
400 static int cmd_property_set(int argc, char **argv)
408 parse_args(argc, argv, cmd_property_set_usage, &types,
409 &object, &name, &value, 3);
411 ret = setget_prop(types, object, name, value);
416 static const char * const cmd_property_list_usage[] = {
417 "btrfs property list [-t <type>] <object>",
418 "Lists available properties with their descriptions for the given object.",
419 "Please see the help of 'btrfs property get' for a description of",
420 "objects and object types.",
424 static int cmd_property_list(int argc, char **argv)
430 parse_args(argc, argv, cmd_property_list_usage,
431 &types, &object, NULL, NULL, 1);
433 ret = dump_props(types, object, 1);
438 static const char property_cmd_group_info[] =
439 "modify properties of filesystem objects";
441 const struct cmd_group property_cmd_group = {
442 property_cmd_group_usage, property_cmd_group_info, {
443 { "get", cmd_property_get,
444 cmd_property_get_usage, NULL, 0 },
445 { "set", cmd_property_set,
446 cmd_property_set_usage, NULL, 0 },
447 { "list", cmd_property_list,
448 cmd_property_list_usage, NULL, 0 },
453 int cmd_property(int argc, char **argv)
455 return handle_command_group(&property_cmd_group, argc, argv);