btrfs-progs: add option to disable backtrace usage
[platform/upstream/btrfs-progs.git] / cmds-property.c
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.
5  *
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.
10  *
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.
15  */
16
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>
24
25 #include "commands.h"
26 #include "props.h"
27 #include "ctree.h"
28 #include "utils.h"
29
30 static const char * const property_cmd_group_usage[] = {
31         "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
32         NULL
33 };
34
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
46 };
47
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
54 };
55
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
62 };
63
64 static int parse_prop(const char *arg, const struct prop_handler *props,
65                       const struct prop_handler **prop_ret)
66 {
67         const struct prop_handler *prop = props;
68
69         for (; prop->name; prop++) {
70                 if (!strcmp(prop->name, arg)) {
71                         *prop_ret = prop;
72                         return 0;
73                 }
74         }
75
76         return -1;
77 }
78
79 static int get_fsid(const char *path, u8 *fsid, int silent)
80 {
81         int ret;
82         int fd;
83         struct btrfs_ioctl_fs_info_args args;
84
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;
92         }
93
94         ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
95         if (ret < 0) {
96                 ret = -errno;
97                 goto out;
98         }
99
100         memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
101         ret = 0;
102
103 out:
104         if (fd != -1)
105                 close(fd);
106         return ret;
107 }
108
109 static int check_btrfs_object(const char *object)
110 {
111         int ret;
112         u8 fsid[BTRFS_FSID_SIZE];
113
114         ret = get_fsid(object, fsid, 0);
115         if (ret < 0)
116                 ret = 0;
117         else
118                 ret = 1;
119         return ret;
120 }
121
122 static int check_is_root(const char *object)
123 {
124         int ret;
125         u8 fsid[BTRFS_FSID_SIZE];
126         u8 fsid2[BTRFS_FSID_SIZE];
127         char *tmp;
128
129         tmp = malloc(strlen(object) + 5);
130         if (!tmp) {
131                 ret = -ENOMEM;
132                 goto out;
133         }
134         strcpy(tmp, object);
135         if (tmp[strlen(tmp) - 1] != '/')
136                 strcat(tmp, "/");
137         strcat(tmp, "..");
138
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;
144         }
145
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;
157         }
158
159         if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
160                 ret = 0;
161                 goto out;
162         }
163
164         ret = 1;
165
166 out:
167         free(tmp);
168         return ret;
169 }
170
171 static int count_bits(int v)
172 {
173         unsigned int tmp = (unsigned int)v;
174         int cnt = 0;
175
176         while (tmp) {
177                 if (tmp & 1)
178                         cnt++;
179                 tmp >>= 1;
180         }
181         return cnt;
182 }
183
184 static int autodetect_object_types(const char *object, int *types_out)
185 {
186         int ret;
187         int is_btrfs_object;
188         int types = 0;
189         struct stat st;
190
191         is_btrfs_object = check_btrfs_object(object);
192
193         ret = lstat(object, &st);
194         if (ret < 0) {
195                 ret = -errno;
196                 goto out;
197         }
198
199         if (is_btrfs_object) {
200                 types |= prop_object_inode;
201                 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
202                         types |= prop_object_subvol;
203
204                 ret = check_is_root(object);
205                 if (ret < 0)
206                         goto out;
207                 if (!ret)
208                         types |= prop_object_root;
209         }
210
211         if (S_ISBLK(st.st_mode))
212                 types |= prop_object_dev;
213
214         ret = 0;
215         *types_out = types;
216
217 out:
218         return ret;
219 }
220
221 static int print_prop_help(const struct prop_handler *prop)
222 {
223         fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
224         return 0;
225 }
226
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)
232 {
233         int ret = 0;
234
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);
240         }
241         return ret;
242 }
243
244 static int dump_props(int types, const char *object, int name_and_help)
245 {
246         int ret;
247         int i;
248         int j;
249         const struct prop_handler *prop;
250
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;
258                         }
259                 }
260         }
261
262         ret = 0;
263
264 out:
265         return ret;
266 }
267
268 static int setget_prop(int types, const char *object,
269                        const char *name, const char *value)
270 {
271         int ret;
272         const struct prop_handler *prop = NULL;
273
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;
279         }
280
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;
287         }
288
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;
294         }
295
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;
301         }
302
303         ret = prop->handler(types, object, name, value);
304
305         if (ret < 0)
306                 ret = 50;
307         else
308                 ret = 0;
309
310 out:
311         return ret;
312
313 }
314
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)
319 {
320         int ret;
321         char *type_str = NULL;
322
323         optind = 1;
324         while (1) {
325                 int c = getopt(argc, argv, "t:");
326                 if (c < 0)
327                         break;
328
329                 switch (c) {
330                 case 't':
331                         type_str = optarg;
332                         break;
333                 default:
334                         usage(usage_str);
335                 }
336         }
337
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);
354                 }
355         }
356
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++];
363
364         if (optind != argc) {
365                 fprintf(stderr, "ERROR: invalid arguments.\n");
366                 usage(usage_str);
367         }
368
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);
376                 }
377                 if (!*types) {
378                         fprintf(stderr,
379                                 "ERROR: object is not a btrfs object.\n");
380                         usage(usage_str);
381                 }
382         }
383 }
384
385 static int cmd_get(int argc, char **argv)
386 {
387         int ret;
388         char *object = NULL;
389         char *name = NULL;
390         int types = 0;
391
392         if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
393                 usage(cmd_get_usage);
394
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);
399         }
400
401         if (name)
402                 ret = setget_prop(types, object, name, NULL);
403         else
404                 ret = dump_props(types, object, 0);
405
406         return ret;
407 }
408
409 static int cmd_set(int argc, char **argv)
410 {
411         int ret;
412         char *object = NULL;
413         char *name = NULL;
414         char *value = NULL;
415         int types = 0;
416
417         if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
418                 usage(cmd_set_usage);
419
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);
424         }
425
426         ret = setget_prop(types, object, name, value);
427
428         return ret;
429 }
430
431 static int cmd_list(int argc, char **argv)
432 {
433         int ret;
434         char *object = NULL;
435         int types = 0;
436
437         if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
438                 usage(cmd_list_usage);
439
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);
444         }
445
446         ret = dump_props(types, object, 1);
447
448         return ret;
449 }
450
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 },
457         }
458 };
459
460 int cmd_property(int argc, char **argv)
461 {
462         return handle_command_group(&property_cmd_group, argc, argv);
463 }