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 check_btrfs_object(const char *object)
54 u8 fsid[BTRFS_FSID_SIZE];
56 ret = get_fsid(object, fsid, 0);
64 static int check_is_root(const char *object)
67 u8 fsid[BTRFS_FSID_SIZE];
68 u8 fsid2[BTRFS_FSID_SIZE];
72 rp = realpath(object, NULL);
77 if (!strcmp(rp, "/")) {
82 tmp = malloc(strlen(object) + 5);
88 if (tmp[strlen(tmp) - 1] != '/')
92 ret = get_fsid(object, fsid, 0);
94 error("get_fsid for %s failed: %s", object, strerror(-ret));
98 ret = get_fsid(tmp, fsid2, 1);
102 } else if (ret == -ENOTDIR) {
105 } else if (ret < 0) {
106 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
110 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
123 static int count_bits(int v)
125 unsigned int tmp = (unsigned int)v;
136 static int autodetect_object_types(const char *object, int *types_out)
143 is_btrfs_object = check_btrfs_object(object);
145 ret = lstat(object, &st);
151 if (is_btrfs_object) {
152 types |= prop_object_inode;
153 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
154 types |= prop_object_subvol;
156 ret = check_is_root(object);
160 types |= prop_object_root;
163 if (S_ISBLK(st.st_mode))
164 types |= prop_object_dev;
173 static int dump_prop(const struct prop_handler *prop,
181 if ((types & type) && (prop->types & type)) {
183 ret = prop->handler(type, object, prop->name, NULL);
185 printf("%-20s%s\n", prop->name, prop->desc);
190 static int dump_props(int types, const char *object, int name_and_help)
195 const struct prop_handler *prop;
197 for (i = 0; prop_handlers[i].name; i++) {
198 prop = &prop_handlers[i];
199 for (j = 1; j < __prop_object_max; j <<= 1) {
200 ret = dump_prop(prop, object, types, j, name_and_help);
214 static int setget_prop(int types, const char *object,
215 const char *name, const char *value)
218 const struct prop_handler *prop = NULL;
220 ret = parse_prop(name, prop_handlers, &prop);
222 error("unknown property: %s", name);
227 types &= prop->types;
229 error("object is not compatible with property: %s", prop->name);
234 if (count_bits(types) > 1) {
235 error("type of object is ambiguous, please use option -t");
240 if (value && prop->read_only) {
241 error("property is read-only property: %s",
247 ret = prop->handler(types, object, name, value);
259 static void parse_args(int argc, char **argv,
260 const char * const *usage_str,
261 int *types, char **object,
262 char **name, char **value, int min_nonopt_args)
265 char *type_str = NULL;
266 int max_nonopt_args = 1;
270 int c = getopt(argc, argv, "t:");
288 if (check_argc_min(argc - optind, min_nonopt_args) ||
289 check_argc_max(argc - optind, max_nonopt_args))
294 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
295 *types = prop_object_subvol;
296 } else if (!strcmp(type_str, "f") ||
297 !strcmp(type_str, "filesystem")) {
298 *types = prop_object_root;
299 } else if (!strcmp(type_str, "i") ||
300 !strcmp(type_str, "inode")) {
301 *types = prop_object_inode;
302 } else if (!strcmp(type_str, "d") ||
303 !strcmp(type_str, "device")) {
304 *types = prop_object_dev;
306 error("invalid object type: %s", type_str);
311 *object = argv[optind++];
313 *name = argv[optind++];
315 *value = argv[optind++];
318 ret = autodetect_object_types(*object, types);
320 error("failed to detect object type: %s",
325 error("object is not a btrfs object: %s", *object);
331 static const char * const cmd_property_get_usage[] = {
332 "btrfs property get [-t <type>] <object> [<name>]",
333 "Gets a property from a btrfs object.",
334 "If no name is specified, all properties for the given object are",
336 "A filesystem object can be a the filesystem itself, a subvolume,",
337 "an inode or a device. The '-t <type>' option can be used to explicitly",
338 "specify what type of object you meant. This is only needed when a",
339 "property could be set for more then one object type. Possible types",
340 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
344 static int cmd_property_get(int argc, char **argv)
351 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
355 ret = setget_prop(types, object, name, NULL);
357 ret = dump_props(types, object, 0);
362 static const char * const cmd_property_set_usage[] = {
363 "btrfs property set [-t <type>] <object> <name> <value>",
364 "Sets a property on a btrfs object.",
365 "Please see the help of 'btrfs property get' for a description of",
366 "objects and object types.",
370 static int cmd_property_set(int argc, char **argv)
378 parse_args(argc, argv, cmd_property_set_usage, &types,
379 &object, &name, &value, 3);
381 ret = setget_prop(types, object, name, value);
386 static const char * const cmd_property_list_usage[] = {
387 "btrfs property list [-t <type>] <object>",
388 "Lists available properties with their descriptions for the given object.",
389 "Please see the help of 'btrfs property get' for a description of",
390 "objects and object types.",
394 static int cmd_property_list(int argc, char **argv)
400 parse_args(argc, argv, cmd_property_list_usage,
401 &types, &object, NULL, NULL, 1);
403 ret = dump_props(types, object, 1);
408 static const char property_cmd_group_info[] =
409 "modify properties of filesystem objects";
411 const struct cmd_group property_cmd_group = {
412 property_cmd_group_usage, property_cmd_group_info, {
413 { "get", cmd_property_get,
414 cmd_property_get_usage, NULL, 0 },
415 { "set", cmd_property_set,
416 cmd_property_set_usage, NULL, 0 },
417 { "list", cmd_property_list,
418 cmd_property_list_usage, NULL, 0 },
423 int cmd_property(int argc, char **argv)
425 return handle_command_group(&property_cmd_group, argc, argv);