btrfs-progs: readme: fix link to issue tracker on github.
[btrfs-progs-unstable/devel.git] / cmds-property.c
blob9ae1246095e0d6849db6df5aa09d45520dc02bfc
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"
29 #include "help.h"
31 static const char * const property_cmd_group_usage[] = {
32 "btrfs property get/set/list [-t <type>] <object> [<name>] [value]",
33 NULL
36 static int parse_prop(const char *arg, const struct prop_handler *props,
37 const struct prop_handler **prop_ret)
39 const struct prop_handler *prop = props;
41 for (; prop->name; prop++) {
42 if (!strcmp(prop->name, arg)) {
43 *prop_ret = prop;
44 return 0;
48 return -1;
51 static int get_fsid(const char *path, u8 *fsid, int silent)
53 int ret;
54 int fd;
55 struct btrfs_ioctl_fs_info_args args;
57 fd = open(path, O_RDONLY);
58 if (fd < 0) {
59 ret = -errno;
60 if (!silent)
61 error("failed to open %s: %s", path,
62 strerror(-ret));
63 goto out;
66 ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
67 if (ret < 0) {
68 ret = -errno;
69 goto out;
72 memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
73 ret = 0;
75 out:
76 if (fd != -1)
77 close(fd);
78 return ret;
81 static int check_btrfs_object(const char *object)
83 int ret;
84 u8 fsid[BTRFS_FSID_SIZE];
86 ret = get_fsid(object, fsid, 0);
87 if (ret < 0)
88 ret = 0;
89 else
90 ret = 1;
91 return ret;
94 static int check_is_root(const char *object)
96 int ret;
97 u8 fsid[BTRFS_FSID_SIZE];
98 u8 fsid2[BTRFS_FSID_SIZE];
99 char *tmp = NULL;
100 char *rp;
102 rp = realpath(object, NULL);
103 if (!rp) {
104 ret = -errno;
105 goto out;
107 if (!strcmp(rp, "/")) {
108 ret = 0;
109 goto out;
112 tmp = malloc(strlen(object) + 5);
113 if (!tmp) {
114 ret = -ENOMEM;
115 goto out;
117 strcpy(tmp, object);
118 if (tmp[strlen(tmp) - 1] != '/')
119 strcat(tmp, "/");
120 strcat(tmp, "..");
122 ret = get_fsid(object, fsid, 0);
123 if (ret < 0) {
124 error("get_fsid for %s failed: %s", object, strerror(-ret));
125 goto out;
128 ret = get_fsid(tmp, fsid2, 1);
129 if (ret == -ENOTTY) {
130 ret = 0;
131 goto out;
132 } else if (ret == -ENOTDIR) {
133 ret = 1;
134 goto out;
135 } else if (ret < 0) {
136 error("get_fsid for %s failed: %s", tmp, strerror(-ret));
137 goto out;
140 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
141 ret = 0;
142 goto out;
145 ret = 1;
147 out:
148 free(tmp);
149 free(rp);
150 return ret;
153 static int count_bits(int v)
155 unsigned int tmp = (unsigned int)v;
156 int cnt = 0;
158 while (tmp) {
159 if (tmp & 1)
160 cnt++;
161 tmp >>= 1;
163 return cnt;
166 static int autodetect_object_types(const char *object, int *types_out)
168 int ret;
169 int is_btrfs_object;
170 int types = 0;
171 struct stat st;
173 is_btrfs_object = check_btrfs_object(object);
175 ret = lstat(object, &st);
176 if (ret < 0) {
177 ret = -errno;
178 goto out;
181 if (is_btrfs_object) {
182 types |= prop_object_inode;
183 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
184 types |= prop_object_subvol;
186 ret = check_is_root(object);
187 if (ret < 0)
188 goto out;
189 if (!ret)
190 types |= prop_object_root;
193 if (S_ISBLK(st.st_mode))
194 types |= prop_object_dev;
196 ret = 0;
197 *types_out = types;
199 out:
200 return ret;
203 static int dump_prop(const struct prop_handler *prop,
204 const char *object,
205 int types,
206 int type,
207 int name_and_help)
209 int ret = 0;
211 if ((types & type) && (prop->types & type)) {
212 if (!name_and_help)
213 ret = prop->handler(type, object, prop->name, NULL);
214 else
215 printf("%-20s%s\n", prop->name, prop->desc);
217 return ret;
220 static int dump_props(int types, const char *object, int name_and_help)
222 int ret;
223 int i;
224 int j;
225 const struct prop_handler *prop;
227 for (i = 0; prop_handlers[i].name; i++) {
228 prop = &prop_handlers[i];
229 for (j = 1; j < __prop_object_max; j <<= 1) {
230 ret = dump_prop(prop, object, types, j, name_and_help);
231 if (ret < 0) {
232 ret = 50;
233 goto out;
238 ret = 0;
240 out:
241 return ret;
244 static int setget_prop(int types, const char *object,
245 const char *name, const char *value)
247 int ret;
248 const struct prop_handler *prop = NULL;
250 ret = parse_prop(name, prop_handlers, &prop);
251 if (ret == -1) {
252 error("unknown property: %s", name);
253 ret = 40;
254 goto out;
257 types &= prop->types;
258 if (!types) {
259 error("object is not compatible with property: %s", prop->name);
260 ret = 47;
261 goto out;
264 if (count_bits(types) > 1) {
265 error("type of object is ambiguous, please use option -t");
266 ret = 48;
267 goto out;
270 if (value && prop->read_only) {
271 error("property is read-only property: %s",
272 prop->name);
273 ret = 51;
274 goto out;
277 ret = prop->handler(types, object, name, value);
279 if (ret < 0)
280 ret = 50;
281 else
282 ret = 0;
284 out:
285 return ret;
289 static void parse_args(int argc, char **argv,
290 const char * const *usage_str,
291 int *types, char **object,
292 char **name, char **value, int min_nonopt_args)
294 int ret;
295 char *type_str = NULL;
296 int max_nonopt_args = 1;
298 optind = 1;
299 while (1) {
300 int c = getopt(argc, argv, "t:");
301 if (c < 0)
302 break;
304 switch (c) {
305 case 't':
306 type_str = optarg;
307 break;
308 default:
309 usage(usage_str);
313 if (name)
314 max_nonopt_args++;
315 if (value)
316 max_nonopt_args++;
318 if (check_argc_min(argc - optind, min_nonopt_args) ||
319 check_argc_max(argc - optind, max_nonopt_args))
320 usage(usage_str);
322 *types = 0;
323 if (type_str) {
324 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
325 *types = prop_object_subvol;
326 } else if (!strcmp(type_str, "f") ||
327 !strcmp(type_str, "filesystem")) {
328 *types = prop_object_root;
329 } else if (!strcmp(type_str, "i") ||
330 !strcmp(type_str, "inode")) {
331 *types = prop_object_inode;
332 } else if (!strcmp(type_str, "d") ||
333 !strcmp(type_str, "device")) {
334 *types = prop_object_dev;
335 } else {
336 error("invalid object type: %s", type_str);
337 usage(usage_str);
341 *object = argv[optind++];
342 if (optind < argc)
343 *name = argv[optind++];
344 if (optind < argc)
345 *value = argv[optind++];
347 if (!*types) {
348 ret = autodetect_object_types(*object, types);
349 if (ret < 0) {
350 error("failed to detect object type: %s",
351 strerror(-ret));
352 usage(usage_str);
354 if (!*types) {
355 error("object is not a btrfs object: %s", *object);
356 usage(usage_str);
361 static const char * const cmd_property_get_usage[] = {
362 "btrfs property get [-t <type>] <object> [<name>]",
363 "Gets a property from a btrfs object.",
364 "If no name is specified, all properties for the given object are",
365 "printed.",
366 "A filesystem object can be a the filesystem itself, a subvolume,",
367 "an inode or a device. The '-t <type>' option can be used to explicitly",
368 "specify what type of object you meant. This is only needed when a",
369 "property could be set for more then one object type. Possible types",
370 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
371 NULL
374 static int cmd_property_get(int argc, char **argv)
376 int ret;
377 char *object = NULL;
378 char *name = NULL;
379 int types = 0;
381 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
382 NULL, 1);
384 if (name)
385 ret = setget_prop(types, object, name, NULL);
386 else
387 ret = dump_props(types, object, 0);
389 return ret;
392 static const char * const cmd_property_set_usage[] = {
393 "btrfs property set [-t <type>] <object> <name> <value>",
394 "Sets a property on a btrfs object.",
395 "Please see the help of 'btrfs property get' for a description of",
396 "objects and object types.",
397 NULL
400 static int cmd_property_set(int argc, char **argv)
402 int ret;
403 char *object = NULL;
404 char *name = NULL;
405 char *value = NULL;
406 int types = 0;
408 parse_args(argc, argv, cmd_property_set_usage, &types,
409 &object, &name, &value, 3);
411 ret = setget_prop(types, object, name, value);
413 return ret;
416 static const char * const cmd_property_list_usage[] = {
417 "btrfs property list [-t <type>] <object>",
418 "Lists available properties with their descriptions for the given object.",
419 "Please see the help of 'btrfs property get' for a description of",
420 "objects and object types.",
421 NULL
424 static int cmd_property_list(int argc, char **argv)
426 int ret;
427 char *object = NULL;
428 int types = 0;
430 parse_args(argc, argv, cmd_property_list_usage,
431 &types, &object, NULL, NULL, 1);
433 ret = dump_props(types, object, 1);
435 return ret;
438 static const char property_cmd_group_info[] =
439 "modify properties of filesystem objects";
441 const struct cmd_group property_cmd_group = {
442 property_cmd_group_usage, property_cmd_group_info, {
443 { "get", cmd_property_get,
444 cmd_property_get_usage, NULL, 0 },
445 { "set", cmd_property_set,
446 cmd_property_set_usage, NULL, 0 },
447 { "list", cmd_property_list,
448 cmd_property_list_usage, NULL, 0 },
449 NULL_CMD_STRUCT
453 int cmd_property(int argc, char **argv)
455 return handle_command_group(&property_cmd_group, argc, argv);