btrfs-progs: docs: update dump-super
[btrfs-progs-unstable/devel.git] / cmds-property.c
blob5b4da26a8e517928007a9cf70ece0ed47843d889
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"
28 #include "utils.h"
30 static const char * const property_cmd_group_usage[] = {
31 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
32 NULL
35 static int parse_prop(const char *arg, const struct prop_handler *props,
36 const struct prop_handler **prop_ret)
38 const struct prop_handler *prop = props;
40 for (; prop->name; prop++) {
41 if (!strcmp(prop->name, arg)) {
42 *prop_ret = prop;
43 return 0;
47 return -1;
50 static int get_fsid(const char *path, u8 *fsid, int silent)
52 int ret;
53 int fd;
54 struct btrfs_ioctl_fs_info_args args;
56 fd = open(path, O_RDONLY);
57 if (fd < 0) {
58 ret = -errno;
59 if (!silent)
60 error("failed to open %s: %s", path,
61 strerror(-ret));
62 goto out;
65 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
66 if (ret < 0) {
67 ret = -errno;
68 goto out;
71 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
72 ret = 0;
74 out:
75 if (fd != -1)
76 close(fd);
77 return ret;
80 static int check_btrfs_object(const char *object)
82 int ret;
83 u8 fsid[BTRFS_FSID_SIZE];
85 ret = get_fsid(object, fsid, 0);
86 if (ret < 0)
87 ret = 0;
88 else
89 ret = 1;
90 return ret;
93 static int check_is_root(const char *object)
95 int ret;
96 u8 fsid[BTRFS_FSID_SIZE];
97 u8 fsid2[BTRFS_FSID_SIZE];
98 char *tmp = NULL;
99 char *rp;
101 rp = realpath(object, NULL);
102 if (!rp) {
103 ret = -errno;
104 goto out;
106 if (!strcmp(rp, "/")) {
107 ret = 0;
108 goto out;
111 tmp = malloc(strlen(object) + 5);
112 if (!tmp) {
113 ret = -ENOMEM;
114 goto out;
116 strcpy(tmp, object);
117 if (tmp[strlen(tmp) - 1] != '/')
118 strcat(tmp, "/");
119 strcat(tmp, "..");
121 ret = get_fsid(object, fsid, 0);
122 if (ret < 0) {
123 error("get_fsid for %s failed: %s", object, strerror(-ret));
124 goto out;
127 ret = get_fsid(tmp, fsid2, 1);
128 if (ret == -ENOTTY) {
129 ret = 0;
130 goto out;
131 } else if (ret == -ENOTDIR) {
132 ret = 1;
133 goto out;
134 } else if (ret < 0) {
135 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
136 goto out;
139 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
140 ret = 0;
141 goto out;
144 ret = 1;
146 out:
147 free(tmp);
148 free(rp);
149 return ret;
152 static int count_bits(int v)
154 unsigned int tmp = (unsigned int)v;
155 int cnt = 0;
157 while (tmp) {
158 if (tmp & 1)
159 cnt++;
160 tmp >>= 1;
162 return cnt;
165 static int autodetect_object_types(const char *object, int *types_out)
167 int ret;
168 int is_btrfs_object;
169 int types = 0;
170 struct stat st;
172 is_btrfs_object = check_btrfs_object(object);
174 ret = lstat(object, &st);
175 if (ret < 0) {
176 ret = -errno;
177 goto out;
180 if (is_btrfs_object) {
181 types |= prop_object_inode;
182 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
183 types |= prop_object_subvol;
185 ret = check_is_root(object);
186 if (ret < 0)
187 goto out;
188 if (!ret)
189 types |= prop_object_root;
192 if (S_ISBLK(st.st_mode))
193 types |= prop_object_dev;
195 ret = 0;
196 *types_out = types;
198 out:
199 return ret;
202 static int print_prop_help(const struct prop_handler *prop)
204 fprintf(stdout, "%-20s%s\n", prop->name, prop->desc);
205 return 0;
208 static int dump_prop(const struct prop_handler *prop,
209 const char *object,
210 int types,
211 int type,
212 int name_and_help)
214 int ret = 0;
216 if ((types & type) && (prop->types & type)) {
217 if (!name_and_help)
218 ret = prop->handler(type, object, prop->name, NULL);
219 else
220 ret = print_prop_help(prop);
222 return ret;
225 static int dump_props(int types, const char *object, int name_and_help)
227 int ret;
228 int i;
229 int j;
230 const struct prop_handler *prop;
232 for (i = 0; prop_handlers[i].name; i++) {
233 prop = &prop_handlers[i];
234 for (j = 1; j < __prop_object_max; j <<= 1) {
235 ret = dump_prop(prop, object, types, j, name_and_help);
236 if (ret < 0) {
237 ret = 50;
238 goto out;
243 ret = 0;
245 out:
246 return ret;
249 static int setget_prop(int types, const char *object,
250 const char *name, const char *value)
252 int ret;
253 const struct prop_handler *prop = NULL;
255 ret = parse_prop(name, prop_handlers, &prop);
256 if (ret == -1) {
257 error("unknown property: %s", name);
258 ret = 40;
259 goto out;
262 types &= prop->types;
263 if (!types) {
264 error("object is not compatible with property: %s", prop->name);
265 ret = 47;
266 goto out;
269 if (count_bits(types) > 1) {
270 error("type of object is ambiguous, please use option -t");
271 ret = 48;
272 goto out;
275 if (value && prop->read_only) {
276 error("property is read-only property: %s",
277 prop->name);
278 ret = 51;
279 goto out;
282 ret = prop->handler(types, object, name, value);
284 if (ret < 0)
285 ret = 50;
286 else
287 ret = 0;
289 out:
290 return ret;
294 static void parse_args(int argc, char **argv,
295 const char * const *usage_str,
296 int *types, char **object,
297 char **name, char **value)
299 int ret;
300 char *type_str = NULL;
302 optind = 1;
303 while (1) {
304 int c = getopt(argc, argv, "t:");
305 if (c < 0)
306 break;
308 switch (c) {
309 case 't':
310 type_str = optarg;
311 break;
312 default:
313 usage(usage_str);
317 *types = 0;
318 if (type_str) {
319 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
320 *types = prop_object_subvol;
321 } else if (!strcmp(type_str, "f") ||
322 !strcmp(type_str, "filesystem")) {
323 *types = prop_object_root;
324 } else if (!strcmp(type_str, "i") ||
325 !strcmp(type_str, "inode")) {
326 *types = prop_object_inode;
327 } else if (!strcmp(type_str, "d") ||
328 !strcmp(type_str, "device")) {
329 *types = prop_object_dev;
330 } else {
331 error("invalid object type: %s", type_str);
332 usage(usage_str);
336 if (object && optind < argc)
337 *object = argv[optind++];
338 if (name && optind < argc)
339 *name = argv[optind++];
340 if (value && optind < argc)
341 *value = argv[optind++];
343 if (optind != argc) {
344 error("unexpected agruments found");
345 usage(usage_str);
348 if (!*types && object && *object) {
349 ret = autodetect_object_types(*object, types);
350 if (ret < 0) {
351 error("failed to detect object type: %s",
352 strerror(-ret));
353 usage(usage_str);
355 if (!*types) {
356 error("object is not a btrfs object: %s", *object);
357 usage(usage_str);
362 static const char * const cmd_property_get_usage[] = {
363 "btrfs property get [-t <type>] <object> [<name>]",
364 "Gets a property from a btrfs object.",
365 "If no name is specified, all properties for the given object are",
366 "printed.",
367 "A filesystem object can be a the filesystem itself, a subvolume,",
368 "an inode or a device. The '-t <type>' option can be used to explicitly",
369 "specify what type of object you meant. This is only needed when a",
370 "property could be set for more then one object type. Possible types",
371 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
372 NULL
375 static int cmd_property_get(int argc, char **argv)
377 int ret;
378 char *object = NULL;
379 char *name = NULL;
380 int types = 0;
382 clean_args_no_options(argc, argv, cmd_property_get_usage);
384 if (check_argc_min(argc, 2) || check_argc_max(argc, 5))
385 usage(cmd_property_get_usage);
387 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
388 NULL);
389 if (!object) {
390 error("invalid arguments");
391 usage(cmd_property_get_usage);
394 if (name)
395 ret = setget_prop(types, object, name, NULL);
396 else
397 ret = dump_props(types, object, 0);
399 return ret;
402 static const char * const cmd_property_set_usage[] = {
403 "btrfs property set [-t <type>] <object> <name> <value>",
404 "Sets a property on a btrfs object.",
405 "Please see the help of 'btrfs property get' for a description of",
406 "objects and object types.",
407 NULL
410 static int cmd_property_set(int argc, char **argv)
412 int ret;
413 char *object = NULL;
414 char *name = NULL;
415 char *value = NULL;
416 int types = 0;
418 clean_args_no_options(argc, argv, cmd_property_set_usage);
420 if (check_argc_min(argc, 4) || check_argc_max(argc, 6))
421 usage(cmd_property_set_usage);
423 parse_args(argc, argv, cmd_property_set_usage, &types,
424 &object, &name, &value);
425 if (!object || !name || !value) {
426 error("invalid arguments");
427 usage(cmd_property_set_usage);
430 ret = setget_prop(types, object, name, value);
432 return ret;
435 static const char * const cmd_property_list_usage[] = {
436 "btrfs property list [-t <type>] <object>",
437 "Lists available properties with their descriptions for the given object.",
438 "Please see the help of 'btrfs property get' for a description of",
439 "objects and object types.",
440 NULL
443 static int cmd_property_list(int argc, char **argv)
445 int ret;
446 char *object = NULL;
447 int types = 0;
449 clean_args_no_options(argc, argv, cmd_property_list_usage);
451 if (check_argc_min(argc, 2) || check_argc_max(argc, 4))
452 usage(cmd_property_list_usage);
454 parse_args(argc, argv, cmd_property_list_usage,
455 &types, &object, NULL, NULL);
456 if (!object) {
457 error("invalid arguments");
458 usage(cmd_property_list_usage);
461 ret = dump_props(types, object, 1);
463 return ret;
466 static const char property_cmd_group_info[] =
467 "modify properties of filesystem objects";
469 const struct cmd_group property_cmd_group = {
470 property_cmd_group_usage, property_cmd_group_info, {
471 { "get", cmd_property_get,
472 cmd_property_get_usage, NULL, 0 },
473 { "set", cmd_property_set,
474 cmd_property_set_usage, NULL, 0 },
475 { "list", cmd_property_list,
476 cmd_property_list_usage, NULL, 0 },
477 NULL_CMD_STRUCT
481 int cmd_property(int argc, char **argv)
483 return handle_command_group(&property_cmd_group, argc, argv);