btrfs-progs: add btrfs_clear_free_space_tree() from the kernel
[btrfs-progs-unstable/devel.git] / cmds-property.c
blob854bff567c301cb5fe72093d0bb9aca83bc559b9
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 dump_prop(const struct prop_handler *prop,
203 const char *object,
204 int types,
205 int type,
206 int name_and_help)
208 int ret = 0;
210 if ((types & type) && (prop->types & type)) {
211 if (!name_and_help)
212 ret = prop->handler(type, object, prop->name, NULL);
213 else
214 printf("%-20s%s\n", prop->name, prop->desc);
216 return ret;
219 static int dump_props(int types, const char *object, int name_and_help)
221 int ret;
222 int i;
223 int j;
224 const struct prop_handler *prop;
226 for (i = 0; prop_handlers[i].name; i++) {
227 prop = &prop_handlers[i];
228 for (j = 1; j < __prop_object_max; j <<= 1) {
229 ret = dump_prop(prop, object, types, j, name_and_help);
230 if (ret < 0) {
231 ret = 50;
232 goto out;
237 ret = 0;
239 out:
240 return ret;
243 static int setget_prop(int types, const char *object,
244 const char *name, const char *value)
246 int ret;
247 const struct prop_handler *prop = NULL;
249 ret = parse_prop(name, prop_handlers, &prop);
250 if (ret == -1) {
251 error("unknown property: %s", name);
252 ret = 40;
253 goto out;
256 types &= prop->types;
257 if (!types) {
258 error("object is not compatible with property: %s", prop->name);
259 ret = 47;
260 goto out;
263 if (count_bits(types) > 1) {
264 error("type of object is ambiguous, please use option -t");
265 ret = 48;
266 goto out;
269 if (value && prop->read_only) {
270 error("property is read-only property: %s",
271 prop->name);
272 ret = 51;
273 goto out;
276 ret = prop->handler(types, object, name, value);
278 if (ret < 0)
279 ret = 50;
280 else
281 ret = 0;
283 out:
284 return ret;
288 static void parse_args(int argc, char **argv,
289 const char * const *usage_str,
290 int *types, char **object,
291 char **name, char **value, int min_nonopt_args)
293 int ret;
294 char *type_str = NULL;
295 int max_nonopt_args = 1;
297 optind = 1;
298 while (1) {
299 int c = getopt(argc, argv, "t:");
300 if (c < 0)
301 break;
303 switch (c) {
304 case 't':
305 type_str = optarg;
306 break;
307 default:
308 usage(usage_str);
312 if (name)
313 max_nonopt_args++;
314 if (value)
315 max_nonopt_args++;
317 if (check_argc_min(argc - optind, min_nonopt_args) ||
318 check_argc_max(argc - optind, max_nonopt_args))
319 usage(usage_str);
321 *types = 0;
322 if (type_str) {
323 if (!strcmp(type_str, "s") || !strcmp(type_str, "subvol")) {
324 *types = prop_object_subvol;
325 } else if (!strcmp(type_str, "f") ||
326 !strcmp(type_str, "filesystem")) {
327 *types = prop_object_root;
328 } else if (!strcmp(type_str, "i") ||
329 !strcmp(type_str, "inode")) {
330 *types = prop_object_inode;
331 } else if (!strcmp(type_str, "d") ||
332 !strcmp(type_str, "device")) {
333 *types = prop_object_dev;
334 } else {
335 error("invalid object type: %s", type_str);
336 usage(usage_str);
340 *object = argv[optind++];
341 if (optind < argc)
342 *name = argv[optind++];
343 if (optind < argc)
344 *value = argv[optind++];
346 if (!*types) {
347 ret = autodetect_object_types(*object, types);
348 if (ret < 0) {
349 error("failed to detect object type: %s",
350 strerror(-ret));
351 usage(usage_str);
353 if (!*types) {
354 error("object is not a btrfs object: %s", *object);
355 usage(usage_str);
360 static const char * const cmd_property_get_usage[] = {
361 "btrfs property get [-t <type>] <object> [<name>]",
362 "Gets a property from a btrfs object.",
363 "If no name is specified, all properties for the given object are",
364 "printed.",
365 "A filesystem object can be a the filesystem itself, a subvolume,",
366 "an inode or a device. The '-t <type>' option can be used to explicitly",
367 "specify what type of object you meant. This is only needed when a",
368 "property could be set for more then one object type. Possible types",
369 "are s[ubvol], f[ilesystem], i[node] and d[evice].",
370 NULL
373 static int cmd_property_get(int argc, char **argv)
375 int ret;
376 char *object = NULL;
377 char *name = NULL;
378 int types = 0;
380 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
381 NULL, 1);
383 if (name)
384 ret = setget_prop(types, object, name, NULL);
385 else
386 ret = dump_props(types, object, 0);
388 return ret;
391 static const char * const cmd_property_set_usage[] = {
392 "btrfs property set [-t <type>] <object> <name> <value>",
393 "Sets a property on a btrfs object.",
394 "Please see the help of 'btrfs property get' for a description of",
395 "objects and object types.",
396 NULL
399 static int cmd_property_set(int argc, char **argv)
401 int ret;
402 char *object = NULL;
403 char *name = NULL;
404 char *value = NULL;
405 int types = 0;
407 parse_args(argc, argv, cmd_property_set_usage, &types,
408 &object, &name, &value, 3);
410 ret = setget_prop(types, object, name, value);
412 return ret;
415 static const char * const cmd_property_list_usage[] = {
416 "btrfs property list [-t <type>] <object>",
417 "Lists available properties with their descriptions for the given object.",
418 "Please see the help of 'btrfs property get' for a description of",
419 "objects and object types.",
420 NULL
423 static int cmd_property_list(int argc, char **argv)
425 int ret;
426 char *object = NULL;
427 int types = 0;
429 parse_args(argc, argv, cmd_property_list_usage,
430 &types, &object, NULL, NULL, 1);
432 ret = dump_props(types, object, 1);
434 return ret;
437 static const char property_cmd_group_info[] =
438 "modify properties of filesystem objects";
440 const struct cmd_group property_cmd_group = {
441 property_cmd_group_usage, property_cmd_group_info, {
442 { "get", cmd_property_get,
443 cmd_property_get_usage, NULL, 0 },
444 { "set", cmd_property_set,
445 cmd_property_set_usage, NULL, 0 },
446 { "list", cmd_property_list,
447 cmd_property_list_usage, NULL, 0 },
448 NULL_CMD_STRUCT
452 int cmd_property(int argc, char **argv)
454 return handle_command_group(&property_cmd_group, argc, argv);