btrfs-progs: init variables which are checked later in btrfs-property
[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         } else if (ret) {
280                 fprintf(stderr, "ERROR: parse_prop reported unknown error\n");
281                 ret = 42;
282                 goto out;
283         }
284
285         types &= prop->types;
286         if (!types) {
287                 fprintf(stderr,
288                         "ERROR: object is not compatible with property\n");
289                 ret = 47;
290                 goto out;
291         }
292
293         if (count_bits(types) > 1) {
294                 fprintf(stderr,
295                         "ERROR: type of object is ambiguous. Please specify a type by hand.\n");
296                 ret = 48;
297                 goto out;
298         }
299
300         if (value && prop->read_only) {
301                 fprintf(stderr, "ERROR: %s is a read-only property.\n",
302                                 prop->name);
303                 ret = 51;
304                 goto out;
305         }
306
307         ret = prop->handler(types, object, name, value);
308
309         if (ret < 0)
310                 ret = 50;
311         else
312                 ret = 0;
313
314 out:
315         return ret;
316
317 }
318
319 static void parse_args(int argc, char **argv,
320                        const char * const *usage_str,
321                        int *types, char **object,
322                        char **name, char **value)
323 {
324         int ret;
325         char *type_str = NULL;
326
327         optind = 1;
328         while (1) {
329                 int c = getopt(argc, argv, "t:");
330                 if (c < 0)
331                         break;
332
333                 switch (c) {
334                 case 't':
335                         type_str = optarg;
336                         break;
337                 default:
338                         usage(usage_str);
339                 }
340         }
341
342         *types = 0;
343         if (type_str) {
344                 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
345                         *types = prop_object_subvol;
346                 } else if (!strcmp(type_str, "f") ||
347                            !strcmp(type_str, "filesystem")) {
348                         *types = prop_object_root;
349                 } else if (!strcmp(type_str, "i") ||
350                            !strcmp(type_str, "inode")) {
351                         *types = prop_object_inode;
352                 } else if (!strcmp(type_str, "d") ||
353                            !strcmp(type_str, "device")) {
354                         *types = prop_object_dev;
355                 } else {
356                         fprintf(stderr, "ERROR: invalid object type.\n");
357                         usage(usage_str);
358                 }
359         }
360
361         if (object && optind < argc)
362                 *object = argv[optind++];
363         if (name && optind < argc)
364                 *name = argv[optind++];
365         if (value && optind < argc)
366                 *value = argv[optind++];
367
368         if (optind != argc) {
369                 fprintf(stderr, "ERROR: invalid arguments.\n");
370                 usage(usage_str);
371         }
372
373         if (!*types && object && *object) {
374                 ret = autodetect_object_types(*object, types);
375                 if (ret < 0) {
376                         fprintf(stderr,
377                                 "ERROR: failed to detect object type. %s\n",
378                                 strerror(-ret));
379                         usage(usage_str);
380                 }
381                 if (!*types) {
382                         fprintf(stderr,
383                                 "ERROR: object is not a btrfs object.\n");
384                         usage(usage_str);
385                 }
386         }
387 }
388
389 static int cmd_get(int argc, char **argv)
390 {
391         int ret;
392         char *object = NULL;
393         char *name = NULL;
394         int types = 0;
395
396         if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
397                 usage(cmd_get_usage);
398
399         parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
400         if (!object) {
401                 fprintf(stderr, "ERROR: invalid arguments.\n");
402                 usage(cmd_set_usage);
403         }
404
405         if (name)
406                 ret = setget_prop(types, object, name, NULL);
407         else
408                 ret = dump_props(types, object, 0);
409
410         return ret;
411 }
412
413 static int cmd_set(int argc, char **argv)
414 {
415         int ret;
416         char *object = NULL;
417         char *name = NULL;
418         char *value = NULL;
419         int types = 0;
420
421         if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
422                 usage(cmd_set_usage);
423
424         parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
425         if (!object || !name || !value) {
426                 fprintf(stderr, "ERROR: invalid arguments.\n");
427                 usage(cmd_set_usage);
428         }
429
430         ret = setget_prop(types, object, name, value);
431
432         return ret;
433 }
434
435 static int cmd_list(int argc, char **argv)
436 {
437         int ret;
438         char *object = NULL;
439         int types = 0;
440
441         if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
442                 usage(cmd_list_usage);
443
444         parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
445         if (!object) {
446                 fprintf(stderr, "ERROR: invalid arguments.\n");
447                 usage(cmd_set_usage);
448         }
449
450         ret = dump_props(types, object, 1);
451
452         return ret;
453 }
454
455 const struct cmd_group property_cmd_group = {
456         property_cmd_group_usage, NULL, {
457                 { "get", cmd_get, cmd_get_usage, NULL, 0 },
458                 { "set", cmd_set, cmd_set_usage, NULL, 0 },
459                 { "list", cmd_list, cmd_list_usage, NULL, 0 },
460                 { 0, 0, 0, 0, 0 },
461         }
462 };
463
464 int cmd_property(int argc, char **argv)
465 {
466         return handle_command_group(&property_cmd_group, argc, argv);
467 }