btrfs-progs: btrfs: Add missing btrfs_close_all_devices for btrfs command
[btrfs-progs-unstable/devel.git] / cmds-property.c
blob0ffd2507396ef4138a9ebd3c9b219d2ace790f6f
1 /*
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.
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
25 #include "commands.h"
26 #include "props.h"
27 #include "ctree.h"
28 #include "utils.h"
30 static const char * const property_cmd_group_usage[] = {
31 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
32 NULL
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",
39 "printed.",
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].",
45 NULL
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.",
53 NULL
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.",
61 NULL
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)) {
71 *prop_ret = prop;
72 return 0;
76 return -1;
79 static int get_fsid(const char *path, u8 *fsid, int silent)
81 int ret;
82 int fd;
83 struct btrfs_ioctl_fs_info_args args;
85 fd = open(path, O_RDONLY);
86 if (fd < 0) {
87 ret = -errno;
88 if (!silent)
89 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
90 strerror(-ret));
91 goto out;
94 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
95 if (ret < 0) {
96 ret = -errno;
97 goto out;
100 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
101 ret = 0;
103 out:
104 if (fd != -1)
105 close(fd);
106 return ret;
109 static int check_btrfs_object(const char *object)
111 int ret;
112 u8 fsid[BTRFS_FSID_SIZE];
114 ret = get_fsid(object, fsid, 0);
115 if (ret < 0)
116 ret = 0;
117 else
118 ret = 1;
119 return ret;
122 static int check_is_root(const char *object)
124 int ret;
125 u8 fsid[BTRFS_FSID_SIZE];
126 u8 fsid2[BTRFS_FSID_SIZE];
127 char *tmp = NULL;
128 char *rp;
130 rp = realpath(object, NULL);
131 if (!rp) {
132 ret = -errno;
133 goto out;
135 if (!strcmp(rp, "/")) {
136 ret = 0;
137 goto out;
140 tmp = malloc(strlen(object) + 5);
141 if (!tmp) {
142 ret = -ENOMEM;
143 goto out;
145 strcpy(tmp, object);
146 if (tmp[strlen(tmp) - 1] != '/')
147 strcat(tmp, "/");
148 strcat(tmp, "..");
150 ret = get_fsid(object, fsid, 0);
151 if (ret < 0) {
152 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object,
153 strerror(-ret));
154 goto out;
157 ret = get_fsid(tmp, fsid2, 1);
158 if (ret == -ENOTTY) {
159 ret = 0;
160 goto out;
161 } else if (ret == -ENOTDIR) {
162 ret = 1;
163 goto out;
164 } else if (ret < 0) {
165 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", tmp,
166 strerror(-ret));
167 goto out;
170 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
171 ret = 0;
172 goto out;
175 ret = 1;
177 out:
178 free(tmp);
179 free(rp);
180 return ret;
183 static int count_bits(int v)
185 unsigned int tmp = (unsigned int)v;
186 int cnt = 0;
188 while (tmp) {
189 if (tmp & 1)
190 cnt++;
191 tmp >>= 1;
193 return cnt;
196 static int autodetect_object_types(const char *object, int *types_out)
198 int ret;
199 int is_btrfs_object;
200 int types = 0;
201 struct stat st;
203 is_btrfs_object = check_btrfs_object(object);
205 ret = lstat(object, &st);
206 if (ret < 0) {
207 ret = -errno;
208 goto out;
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);
217 if (ret < 0)
218 goto out;
219 if (!ret)
220 types |= prop_object_root;
223 if (S_ISBLK(st.st_mode))
224 types |= prop_object_dev;
226 ret = 0;
227 *types_out = types;
229 out:
230 return ret;
233 static int print_prop_help(const struct prop_handler *prop)
235 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
236 return 0;
239 static int dump_prop(const struct prop_handler *prop,
240 const char *object,
241 int types,
242 int type,
243 int name_and_help)
245 int ret = 0;
247 if ((types & type) && (prop->types & type)) {
248 if (!name_and_help)
249 ret = prop->handler(type, object, prop->name, NULL);
250 else
251 ret = print_prop_help(prop);
253 return ret;
256 static int dump_props(int types, const char *object, int name_and_help)
258 int ret;
259 int i;
260 int j;
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);
267 if (ret < 0) {
268 ret = 50;
269 goto out;
274 ret = 0;
276 out:
277 return ret;
280 static int setget_prop(int types, const char *object,
281 const char *name, const char *value)
283 int ret;
284 const struct prop_handler *prop = NULL;
286 ret = parse_prop(name, prop_handlers, &prop);
287 if (ret == -1) {
288 fprintf(stderr, "ERROR: property is unknown\n");
289 ret = 40;
290 goto out;
293 types &= prop->types;
294 if (!types) {
295 fprintf(stderr,
296 "ERROR: object is not compatible with property\n");
297 ret = 47;
298 goto out;
301 if (count_bits(types) > 1) {
302 fprintf(stderr,
303 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
304 ret = 48;
305 goto out;
308 if (value && prop->read_only) {
309 fprintf(stderr, "ERROR: %s is a read-only property.\n",
310 prop->name);
311 ret = 51;
312 goto out;
315 ret = prop->handler(types, object, name, value);
317 if (ret < 0)
318 ret = 50;
319 else
320 ret = 0;
322 out:
323 return ret;
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)
332 int ret;
333 char *type_str = NULL;
335 optind = 1;
336 while (1) {
337 int c = getopt(argc, argv, "t:");
338 if (c < 0)
339 break;
341 switch (c) {
342 case 't':
343 type_str = optarg;
344 break;
345 default:
346 usage(usage_str);
350 *types = 0;
351 if (type_str) {
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;
363 } else {
364 fprintf(stderr, "ERROR: invalid object type.\n");
365 usage(usage_str);
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");
378 usage(usage_str);
381 if (!*types && object && *object) {
382 ret = autodetect_object_types(*object, types);
383 if (ret < 0) {
384 fprintf(stderr,
385 "ERROR: failed to detect object type. %s\n",
386 strerror(-ret));
387 usage(usage_str);
389 if (!*types) {
390 fprintf(stderr,
391 "ERROR: object is not a btrfs object.\n");
392 usage(usage_str);
397 static int cmd_property_get(int argc, char **argv)
399 int ret;
400 char *object = NULL;
401 char *name = NULL;
402 int types = 0;
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,
408 NULL);
409 if (!object) {
410 fprintf(stderr, "ERROR: invalid arguments.\n");
411 usage(cmd_property_set_usage);
414 if (name)
415 ret = setget_prop(types, object, name, NULL);
416 else
417 ret = dump_props(types, object, 0);
419 return ret;
422 static int cmd_property_set(int argc, char **argv)
424 int ret;
425 char *object = NULL;
426 char *name = NULL;
427 char *value = NULL;
428 int types = 0;
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);
442 return ret;
445 static int cmd_property_list(int argc, char **argv)
447 int ret;
448 char *object = NULL;
449 int types = 0;
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);
456 if (!object) {
457 fprintf(stderr, "ERROR: invalid arguments.\n");
458 usage(cmd_property_set_usage);
461 ret = dump_props(types, object, 1);
463 return ret;
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 },
477 NULL_CMD_STRUCT
481 int cmd_property(int argc, char **argv)
483 return handle_command_group(&property_cmd_group, argc, argv);