btrfs-progs: mute coverity warnings about deadcode
[platform/upstream/btrfs-progs.git] / cmds-device.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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <getopt.h>
26
27 #include "kerncompat.h"
28 #include "ctree.h"
29 #include "ioctl.h"
30 #include "utils.h"
31 #include "volumes.h"
32 #include "cmds-fi-usage.h"
33
34 #include "commands.h"
35
36 static const char * const device_cmd_group_usage[] = {
37         "btrfs device <command> [<args>]",
38         NULL
39 };
40
41 static const char * const cmd_device_add_usage[] = {
42         "btrfs device add [options] <device> [<device>...] <path>",
43         "Add a device to a filesystem",
44         "-K|--nodiscard    do not perform whole device TRIM",
45         "-f|--force        force overwrite existing filesystem on the disk",
46         NULL
47 };
48
49 static int cmd_device_add(int argc, char **argv)
50 {
51         char    *mntpnt;
52         int     i, fdmnt, ret=0, e;
53         DIR     *dirstream = NULL;
54         int discard = 1;
55         int force = 0;
56         int last_dev;
57
58         while (1) {
59                 int c;
60                 static const struct option long_options[] = {
61                         { "nodiscard", optional_argument, NULL, 'K'},
62                         { "force", no_argument, NULL, 'f'},
63                         { NULL, 0, NULL, 0}
64                 };
65
66                 c = getopt_long(argc, argv, "Kf", long_options, NULL);
67                 if (c < 0)
68                         break;
69                 switch (c) {
70                 case 'K':
71                         discard = 0;
72                         break;
73                 case 'f':
74                         force = 1;
75                         break;
76                 default:
77                         usage(cmd_device_add_usage);
78                 }
79         }
80
81         if (check_argc_min(argc - optind, 2))
82                 usage(cmd_device_add_usage);
83
84         last_dev = argc - 1;
85         mntpnt = argv[last_dev];
86
87         fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
88         if (fdmnt < 0)
89                 return 1;
90
91         for (i = optind; i < last_dev; i++){
92                 struct btrfs_ioctl_vol_args ioctl_args;
93                 int     devfd, res;
94                 u64 dev_block_count = 0;
95                 char *path;
96
97                 res = test_dev_for_mkfs(argv[i], force);
98                 if (res) {
99                         ret++;
100                         continue;
101                 }
102
103                 devfd = open(argv[i], O_RDWR);
104                 if (devfd < 0) {
105                         fprintf(stderr, "ERROR: Unable to open device '%s'\n", argv[i]);
106                         ret++;
107                         continue;
108                 }
109
110                 res = btrfs_prepare_device(devfd, argv[i], 1, &dev_block_count,
111                                            0, discard);
112                 close(devfd);
113                 if (res) {
114                         ret++;
115                         goto error_out;
116                 }
117
118                 path = canonicalize_path(argv[i]);
119                 if (!path) {
120                         fprintf(stderr,
121                                 "ERROR: Could not canonicalize pathname '%s': %s\n",
122                                 argv[i], strerror(errno));
123                         ret++;
124                         goto error_out;
125                 }
126
127                 memset(&ioctl_args, 0, sizeof(ioctl_args));
128                 strncpy_null(ioctl_args.name, path);
129                 res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
130                 e = errno;
131                 if (res < 0) {
132                         fprintf(stderr, "ERROR: error adding the device '%s' - %s\n",
133                                 path, strerror(e));
134                         ret++;
135                 }
136                 free(path);
137         }
138
139 error_out:
140         close_file_or_dir(fdmnt, dirstream);
141         btrfs_close_all_devices();
142         return !!ret;
143 }
144
145 static int _cmd_device_remove(int argc, char **argv,
146                 const char * const *usagestr)
147 {
148         char    *mntpnt;
149         int     i, fdmnt, ret=0, e;
150         DIR     *dirstream = NULL;
151
152         if (check_argc_min(argc, 3))
153                 usage(usagestr);
154
155         mntpnt = argv[argc - 1];
156
157         fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
158         if (fdmnt < 0)
159                 return 1;
160
161         for(i=1 ; i < argc - 1; i++ ){
162                 struct  btrfs_ioctl_vol_args arg;
163                 int     res;
164
165                 if (is_block_device(argv[i]) != 1) {
166                         fprintf(stderr,
167                                 "ERROR: %s is not a block device\n", argv[i]);
168                         ret++;
169                         continue;
170                 }
171                 memset(&arg, 0, sizeof(arg));
172                 strncpy_null(arg.name, argv[i]);
173                 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
174                 e = errno;
175                 if (res) {
176                         const char *msg;
177
178                         if (res > 0)
179                                 msg = btrfs_err_str(res);
180                         else
181                                 msg = strerror(e);
182                         fprintf(stderr,
183                                 "ERROR: error removing the device '%s' - %s\n",
184                                 argv[i], msg);
185                         ret++;
186                 }
187         }
188
189         close_file_or_dir(fdmnt, dirstream);
190         return !!ret;
191 }
192
193 static const char * const cmd_device_remove_usage[] = {
194         "btrfs device remove <device> [<device>...] <path>",
195         "Remove a device from a filesystem",
196         NULL
197 };
198
199 static int cmd_device_remove(int argc, char **argv)
200 {
201         return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
202 }
203
204 static const char * const cmd_device_delete_usage[] = {
205         "btrfs device delete <device> [<device>...] <path>",
206         "Remove a device from a filesystem",
207         NULL
208 };
209
210 static int cmd_device_delete(int argc, char **argv)
211 {
212         return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
213 }
214
215 static const char * const cmd_device_scan_usage[] = {
216         "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
217         "Scan devices for a btrfs filesystem",
218         " -d|--all-devices (deprecated)",
219         NULL
220 };
221
222 static int cmd_device_scan(int argc, char **argv)
223 {
224         int i;
225         int devstart = 1;
226         int all = 0;
227         int ret = 0;
228
229         optind = 1;
230         while (1) {
231                 int c;
232                 static const struct option long_options[] = {
233                         { "all-devices", no_argument, NULL, 'd'},
234                         { NULL, 0, NULL, 0}
235                 };
236
237                 c = getopt_long(argc, argv, "d", long_options, NULL);
238                 if (c < 0)
239                         break;
240                 switch (c) {
241                 case 'd':
242                         all = 1;
243                         break;
244                 default:
245                         usage(cmd_device_scan_usage);
246                 }
247         }
248
249         if (all && check_argc_max(argc, 2))
250                 usage(cmd_device_scan_usage);
251
252         if (all || argc == 1) {
253                 printf("Scanning for Btrfs filesystems\n");
254                 ret = btrfs_scan_lblkid();
255                 if (ret)
256                         fprintf(stderr, "ERROR: error %d while scanning\n", ret);
257                 ret = btrfs_register_all_devices();
258                 if (ret)
259                         fprintf(stderr, "ERROR: error %d while registering\n", ret);
260                 goto out;
261         }
262
263         for( i = devstart ; i < argc ; i++ ){
264                 char *path;
265
266                 if (is_block_device(argv[i]) != 1) {
267                         fprintf(stderr,
268                                 "ERROR: %s is not a block device\n", argv[i]);
269                         ret = 1;
270                         goto out;
271                 }
272                 path = canonicalize_path(argv[i]);
273                 if (!path) {
274                         fprintf(stderr,
275                                 "ERROR: Could not canonicalize path '%s': %s\n",
276                                 argv[i], strerror(errno));
277                         ret = 1;
278                         goto out;
279                 }
280                 printf("Scanning for Btrfs filesystems in '%s'\n", path);
281                 if (btrfs_register_one_device(path) != 0) {
282                         ret = 1;
283                         free(path);
284                         goto out;
285                 }
286                 free(path);
287         }
288
289 out:
290         btrfs_close_all_devices();
291         return !!ret;
292 }
293
294 static const char * const cmd_device_ready_usage[] = {
295         "btrfs device ready <device>",
296         "Check device to see if it has all of its devices in cache for mounting",
297         NULL
298 };
299
300 static int cmd_device_ready(int argc, char **argv)
301 {
302         struct  btrfs_ioctl_vol_args args;
303         int     fd;
304         int     ret;
305         char    *path;
306
307         if (check_argc_min(argc, 2))
308                 usage(cmd_device_ready_usage);
309
310         fd = open("/dev/btrfs-control", O_RDWR);
311         if (fd < 0) {
312                 perror("failed to open /dev/btrfs-control");
313                 return 1;
314         }
315
316         path = canonicalize_path(argv[argc - 1]);
317         if (!path) {
318                 fprintf(stderr,
319                         "ERROR: Could not canonicalize pathname '%s': %s\n",
320                         argv[argc - 1], strerror(errno));
321                 ret = 1;
322                 goto out;
323         }
324
325         if (is_block_device(path) != 1) {
326                 fprintf(stderr,
327                         "ERROR: %s is not a block device\n", path);
328                 ret = 1;
329                 goto out;
330         }
331
332         memset(&args, 0, sizeof(args));
333         strncpy_null(args.name, path);
334         ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
335         if (ret < 0) {
336                 fprintf(stderr, "ERROR: unable to determine if the device '%s'"
337                         " is ready for mounting - %s\n", path,
338                         strerror(errno));
339                 ret = 1;
340         }
341
342 out:
343         free(path);
344         close(fd);
345         return ret;
346 }
347
348 static const char * const cmd_device_stats_usage[] = {
349         "btrfs device stats [-z] <path>|<device>",
350         "Show current device IO stats.",
351         "",
352         "-z                     show current stats and reset values to zero",
353         NULL
354 };
355
356 static int cmd_device_stats(int argc, char **argv)
357 {
358         char *dev_path;
359         struct btrfs_ioctl_fs_info_args fi_args;
360         struct btrfs_ioctl_dev_info_args *di_args = NULL;
361         int ret;
362         int fdmnt;
363         int i;
364         int c;
365         int err = 0;
366         __u64 flags = 0;
367         DIR *dirstream = NULL;
368
369         optind = 1;
370         while ((c = getopt(argc, argv, "z")) != -1) {
371                 switch (c) {
372                 case 'z':
373                         flags = BTRFS_DEV_STATS_RESET;
374                         break;
375                 case '?':
376                 default:
377                         usage(cmd_device_stats_usage);
378                 }
379         }
380
381         argc = argc - optind;
382         if (check_argc_exact(argc, 1))
383                 usage(cmd_device_stats_usage);
384
385         dev_path = argv[optind];
386
387         fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
388         if (fdmnt < 0)
389                 return 1;
390
391         ret = get_fs_info(dev_path, &fi_args, &di_args);
392         if (ret) {
393                 fprintf(stderr, "ERROR: getting dev info for devstats failed: "
394                                 "%s\n", strerror(-ret));
395                 err = 1;
396                 goto out;
397         }
398         if (!fi_args.num_devices) {
399                 fprintf(stderr, "ERROR: no devices found\n");
400                 err = 1;
401                 goto out;
402         }
403
404         for (i = 0; i < fi_args.num_devices; i++) {
405                 struct btrfs_ioctl_get_dev_stats args = {0};
406                 __u8 path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
407
408                 strncpy((char *)path, (char *)di_args[i].path,
409                         BTRFS_DEVICE_PATH_NAME_MAX);
410                 path[BTRFS_DEVICE_PATH_NAME_MAX] = '\0';
411
412                 args.devid = di_args[i].devid;
413                 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
414                 args.flags = flags;
415
416                 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
417                         fprintf(stderr,
418                                 "ERROR: ioctl(BTRFS_IOC_GET_DEV_STATS) on %s failed: %s\n",
419                                 path, strerror(errno));
420                         err = 1;
421                 } else {
422                         char *canonical_path;
423
424                         canonical_path = canonicalize_path((char *)path);
425
426                         if (args.nr_items >= BTRFS_DEV_STAT_WRITE_ERRS + 1)
427                                 printf("[%s].write_io_errs   %llu\n",
428                                        canonical_path,
429                                        (unsigned long long) args.values[
430                                         BTRFS_DEV_STAT_WRITE_ERRS]);
431                         if (args.nr_items >= BTRFS_DEV_STAT_READ_ERRS + 1)
432                                 printf("[%s].read_io_errs    %llu\n",
433                                        canonical_path,
434                                        (unsigned long long) args.values[
435                                         BTRFS_DEV_STAT_READ_ERRS]);
436                         if (args.nr_items >= BTRFS_DEV_STAT_FLUSH_ERRS + 1)
437                                 printf("[%s].flush_io_errs   %llu\n",
438                                        canonical_path,
439                                        (unsigned long long) args.values[
440                                         BTRFS_DEV_STAT_FLUSH_ERRS]);
441                         if (args.nr_items >= BTRFS_DEV_STAT_CORRUPTION_ERRS + 1)
442                                 printf("[%s].corruption_errs %llu\n",
443                                        canonical_path,
444                                        (unsigned long long) args.values[
445                                         BTRFS_DEV_STAT_CORRUPTION_ERRS]);
446                         if (args.nr_items >= BTRFS_DEV_STAT_GENERATION_ERRS + 1)
447                                 printf("[%s].generation_errs %llu\n",
448                                        canonical_path,
449                                        (unsigned long long) args.values[
450                                         BTRFS_DEV_STAT_GENERATION_ERRS]);
451
452                         free(canonical_path);
453                 }
454         }
455
456 out:
457         free(di_args);
458         close_file_or_dir(fdmnt, dirstream);
459         btrfs_close_all_devices();
460
461         return err;
462 }
463
464 static const char * const cmd_device_usage_usage[] = {
465         "btrfs device usage [options] <path> [<path>..]",
466         "Show detailed information about internal allocations in devices.",
467         HELPINFO_OUTPUT_UNIT_DF,
468         NULL
469 };
470
471 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
472 {
473         int i;
474         int ret = 0;
475         struct chunk_info *chunkinfo = NULL;
476         struct device_info *devinfo = NULL;
477         int chunkcount = 0;
478         int devcount = 0;
479
480         ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
481                         &devcount);
482         if (ret)
483                 goto out;
484
485         for (i = 0; i < devcount; i++) {
486                 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
487                 print_device_sizes(fd, &devinfo[i], unit_mode);
488                 print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount,
489                                 unit_mode);
490                 printf("\n");
491         }
492
493 out:
494         free(devinfo);
495         free(chunkinfo);
496
497         return ret;
498 }
499
500 static int cmd_device_usage(int argc, char **argv)
501 {
502         unsigned unit_mode;
503         int ret = 0;
504         int more_than_one = 0;
505         int i;
506
507         unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
508
509         if (check_argc_min(argc, 2) || argv[1][0] == '-')
510                 usage(cmd_device_usage_usage);
511
512         for (i = 1; i < argc; i++) {
513                 int fd;
514                 DIR *dirstream = NULL;
515
516                 if (more_than_one)
517                         printf("\n");
518
519                 fd = btrfs_open_dir(argv[i], &dirstream, 1);
520                 if (fd < 0) {
521                         ret = 1;
522                         goto out;
523                 }
524
525                 ret = _cmd_device_usage(fd, argv[i], unit_mode);
526                 close_file_or_dir(fd, dirstream);
527
528                 if (ret)
529                         goto out;
530                 more_than_one = 1;
531         }
532 out:
533         return !!ret;
534 }
535
536 static const char device_cmd_group_info[] =
537 "manage and query devices in the filesystem";
538
539 const struct cmd_group device_cmd_group = {
540         device_cmd_group_usage, device_cmd_group_info, {
541                 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
542                 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
543                         CMD_ALIAS },
544                 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
545                 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
546                 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
547                 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
548                 { "usage", cmd_device_usage,
549                         cmd_device_usage_usage, NULL, 0 },
550                 NULL_CMD_STRUCT
551         }
552 };
553
554 int cmd_device(int argc, char **argv)
555 {
556         return handle_command_group(&device_cmd_group, argc, argv);
557 }