btrfs-progs: move get_fsid() to utils.c
[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 #include "help.h"
30
31 static const char * const property_cmd_group_usage[] = {
32         "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
33         NULL
34 };
35
36 static int parse_prop(const char *arg, const struct prop_handler *props,
37                       const struct prop_handler **prop_ret)
38 {
39         const struct prop_handler *prop = props;
40
41         for (; prop->name; prop++) {
42                 if (!strcmp(prop->name, arg)) {
43                         *prop_ret = prop;
44                         return 0;
45                 }
46         }
47
48         return -1;
49 }
50
51 static int check_btrfs_object(const char *object)
52 {
53         int ret;
54         u8 fsid[BTRFS_FSID_SIZE];
55
56         ret = get_fsid(object, fsid, 0);
57         if (ret < 0)
58                 ret = 0;
59         else
60                 ret = 1;
61         return ret;
62 }
63
64 static int check_is_root(const char *object)
65 {
66         int ret;
67         u8 fsid[BTRFS_FSID_SIZE];
68         u8 fsid2[BTRFS_FSID_SIZE];
69         char *tmp = NULL;
70         char *rp;
71
72         rp = realpath(object, NULL);
73         if (!rp) {
74                 ret = -errno;
75                 goto out;
76         }
77         if (!strcmp(rp, "/")) {
78                 ret = 0;
79                 goto out;
80         }
81
82         tmp = malloc(strlen(object) + 5);
83         if (!tmp) {
84                 ret = -ENOMEM;
85                 goto out;
86         }
87         strcpy(tmp, object);
88         if (tmp[strlen(tmp) - 1] != '/')
89                 strcat(tmp, "/");
90         strcat(tmp, "..");
91
92         ret = get_fsid(object, fsid, 0);
93         if (ret < 0) {
94                 error("get_fsid for %s failed: %s", object, strerror(-ret));
95                 goto out;
96         }
97
98         ret = get_fsid(tmp, fsid2, 1);
99         if (ret == -ENOTTY) {
100                 ret = 0;
101                 goto out;
102         } else if (ret == -ENOTDIR) {
103                 ret = 1;
104                 goto out;
105         } else if (ret < 0) {
106                 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
107                 goto out;
108         }
109
110         if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
111                 ret = 0;
112                 goto out;
113         }
114
115         ret = 1;
116
117 out:
118         free(tmp);
119         free(rp);
120         return ret;
121 }
122
123 static int count_bits(int v)
124 {
125         unsigned int tmp = (unsigned int)v;
126         int cnt = 0;
127
128         while (tmp) {
129                 if (tmp & 1)
130                         cnt++;
131                 tmp >>= 1;
132         }
133         return cnt;
134 }
135
136 static int autodetect_object_types(const char *object, int *types_out)
137 {
138         int ret;
139         int is_btrfs_object;
140         int types = 0;
141         struct stat st;
142
143         is_btrfs_object = check_btrfs_object(object);
144
145         ret = lstat(object, &st);
146         if (ret < 0) {
147                 ret = -errno;
148                 goto out;
149         }
150
151         if (is_btrfs_object) {
152                 types |= prop_object_inode;
153                 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
154                         types |= prop_object_subvol;
155
156                 ret = check_is_root(object);
157                 if (ret < 0)
158                         goto out;
159                 if (!ret)
160                         types |= prop_object_root;
161         }
162
163         if (S_ISBLK(st.st_mode))
164                 types |= prop_object_dev;
165
166         ret = 0;
167         *types_out = types;
168
169 out:
170         return ret;
171 }
172
173 static int dump_prop(const struct prop_handler *prop,
174                      const char *object,
175                      int types,
176                      int type,
177                      int name_and_help)
178 {
179         int ret = 0;
180
181         if ((types & type) && (prop->types & type)) {
182                 if (!name_and_help)
183                         ret = prop->handler(type, object, prop->name, NULL);
184                 else
185                         printf("%-20s%s\n", prop->name, prop->desc);
186         }
187         return ret;
188 }
189
190 static int dump_props(int types, const char *object, int name_and_help)
191 {
192         int ret;
193         int i;
194         int j;
195         const struct prop_handler *prop;
196
197         for (i = 0; prop_handlers[i].name; i++) {
198                 prop = &prop_handlers[i];
199                 for (j = 1; j < __prop_object_max; j <<= 1) {
200                         ret = dump_prop(prop, object, types, j, name_and_help);
201                         if (ret < 0) {
202                                 ret = 50;
203                                 goto out;
204                         }
205                 }
206         }
207
208         ret = 0;
209
210 out:
211         return ret;
212 }
213
214 static int setget_prop(int types, const char *object,
215                        const char *name, const char *value)
216 {
217         int ret;
218         const struct prop_handler *prop = NULL;
219
220         ret = parse_prop(name, prop_handlers, &prop);
221         if (ret == -1) {
222                 error("unknown property: %s", name);
223                 ret = 40;
224                 goto out;
225         }
226
227         types &= prop->types;
228         if (!types) {
229                 error("object is not compatible with property: %s", prop->name);
230                 ret = 47;
231                 goto out;
232         }
233
234         if (count_bits(types) > 1) {
235                 error("type of object is ambiguous, please use option -t");
236                 ret = 48;
237                 goto out;
238         }
239
240         if (value && prop->read_only) {
241                 error("property is read-only property: %s",
242                                 prop->name);
243                 ret = 51;
244                 goto out;
245         }
246
247         ret = prop->handler(types, object, name, value);
248
249         if (ret < 0)
250                 ret = 50;
251         else
252                 ret = 0;
253
254 out:
255         return ret;
256
257 }
258
259 static void parse_args(int argc, char **argv,
260                        const char * const *usage_str,
261                        int *types, char **object,
262                        char **name, char **value, int min_nonopt_args)
263 {
264         int ret;
265         char *type_str = NULL;
266         int max_nonopt_args = 1;
267
268         optind = 1;
269         while (1) {
270                 int c = getopt(argc, argv, "t:");
271                 if (c < 0)
272                         break;
273
274                 switch (c) {
275                 case 't':
276                         type_str = optarg;
277                         break;
278                 default:
279                         usage(usage_str);
280                 }
281         }
282
283         if (name)
284                 max_nonopt_args++;
285         if (value)
286                 max_nonopt_args++;
287
288         if (check_argc_min(argc - optind, min_nonopt_args) ||
289             check_argc_max(argc - optind, max_nonopt_args))
290                 usage(usage_str);
291
292         *types = 0;
293         if (type_str) {
294                 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
295                         *types = prop_object_subvol;
296                 } else if (!strcmp(type_str, "f") ||
297                            !strcmp(type_str, "filesystem")) {
298                         *types = prop_object_root;
299                 } else if (!strcmp(type_str, "i") ||
300                            !strcmp(type_str, "inode")) {
301                         *types = prop_object_inode;
302                 } else if (!strcmp(type_str, "d") ||
303                            !strcmp(type_str, "device")) {
304                         *types = prop_object_dev;
305                 } else {
306                         error("invalid object type: %s", type_str);
307                         usage(usage_str);
308                 }
309         }
310
311         *object = argv[optind++];
312         if (optind < argc)
313                 *name = argv[optind++];
314         if (optind < argc)
315                 *value = argv[optind++];
316
317         if (!*types) {
318                 ret = autodetect_object_types(*object, types);
319                 if (ret < 0) {
320                         error("failed to detect object type: %s",
321                                 strerror(-ret));
322                         usage(usage_str);
323                 }
324                 if (!*types) {
325                         error("object is not a btrfs object: %s", *object);
326                         usage(usage_str);
327                 }
328         }
329 }
330
331 static const char * const cmd_property_get_usage[] = {
332         "btrfs property get [-t <type>] <object> [<name>]",
333         "Gets a property from a btrfs object.",
334         "If no name is specified, all properties for the given object are",
335         "printed.",
336         "A filesystem object can be a the filesystem itself, a subvolume,",
337         "an inode or a device. The '-t <type>' option can be used to explicitly",
338         "specify what type of object you meant. This is only needed when a",
339         "property could be set for more then one object type. Possible types",
340         "are s[ubvol], f[ilesystem], i[node] and d[evice].",
341         NULL
342 };
343
344 static int cmd_property_get(int argc, char **argv)
345 {
346         int ret;
347         char *object = NULL;
348         char *name = NULL;
349         int types = 0;
350
351         parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
352                    NULL, 1);
353
354         if (name)
355                 ret = setget_prop(types, object, name, NULL);
356         else
357                 ret = dump_props(types, object, 0);
358
359         return ret;
360 }
361
362 static const char * const cmd_property_set_usage[] = {
363         "btrfs property set [-t <type>] <object> <name> <value>",
364         "Sets a property on a btrfs object.",
365         "Please see the help of 'btrfs property get' for a description of",
366         "objects and object types.",
367         NULL
368 };
369
370 static int cmd_property_set(int argc, char **argv)
371 {
372         int ret;
373         char *object = NULL;
374         char *name = NULL;
375         char *value = NULL;
376         int types = 0;
377
378         parse_args(argc, argv, cmd_property_set_usage, &types,
379                    &object, &name, &value, 3);
380
381         ret = setget_prop(types, object, name, value);
382
383         return ret;
384 }
385
386 static const char * const cmd_property_list_usage[] = {
387         "btrfs property list [-t <type>] <object>",
388         "Lists available properties with their descriptions for the given object.",
389         "Please see the help of 'btrfs property get' for a description of",
390         "objects and object types.",
391         NULL
392 };
393
394 static int cmd_property_list(int argc, char **argv)
395 {
396         int ret;
397         char *object = NULL;
398         int types = 0;
399
400         parse_args(argc, argv, cmd_property_list_usage,
401                    &types, &object, NULL, NULL, 1);
402
403         ret = dump_props(types, object, 1);
404
405         return ret;
406 }
407
408 static const char property_cmd_group_info[] =
409 "modify properties of filesystem objects";
410
411 const struct cmd_group property_cmd_group = {
412         property_cmd_group_usage, property_cmd_group_info, {
413                 { "get", cmd_property_get,
414                         cmd_property_get_usage, NULL, 0 },
415                 { "set", cmd_property_set,
416                         cmd_property_set_usage, NULL, 0 },
417                 { "list", cmd_property_list,
418                         cmd_property_list_usage, NULL, 0 },
419                 NULL_CMD_STRUCT
420         }
421 };
422
423 int cmd_property(int argc, char **argv)
424 {
425         return handle_command_group(&property_cmd_group, argc, argv);
426 }