btrfs-progs: skip erroneous free before initialization
[btrfs-progs-unstable/devel.git] / cmds-property.c
blobdf53f918a4dbfc60413acc8f392785abba1aad48
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"
29 static const char * const property_cmd_group_usage[] = {
30 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
31 NULL
34 static const char * const cmd_get_usage[] = {
35 "btrfs property get [-t <type>] <object> [<name>]",
36 "Gets a property from a btrfs object.",
37 "If no name is specified, all properties for the given object are",
38 "printed.",
39 "A filesystem object can be a the filesystem itself, a subvolume,",
40 "an inode or a device. The '-t <type>' option can be used to explicitly",
41 "specify what type of object you meant. This is only needed when a",
42 "property could be set for more then one object type. Possible types",
43 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
44 NULL
47 static const char * const cmd_set_usage[] = {
48 "btrfs property set [-t <type>] <object> <name> <value>",
49 "Sets a property on a btrfs object.",
50 "Please see the help of 'btrfs property get' for a description of",
51 "objects and object types.",
52 NULL
55 static const char * const cmd_list_usage[] = {
56 "btrfs property list [-t <type>] <object>",
57 "Lists available properties with their descriptions for the given object.",
58 "Please see the help of 'btrfs property get' for a description of",
59 "objects and object types.",
60 NULL
63 static int parse_prop(const char *arg, const struct prop_handler *props,
64 const struct prop_handler **prop_ret)
66 const struct prop_handler *prop = props;
68 for (; prop->name; prop++) {
69 if (!strcmp(prop->name, arg)) {
70 *prop_ret = prop;
71 return 0;
75 return -1;
78 static int get_fsid(const char *path, u8 *fsid, int silent)
80 int ret;
81 int fd;
82 struct btrfs_ioctl_fs_info_args args;
84 fd = open(path, O_RDONLY);
85 if (fd < 0) {
86 ret = -errno;
87 if (!silent)
88 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
89 strerror(-ret));
90 goto out;
93 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
94 if (ret < 0) {
95 ret = -errno;
96 goto out;
99 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
100 ret = 0;
102 out:
103 if (fd != -1)
104 close(fd);
105 return ret;
108 static int check_btrfs_object(const char *object)
110 int ret;
111 u8 fsid[BTRFS_FSID_SIZE];
113 ret = get_fsid(object, fsid, 0);
114 if (ret < 0)
115 ret = 0;
116 else
117 ret = 1;
118 return ret;
121 static int check_is_root(const char *object)
123 int ret;
124 u8 fsid[BTRFS_FSID_SIZE];
125 u8 fsid2[BTRFS_FSID_SIZE];
126 char *tmp;
128 tmp = malloc(strlen(object) + 5);
129 if (!tmp) {
130 ret = -ENOMEM;
131 goto out;
133 strcpy(tmp, object);
134 if (tmp[strlen(tmp) - 1] != '/')
135 strcat(tmp, "/");
136 strcat(tmp, "..");
138 ret = get_fsid(object, fsid, 0);
139 if (ret < 0) {
140 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", object,
141 strerror(-ret));
142 goto out;
145 ret = get_fsid(tmp, fsid2, 1);
146 if (ret == -ENOTTY) {
147 ret = 0;
148 goto out;
149 } else if (ret == -ENOTDIR) {
150 ret = 1;
151 goto out;
152 } else if (ret < 0) {
153 fprintf(stderr, "ERROR: get_fsid for %s failed. %s\n", tmp,
154 strerror(-ret));
155 goto out;
158 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
159 ret = 0;
160 goto out;
163 ret = 1;
165 out:
166 free(tmp);
167 return ret;
170 static int count_bits(int v)
172 unsigned int tmp = (unsigned int)v;
173 int cnt = 0;
175 while (tmp) {
176 if (tmp & 1)
177 cnt++;
178 tmp >>= 1;
180 return cnt;
183 static int autodetect_object_types(const char *object, int *types_out)
185 int ret;
186 int is_btrfs_object;
187 int types = 0;
188 struct stat st;
190 is_btrfs_object = check_btrfs_object(object);
192 ret = lstat(object, &st);
193 if (ret < 0) {
194 ret = -errno;
195 goto out;
198 if (is_btrfs_object) {
199 types |= prop_object_inode;
200 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
201 types |= prop_object_subvol;
203 ret = check_is_root(object);
204 if (ret < 0)
205 goto out;
206 if (!ret)
207 types |= prop_object_root;
210 if (S_ISBLK(st.st_mode))
211 types |= prop_object_dev;
213 ret = 0;
214 *types_out = types;
216 out:
217 return ret;
220 static int print_prop_help(const struct prop_handler *prop)
222 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
223 return 0;
226 static int dump_prop(const struct prop_handler *prop,
227 const char *object,
228 int types,
229 int type,
230 int name_and_help)
232 int ret = 0;
234 if ((types & type) && (prop->types & type)) {
235 if (!name_and_help)
236 ret = prop->handler(type, object, prop->name, NULL);
237 else
238 ret = print_prop_help(prop);
240 return ret;
243 static int dump_props(int types, const char *object, int name_and_help)
245 int ret;
246 int i;
247 int j;
248 const struct prop_handler *prop;
250 for (i = 0; prop_handlers[i].name; i++) {
251 prop = &prop_handlers[i];
252 for (j = 1; j < __prop_object_max; j <<= 1) {
253 ret = dump_prop(prop, object, types, j, name_and_help);
254 if (ret < 0) {
255 ret = 50;
256 goto out;
261 ret = 0;
263 out:
264 return ret;
267 static int setget_prop(int types, const char *object,
268 const char *name, const char *value)
270 int ret;
271 const struct prop_handler *prop = NULL;
273 ret = parse_prop(name, prop_handlers, &prop);
274 if (ret == -1) {
275 fprintf(stderr, "ERROR: property is unknown\n");
276 ret = 40;
277 goto out;
278 } else if (ret) {
279 fprintf(stderr, "ERROR: parse_prop reported unknown error\n");
280 ret = 42;
281 goto out;
284 types &= prop->types;
285 if (!types) {
286 fprintf(stderr,
287 "ERROR: object is not compatible with property\n");
288 ret = 47;
289 goto out;
292 if (count_bits(types) > 1) {
293 fprintf(stderr,
294 "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
295 ret = 48;
296 goto out;
299 if (value && prop->read_only) {
300 fprintf(stderr, "ERROR: %s is a read-only property.\n",
301 prop->name);
302 ret = 51;
303 goto out;
306 ret = prop->handler(types, object, name, value);
308 if (ret < 0)
309 ret = 50;
310 else
311 ret = 0;
313 out:
314 return ret;
318 static void parse_args(int argc, char **argv,
319 const char * const *usage_str,
320 int *types, char **object,
321 char **name, char **value)
323 int ret;
324 char *type_str = NULL;
326 optind = 1;
327 while (1) {
328 int c = getopt(argc, argv, "t:");
329 if (c < 0)
330 break;
332 switch (c) {
333 case 't':
334 type_str = optarg;
335 break;
336 default:
337 usage(usage_str);
341 *types = 0;
342 if (type_str) {
343 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
344 *types = prop_object_subvol;
345 } else if (!strcmp(type_str, "f") ||
346 !strcmp(type_str, "filesystem")) {
347 *types = prop_object_root;
348 } else if (!strcmp(type_str, "i") ||
349 !strcmp(type_str, "inode")) {
350 *types = prop_object_inode;
351 } else if (!strcmp(type_str, "d") ||
352 !strcmp(type_str, "device")) {
353 *types = prop_object_dev;
354 } else {
355 fprintf(stderr, "ERROR: invalid object type.\n");
356 usage(usage_str);
360 if (object && optind < argc)
361 *object = argv[optind++];
362 if (name && optind < argc)
363 *name = argv[optind++];
364 if (value && optind < argc)
365 *value = argv[optind++];
367 if (optind != argc) {
368 fprintf(stderr, "ERROR: invalid arguments.\n");
369 usage(usage_str);
372 if (!*types && object && *object) {
373 ret = autodetect_object_types(*object, types);
374 if (ret < 0) {
375 fprintf(stderr,
376 "ERROR: failed to detect object type. %s\n",
377 strerror(-ret));
378 usage(usage_str);
380 if (!*types) {
381 fprintf(stderr,
382 "ERROR: object is not a btrfs object.\n");
383 usage(usage_str);
388 static int cmd_get(int argc, char **argv)
390 int ret;
391 char *object;
392 char *name = NULL;
393 int types = 0;
395 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
396 usage(cmd_get_usage);
398 parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
399 if (!object) {
400 fprintf(stderr, "ERROR: invalid arguments.\n");
401 usage(cmd_set_usage);
404 if (name)
405 ret = setget_prop(types, object, name, NULL);
406 else
407 ret = dump_props(types, object, 0);
409 return ret;
412 static int cmd_set(int argc, char **argv)
414 int ret;
415 char *object;
416 char *name;
417 char *value;
418 int types = 0;
420 if (check_argc_min(argc, 4) || check_argc_max(argc, 5))
421 usage(cmd_set_usage);
423 parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
424 if (!object || !name || !value) {
425 fprintf(stderr, "ERROR: invalid arguments.\n");
426 usage(cmd_set_usage);
429 ret = setget_prop(types, object, name, value);
431 return ret;
434 static int cmd_list(int argc, char **argv)
436 int ret;
437 char *object = NULL;
438 int types = 0;
440 if (check_argc_min(argc, 2) || check_argc_max(argc, 3))
441 usage(cmd_list_usage);
443 parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
444 if (!object) {
445 fprintf(stderr, "ERROR: invalid arguments.\n");
446 usage(cmd_set_usage);
449 ret = dump_props(types, object, 1);
451 return ret;
454 const struct cmd_group property_cmd_group = {
455 property_cmd_group_usage, NULL, {
456 { "get", cmd_get, cmd_get_usage, NULL, 0 },
457 { "set", cmd_set, cmd_set_usage, NULL, 0 },
458 { "list", cmd_list, cmd_list_usage, NULL, 0 },
459 { 0, 0, 0, 0, 0 },
463 int cmd_property(int argc, char **argv)
465 return handle_command_group(&property_cmd_group, argc, argv);