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 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
];
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 fprintf(stderr
, "ERROR: get_fsid for %s failed. %s\n", object
,
157 ret
= get_fsid(tmp
, fsid2
, 1);
158 if (ret
== -ENOTTY
) {
161 } else if (ret
== -ENOTDIR
) {
164 } else if (ret
< 0) {
165 fprintf(stderr
, "ERROR: get_fsid for %s failed. %s\n", tmp
,
170 if (memcmp(fsid
, fsid2
, BTRFS_FSID_SIZE
)) {
183 static int count_bits(int v
)
185 unsigned int tmp
= (unsigned int)v
;
196 static int autodetect_object_types(const char *object
, int *types_out
)
203 is_btrfs_object
= check_btrfs_object(object
);
205 ret
= lstat(object
, &st
);
211 if (is_btrfs_object
) {
212 types
|= prop_object_inode
;
213 if (st
.st_ino
== BTRFS_FIRST_FREE_OBJECTID
)
214 types
|= prop_object_subvol
;
216 ret
= check_is_root(object
);
220 types
|= prop_object_root
;
223 if (S_ISBLK(st
.st_mode
))
224 types
|= prop_object_dev
;
233 static int print_prop_help(const struct prop_handler
*prop
)
235 fprintf(stdout
, "%-20s%s\n", prop
->name
, prop
->desc
);
239 static int dump_prop(const struct prop_handler
*prop
,
247 if ((types
& type
) && (prop
->types
& type
)) {
249 ret
= prop
->handler(type
, object
, prop
->name
, NULL
);
251 ret
= print_prop_help(prop
);
256 static int dump_props(int types
, const char *object
, int name_and_help
)
261 const struct prop_handler
*prop
;
263 for (i
= 0; prop_handlers
[i
].name
; i
++) {
264 prop
= &prop_handlers
[i
];
265 for (j
= 1; j
< __prop_object_max
; j
<<= 1) {
266 ret
= dump_prop(prop
, object
, types
, j
, name_and_help
);
280 static int setget_prop(int types
, const char *object
,
281 const char *name
, const char *value
)
284 const struct prop_handler
*prop
= NULL
;
286 ret
= parse_prop(name
, prop_handlers
, &prop
);
288 fprintf(stderr
, "ERROR: property is unknown\n");
293 types
&= prop
->types
;
296 "ERROR: object is not compatible with property\n");
301 if (count_bits(types
) > 1) {
303 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
308 if (value
&& prop
->read_only
) {
309 fprintf(stderr
, "ERROR: %s is a read-only property.\n",
315 ret
= prop
->handler(types
, object
, name
, value
);
327 static void parse_args(int argc
, char **argv
,
328 const char * const *usage_str
,
329 int *types
, char **object
,
330 char **name
, char **value
)
333 char *type_str
= NULL
;
337 int c
= getopt(argc
, argv
, "t:");
352 if (!strcmp(type_str
, "s") || !strcmp(type_str
, "subvol")) {
353 *types
= prop_object_subvol
;
354 } else if (!strcmp(type_str
, "f") ||
355 !strcmp(type_str
, "filesystem")) {
356 *types
= prop_object_root
;
357 } else if (!strcmp(type_str
, "i") ||
358 !strcmp(type_str
, "inode")) {
359 *types
= prop_object_inode
;
360 } else if (!strcmp(type_str
, "d") ||
361 !strcmp(type_str
, "device")) {
362 *types
= prop_object_dev
;
364 fprintf(stderr
, "ERROR: invalid object type.\n");
369 if (object
&& optind
< argc
)
370 *object
= argv
[optind
++];
371 if (name
&& optind
< argc
)
372 *name
= argv
[optind
++];
373 if (value
&& optind
< argc
)
374 *value
= argv
[optind
++];
376 if (optind
!= argc
) {
377 fprintf(stderr
, "ERROR: invalid arguments.\n");
381 if (!*types
&& object
&& *object
) {
382 ret
= autodetect_object_types(*object
, types
);
385 "ERROR: failed to detect object type. %s\n",
391 "ERROR: object is not a btrfs object.\n");
397 static int cmd_property_get(int argc
, char **argv
)
404 if (check_argc_min(argc
, 2) || check_argc_max(argc
, 5))
405 usage(cmd_property_get_usage
);
407 parse_args(argc
, argv
, cmd_property_get_usage
, &types
, &object
, &name
,
410 fprintf(stderr
, "ERROR: invalid arguments.\n");
411 usage(cmd_property_set_usage
);
415 ret
= setget_prop(types
, object
, name
, NULL
);
417 ret
= dump_props(types
, object
, 0);
422 static int cmd_property_set(int argc
, char **argv
)
430 if (check_argc_min(argc
, 4) || check_argc_max(argc
, 6))
431 usage(cmd_property_set_usage
);
433 parse_args(argc
, argv
, cmd_property_set_usage
, &types
,
434 &object
, &name
, &value
);
435 if (!object
|| !name
|| !value
) {
436 fprintf(stderr
, "ERROR: invalid arguments.\n");
437 usage(cmd_property_set_usage
);
440 ret
= setget_prop(types
, object
, name
, value
);
445 static int cmd_property_list(int argc
, char **argv
)
451 if (check_argc_min(argc
, 2) || check_argc_max(argc
, 4))
452 usage(cmd_property_list_usage
);
454 parse_args(argc
, argv
, cmd_property_list_usage
,
455 &types
, &object
, NULL
, NULL
);
457 fprintf(stderr
, "ERROR: invalid arguments.\n");
458 usage(cmd_property_set_usage
);
461 ret
= dump_props(types
, object
, 1);
466 static const char property_cmd_group_info
[] =
467 "modify properties of filesystem objects";
469 const struct cmd_group property_cmd_group
= {
470 property_cmd_group_usage
, property_cmd_group_info
, {
471 { "get", cmd_property_get
,
472 cmd_property_get_usage
, NULL
, 0 },
473 { "set", cmd_property_set
,
474 cmd_property_set_usage
, NULL
, 0 },
475 { "list", cmd_property_list
,
476 cmd_property_list_usage
, NULL
, 0 },
481 int cmd_property(int argc
, char **argv
)
483 return handle_command_group(&property_cmd_group
, argc
, argv
);