Btrfs progs v4.17.1
[btrfs-progs-unstable/devel.git] / cmds-property.c
blob03bafa054701bea1609c0c30ab7d6b97804d5c88
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 check_btrfs_object(const char *object)
53 int ret;
54 u8 fsid[BTRFS_FSID_SIZE];
56 ret = get_fsid(object, fsid, 0);
57 if (ret < 0)
58 ret = 0;
59 else
60 ret = 1;
61 return ret;
64 static int check_is_root(const char *object)
66 int ret;
67 u8 fsid[BTRFS_FSID_SIZE];
68 u8 fsid2[BTRFS_FSID_SIZE];
69 char *tmp = NULL;
70 char *rp;
72 rp = realpath(object, NULL);
73 if (!rp) {
74 ret = -errno;
75 goto out;
77 if (!strcmp(rp, "/")) {
78 ret = 0;
79 goto out;
82 tmp = malloc(strlen(object) + 5);
83 if (!tmp) {
84 ret = -ENOMEM;
85 goto out;
87 strcpy(tmp, object);
88 if (tmp[strlen(tmp) - 1] != '/')
89 strcat(tmp, "/");
90 strcat(tmp, "..");
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;
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;
110 if (memcmp(fsid, fsid2, BTRFS_FSID_SIZE)) {
111 ret = 0;
112 goto out;
115 ret = 1;
117 out:
118 free(tmp);
119 free(rp);
120 return ret;
123 static int count_bits(int v)
125 unsigned int tmp = (unsigned int)v;
126 int cnt = 0;
128 while (tmp) {
129 if (tmp & 1)
130 cnt++;
131 tmp >>= 1;
133 return cnt;
136 static int autodetect_object_types(const char *object, int *types_out)
138 int ret;
139 int is_btrfs_object;
140 int types = 0;
141 struct stat st;
143 is_btrfs_object = check_btrfs_object(object);
145 ret = lstat(object, &st);
146 if (ret < 0) {
147 ret = -errno;
148 goto out;
151 if (is_btrfs_object) {
152 types |= prop_object_inode;
153 if (st.st_ino == BTRFS_FIRST_FREE_OBJECTID)
154 types |= prop_object_subvol;
156 ret = check_is_root(object);
157 if (ret < 0)
158 goto out;
159 if (!ret)
160 types |= prop_object_root;
163 if (S_ISBLK(st.st_mode))
164 types |= prop_object_dev;
166 ret = 0;
167 *types_out = types;
169 out:
170 return ret;
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)
179 int ret = 0;
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);
187 return ret;
190 static int dump_props(int types, const char *object, int name_and_help)
192 int ret;
193 int i;
194 int j;
195 const struct prop_handler *prop;
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;
208 ret = 0;
210 out:
211 return ret;
214 static int setget_prop(int types, const char *object,
215 const char *name, const char *value)
217 int ret;
218 const struct prop_handler *prop = NULL;
220 ret = parse_prop(name, prop_handlers, &prop);
221 if (ret == -1) {
222 error("unknown property: %s", name);
223 ret = 40;
224 goto out;
227 types &= prop->types;
228 if (!types) {
229 error("object is not compatible with property: %s", prop->name);
230 ret = 47;
231 goto out;
234 if (count_bits(types) > 1) {
235 error("type of object is ambiguous, please use option -t");
236 ret = 48;
237 goto out;
240 if (value && prop->read_only) {
241 error("property is read-only property: %s",
242 prop->name);
243 ret = 51;
244 goto out;
247 ret = prop->handler(types, object, name, value);
249 if (ret < 0)
250 ret = 50;
251 else
252 ret = 0;
254 out:
255 return ret;
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)
264 int ret;
265 char *type_str = NULL;
266 int max_nonopt_args = 1;
268 optind = 1;
269 while (1) {
270 int c = getopt(argc, argv, "t:");
271 if (c < 0)
272 break;
274 switch (c) {
275 case 't':
276 type_str = optarg;
277 break;
278 default:
279 usage(usage_str);
283 if (name)
284 max_nonopt_args++;
285 if (value)
286 max_nonopt_args++;
288 if (check_argc_min(argc - optind, min_nonopt_args) ||
289 check_argc_max(argc - optind, max_nonopt_args))
290 usage(usage_str);
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);
311 *object = argv[optind++];
312 if (optind < argc)
313 *name = argv[optind++];
314 if (optind < argc)
315 *value = argv[optind++];
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);
324 if (!*types) {
325 error("object is not a btrfs object: %s", *object);
326 usage(usage_str);
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
344 static int cmd_property_get(int argc, char **argv)
346 int ret;
347 char *object = NULL;
348 char *name = NULL;
349 int types = 0;
351 parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
352 NULL, 1);
354 if (name)
355 ret = setget_prop(types, object, name, NULL);
356 else
357 ret = dump_props(types, object, 0);
359 return ret;
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
370 static int cmd_property_set(int argc, char **argv)
372 int ret;
373 char *object = NULL;
374 char *name = NULL;
375 char *value = NULL;
376 int types = 0;
378 parse_args(argc, argv, cmd_property_set_usage, &types,
379 &object, &name, &value, 3);
381 ret = setget_prop(types, object, name, value);
383 return ret;
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
394 static int cmd_property_list(int argc, char **argv)
396 int ret;
397 char *object = NULL;
398 int types = 0;
400 parse_args(argc, argv, cmd_property_list_usage,
401 &types, &object, NULL, NULL, 1);
403 ret = dump_props(types, object, 1);
405 return ret;
408 static const char property_cmd_group_info[] =
409 "modify properties of filesystem objects";
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
423 int cmd_property(int argc, char **argv)
425 return handle_command_group(&property_cmd_group, argc, argv);