btrfs-progs: fix find_mount_root() to handle duplicated mount point correctly
[btrfs-progs-unstable/devel.git] / cmds-property.c
bloba7642933473828cd134ff747f8aa1c563c212ab4
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_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_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_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;
129 tmp = malloc(strlen(object) + 5);
130 if (!tmp) {
131 ret = -ENOMEM;
132 goto out;
134 strcpy(tmp, object);
135 if (tmp[strlen(tmp) - 1] != '/')
136 strcat(tmp, "/");
137 strcat(tmp, "..");
139 ret = get_fsid(object, fsid, 0);
140 if (ret < 0) {
141 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object,
142 strerror(-ret));
143 goto out;
146 ret = get_fsid(tmp, fsid2, 1);
147 if (ret == -ENOTTY) {
148 ret = 0;
149 goto out;
150 } else if (ret == -ENOTDIR) {
151 ret = 1;
152 goto out;
153 } else if (ret < 0) {
154 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", tmp,
155 strerror(-ret));
156 goto out;
159 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
160 ret = 0;
161 goto out;
164 ret = 1;
166 out:
167 free(tmp);
168 return ret;
171 static int count_bits(int v)
173 unsigned int tmp = (unsigned int)v;
174 int cnt = 0;
176 while (tmp) {
177 if (tmp & 1)
178 cnt++;
179 tmp >>= 1;
181 return cnt;
184 static int autodetect_object_types(const char *object, int *types_out)
186 int ret;
187 int is_btrfs_object;
188 int types = 0;
189 struct stat st;
191 is_btrfs_object = check_btrfs_object(object);
193 ret = lstat(object, &st);
194 if (ret < 0) {
195 ret = -errno;
196 goto out;
199 if (is_btrfs_object) {
200 types |= prop_object_inode;
201 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
202 types |= prop_object_subvol;
204 ret = check_is_root(object);
205 if (ret < 0)
206 goto out;
207 if (!ret)
208 types |= prop_object_root;
211 if (S_ISBLK(st.st_mode))
212 types |= prop_object_dev;
214 ret = 0;
215 *types_out = types;
217 out:
218 return ret;
221 static int print_prop_help(const struct prop_handler *prop)
223 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
224 return 0;
227 static int dump_prop(const struct prop_handler *prop,
228 const char *object,
229 int types,
230 int type,
231 int name_and_help)
233 int ret = 0;
235 if ((types & type) && (prop->types & type)) {
236 if (!name_and_help)
237 ret = prop->handler(type, object, prop->name, NULL);
238 else
239 ret = print_prop_help(prop);
241 return ret;
244 static int dump_props(int types, const char *object, int name_and_help)
246 int ret;
247 int i;
248 int j;
249 const struct prop_handler *prop;
251 for (i = 0; prop_handlers[i].name; i++) {
252 prop = &prop_handlers[i];
253 for (j = 1; j < __prop_object_max; j <<= 1) {
254 ret = dump_prop(prop, object, types, j, name_and_help);
255 if (ret < 0) {
256 ret = 50;
257 goto out;
262 ret = 0;
264 out:
265 return ret;
268 static int setget_prop(int types, const char *object,
269 const char *name, const char *value)
271 int ret;
272 const struct prop_handler *prop = NULL;
274 ret = parse_prop(name, prop_handlers, &prop);
275 if (ret == -1) {
276 fprintf(stderr, "ERROR: property is unknown\n");
277 ret = 40;
278 goto out;
281 types &= prop->types;
282 if (!types) {
283 fprintf(stderr,
284 "ERROR: object is not compatible with property\n");
285 ret = 47;
286 goto out;
289 if (count_bits(types) > 1) {
290 fprintf(stderr,
291 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
292 ret = 48;
293 goto out;
296 if (value && prop->read_only) {
297 fprintf(stderr, "ERROR: %s is a read-only property.\n",
298 prop->name);
299 ret = 51;
300 goto out;
303 ret = prop->handler(types, object, name, value);
305 if (ret < 0)
306 ret = 50;
307 else
308 ret = 0;
310 out:
311 return ret;
315 static void parse_args(int argc, char **argv,
316 const char * const *usage_str,
317 int *types, char **object,
318 char **name, char **value)
320 int ret;
321 char *type_str = NULL;
323 optind = 1;
324 while (1) {
325 int c = getopt(argc, argv, "t:");
326 if (c < 0)
327 break;
329 switch (c) {
330 case 't':
331 type_str = optarg;
332 break;
333 default:
334 usage(usage_str);
338 *types = 0;
339 if (type_str) {
340 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
341 *types = prop_object_subvol;
342 } else if (!strcmp(type_str, "f") ||
343 !strcmp(type_str, "filesystem")) {
344 *types = prop_object_root;
345 } else if (!strcmp(type_str, "i") ||
346 !strcmp(type_str, "inode")) {
347 *types = prop_object_inode;
348 } else if (!strcmp(type_str, "d") ||
349 !strcmp(type_str, "device")) {
350 *types = prop_object_dev;
351 } else {
352 fprintf(stderr, "ERROR: invalid object type.\n");
353 usage(usage_str);
357 if (object && optind < argc)
358 *object = argv[optind++];
359 if (name && optind < argc)
360 *name = argv[optind++];
361 if (value && optind < argc)
362 *value = argv[optind++];
364 if (optind != argc) {
365 fprintf(stderr, "ERROR: invalid arguments.\n");
366 usage(usage_str);
369 if (!*types && object && *object) {
370 ret = autodetect_object_types(*object, types);
371 if (ret < 0) {
372 fprintf(stderr,
373 "ERROR: failed to detect object type. %s\n",
374 strerror(-ret));
375 usage(usage_str);
377 if (!*types) {
378 fprintf(stderr,
379 "ERROR: object is not a btrfs object.\n");
380 usage(usage_str);
385 static int cmd_get(int argc, char **argv)
387 int ret;
388 char *object = NULL;
389 char *name = NULL;
390 int types = 0;
392 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
393 usage(cmd_get_usage);
395 parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
396 if (!object) {
397 fprintf(stderr, "ERROR: invalid arguments.\n");
398 usage(cmd_set_usage);
401 if (name)
402 ret = setget_prop(types, object, name, NULL);
403 else
404 ret = dump_props(types, object, 0);
406 return ret;
409 static int cmd_set(int argc, char **argv)
411 int ret;
412 char *object = NULL;
413 char *name = NULL;
414 char *value = NULL;
415 int types = 0;
417 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
418 usage(cmd_set_usage);
420 parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
421 if (!object || !name || !value) {
422 fprintf(stderr, "ERROR: invalid arguments.\n");
423 usage(cmd_set_usage);
426 ret = setget_prop(types, object, name, value);
428 return ret;
431 static int cmd_list(int argc, char **argv)
433 int ret;
434 char *object = NULL;
435 int types = 0;
437 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
438 usage(cmd_list_usage);
440 parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
441 if (!object) {
442 fprintf(stderr, "ERROR: invalid arguments.\n");
443 usage(cmd_set_usage);
446 ret = dump_props(types, object, 1);
448 return ret;
451 const struct cmd_group property_cmd_group = {
452 property_cmd_group_usage, NULL, {
453 { "get", cmd_get, cmd_get_usage, NULL, 0 },
454 { "set", cmd_set, cmd_set_usage, NULL, 0 },
455 { "list", cmd_list, cmd_list_usage, NULL, 0 },
456 { 0, 0, 0, 0, 0 },
460 int cmd_property(int argc, char **argv)
462 return handle_command_group(&property_cmd_group, argc, argv);