btrfs-progs: alias btrfs device delete to btrfs device remove
[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 = NULL;
128         char *rp;
129
130         rp = realpath(object, NULL);
131         if (!rp) {
132                 ret = -errno;
133                 goto out;
134         }
135         if (!strcmp(rp, "/")) {
136                 ret = 0;
137                 goto out;
138         }
139
140         tmp = malloc(strlen(object) + 5);
141         if (!tmp) {
142                 ret = -ENOMEM;
143                 goto out;
144         }
145         strcpy(tmp, object);
146         if (tmp[strlen(tmp) - 1] != '/')
147                 strcat(tmp, "/");
148         strcat(tmp, "..");
149
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;
155         }
156
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;
168         }
169
170         if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
171                 ret = 0;
172                 goto out;
173         }
174
175         ret = 1;
176
177 out:
178         free(tmp);
179         free(rp);
180         return ret;
181 }
182
183 static int count_bits(int v)
184 {
185         unsigned int tmp = (unsigned int)v;
186         int cnt = 0;
187
188         while (tmp) {
189                 if (tmp & 1)
190                         cnt++;
191                 tmp >>= 1;
192         }
193         return cnt;
194 }
195
196 static int autodetect_object_types(const char *object, int *types_out)
197 {
198         int ret;
199         int is_btrfs_object;
200         int types = 0;
201         struct stat st;
202
203         is_btrfs_object = check_btrfs_object(object);
204
205         ret = lstat(object, &st);
206         if (ret < 0) {
207                 ret = -errno;
208                 goto out;
209         }
210
211         if (is_btrfs_object) {
212                 types |= prop_object_inode;
213                 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
214                         types |= prop_object_subvol;
215
216                 ret = check_is_root(object);
217                 if (ret < 0)
218                         goto out;
219                 if (!ret)
220                         types |= prop_object_root;
221         }
222
223         if (S_ISBLK(st.st_mode))
224                 types |= prop_object_dev;
225
226         ret = 0;
227         *types_out = types;
228
229 out:
230         return ret;
231 }
232
233 static int print_prop_help(const struct prop_handler *prop)
234 {
235         fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
236         return 0;
237 }
238
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)
244 {
245         int ret = 0;
246
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);
252         }
253         return ret;
254 }
255
256 static int dump_props(int types, const char *object, int name_and_help)
257 {
258         int ret;
259         int i;
260         int j;
261         const struct prop_handler *prop;
262
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;
270                         }
271                 }
272         }
273
274         ret = 0;
275
276 out:
277         return ret;
278 }
279
280 static int setget_prop(int types, const char *object,
281                        const char *name, const char *value)
282 {
283         int ret;
284         const struct prop_handler *prop = NULL;
285
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;
291         }
292
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;
299         }
300
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;
306         }
307
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;
313         }
314
315         ret = prop->handler(types, object, name, value);
316
317         if (ret < 0)
318                 ret = 50;
319         else
320                 ret = 0;
321
322 out:
323         return ret;
324
325 }
326
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)
331 {
332         int ret;
333         char *type_str = NULL;
334
335         optind = 1;
336         while (1) {
337                 int c = getopt(argc, argv, "t:");
338                 if (c < 0)
339                         break;
340
341                 switch (c) {
342                 case 't':
343                         type_str = optarg;
344                         break;
345                 default:
346                         usage(usage_str);
347                 }
348         }
349
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);
366                 }
367         }
368
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++];
375
376         if (optind != argc) {
377                 fprintf(stderr, "ERROR: invalid arguments.\n");
378                 usage(usage_str);
379         }
380
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);
388                 }
389                 if (!*types) {
390                         fprintf(stderr,
391                                 "ERROR: object is not a btrfs object.\n");
392                         usage(usage_str);
393                 }
394         }
395 }
396
397 static int cmd_get(int argc, char **argv)
398 {
399         int ret;
400         char *object = NULL;
401         char *name = NULL;
402         int types = 0;
403
404         if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
405                 usage(cmd_get_usage);
406
407         parse_args(argc, argv, cmd_get_usage, &types, &object, &name, NULL);
408         if (!object) {
409                 fprintf(stderr, "ERROR: invalid arguments.\n");
410                 usage(cmd_set_usage);
411         }
412
413         if (name)
414                 ret = setget_prop(types, object, name, NULL);
415         else
416                 ret = dump_props(types, object, 0);
417
418         return ret;
419 }
420
421 static int cmd_set(int argc, char **argv)
422 {
423         int ret;
424         char *object = NULL;
425         char *name = NULL;
426         char *value = NULL;
427         int types = 0;
428
429         if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
430                 usage(cmd_set_usage);
431
432         parse_args(argc, argv, cmd_set_usage, &types, &object, &name, &value);
433         if (!object || !name || !value) {
434                 fprintf(stderr, "ERROR: invalid arguments.\n");
435                 usage(cmd_set_usage);
436         }
437
438         ret = setget_prop(types, object, name, value);
439
440         return ret;
441 }
442
443 static int cmd_list(int argc, char **argv)
444 {
445         int ret;
446         char *object = NULL;
447         int types = 0;
448
449         if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
450                 usage(cmd_list_usage);
451
452         parse_args(argc, argv, cmd_list_usage, &types, &object, NULL, NULL);
453         if (!object) {
454                 fprintf(stderr, "ERROR: invalid arguments.\n");
455                 usage(cmd_set_usage);
456         }
457
458         ret = dump_props(types, object, 1);
459
460         return ret;
461 }
462
463 static const char property_cmd_group_info[] =
464 "modify properties of filesystem objects";
465
466 const struct cmd_group property_cmd_group = {
467         property_cmd_group_usage, property_cmd_group_info, {
468                 { "get", cmd_get, cmd_get_usage, NULL, 0 },
469                 { "set", cmd_set, cmd_set_usage, NULL, 0 },
470                 { "list", cmd_list, cmd_list_usage, NULL, 0 },
471                 { 0, 0, 0, 0, 0 },
472         }
473 };
474
475 int cmd_property(int argc, char **argv)
476 {
477         return handle_command_group(&property_cmd_group, argc, argv);
478 }