btrfs-progs: better option/error handling for btrfs-vol
[platform/upstream/btrfs-progs.git] / btrfs-vol.c
1 /*
2  * Copyright (C) 2007 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #define _GNU_SOURCE
20 #ifndef __CHECKER__
21 #include <sys/ioctl.h>
22 #include <sys/mount.h>
23 #include "ioctl.h"
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <getopt.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <dirent.h>
33 #include <uuid/uuid.h>
34 #include "kerncompat.h"
35 #include "ctree.h"
36 #include "transaction.h"
37 #include "utils.h"
38 #include "volumes.h"
39
40 #ifdef __CHECKER__
41 #define BLKGETSIZE64 0
42 #define BTRFS_IOC_SNAP_CREATE 0
43 #define BTRFS_IOC_ADD_DEV 0
44 #define BTRFS_IOC_RM_DEV 0
45 #define BTRFS_VOL_NAME_MAX 255
46 struct btrfs_ioctl_vol_args { char name[BTRFS_VOL_NAME_MAX]; };
47 static inline int ioctl(int fd, int define, void *arg) { return 0; }
48 #endif
49
50 static void print_usage(void)
51 {
52         fprintf(stderr, "usage: btrfs-vol [options] mount_point\n");
53         fprintf(stderr, "\t-a device add one device\n");
54         fprintf(stderr, "\t-b balance chunks across all devices\n");
55         fprintf(stderr, "\t-r device remove one device\n");
56         exit(1);
57 }
58
59 static struct option long_options[] = {
60         /* { "byte-count", 1, NULL, 'b' }, */
61         { "add", 1, NULL, 'a' },
62         { "balance", 0, NULL, 'b' },
63         { "remove", 1, NULL, 'r' },
64         { 0, 0, 0, 0}
65 };
66
67 int main(int ac, char **av)
68 {
69         struct stat st;
70         char *device = NULL;
71         char *mnt = NULL;
72         int ret;
73         int option_index = 0;
74         int cmd = 0;
75         int fd;
76         int devfd = 0;
77         DIR *dirstream;
78         struct btrfs_ioctl_vol_args args;
79         u64 dev_block_count = 0;
80
81         printf( "**\n"
82                 "** WARNING: this program is considered deprecated\n"
83                 "** Please consider to switch to the btrfs utility\n"
84                 "**\n");
85
86         while(1) {
87                 int c;
88                 c = getopt_long(ac, av, "a:br:", long_options,
89                                 &option_index);
90                 if (c < 0)
91                         break;
92                 switch(c) {
93                         case 'a':
94                                 device = strdup(optarg);
95                                 cmd = BTRFS_IOC_ADD_DEV;
96                                 break;
97                         case 'b':
98                                 cmd = BTRFS_IOC_BALANCE;
99                                 break;
100                         case 'r':
101                                 device = strdup(optarg);
102                                 cmd = BTRFS_IOC_RM_DEV;
103                                 break;
104                         default:
105                                 print_usage();
106                 }
107         }
108         ac = ac - optind;
109         if (ac == 0 || !cmd) {
110                 if (!ac)
111                         fprintf(stderr, "No mountpoint specified\n");
112                 else
113                         fprintf(stderr, "No command specified\n");
114                 print_usage();
115         }
116         mnt = av[optind];
117
118         if (device && strcmp(device, "missing") == 0 &&
119             cmd == BTRFS_IOC_RM_DEV) {
120                 fprintf(stderr, "removing missing devices from %s\n", mnt);
121         } else if (cmd != BTRFS_IOC_BALANCE) {
122                 if (cmd == BTRFS_IOC_ADD_DEV) {
123                         ret = check_mounted(device);
124                         if (ret < 0) {
125                                 fprintf(stderr,
126                                         "error checking %s mount status\n",
127                                         device);
128                                 exit(1);
129                         }
130                         if (ret == 1) {
131                                 fprintf(stderr, "%s is mounted\n", device);
132                                 exit(1);
133                         }
134                 }
135                 devfd = open(device, O_RDWR);
136                 if (devfd < 0) {
137                         fprintf(stderr, "Unable to open device %s\n", device);
138                         exit(1);
139                 }
140                 ret = fstat(devfd, &st);
141                 if (ret) {
142                         fprintf(stderr, "Unable to stat %s\n", device);
143                         exit(1);
144                 }
145                 if (!S_ISBLK(st.st_mode)) {
146                         fprintf(stderr, "%s is not a block device\n", device);
147                         exit(1);
148                 }
149         }
150         dirstream = opendir(mnt);
151         if (!dirstream) {
152                 fprintf(stderr, "Unable to open directory %s\n", mnt);
153                 exit(1);
154         }
155         if (cmd == BTRFS_IOC_ADD_DEV) {
156                 int mixed = 0;
157
158                 ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count,
159                                            0, &mixed, 0);
160                 if (ret) {
161                         fprintf(stderr, "Unable to init %s\n", device);
162                         exit(1);
163                 }
164         }
165         fd = dirfd(dirstream);
166         if (device)
167                 strncpy_null(args.name, device);
168         else
169                 args.name[0] = '\0';
170
171         ret = ioctl(fd, cmd, &args);
172         printf("ioctl returns %d\n", ret);
173         return 0;
174 }
175