sbin/mount_hammer: Minor fix and cleanups
[dragonfly.git] / sbin / mount_hammer / mount_hammer.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/syslimits.h>
38 #include <vfs/hammer/hammer_mount.h>
39 #include <vfs/hammer/hammer_disk.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <stddef.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <fcntl.h>
48 #include <err.h>
49 #include <mntopts.h>
50
51 static void extract_volumes(struct hammer_mount_info *info, char **av, int ac);
52 static void free_volumes(struct hammer_mount_info *info);
53 static void usage(void);
54
55 #define MOPT_UPDATE         { "update",     0, MNT_UPDATE, 0 }
56
57 #define MOPT_HAMMEROPTS         \
58         { "history", 1, HMNT_NOHISTORY, 1 },    \
59         { "master=", 0, HMNT_MASTERID, 1 },     \
60         { "mirror", 1, HMNT_NOMIRROR, 1 }
61
62 static struct mntopt mopts[] = { MOPT_STDOPTS, MOPT_HAMMEROPTS,
63                                  MOPT_UPDATE, MOPT_NULL };
64
65 int
66 main(int ac, char **av)
67 {
68         struct hammer_mount_info info;
69         struct vfsconf vfc;
70         struct hammer_volume_ondisk *od;
71         int mount_flags = 0;
72         int init_flags = 0;
73         int error;
74         int ch;
75         int ax;
76         int fd;
77         int pr;
78         int fdevs_size;
79         char *mountpt;
80         char *ptr;
81         char *fdevs;
82         const char *fdev;
83
84         bzero(&info, sizeof(info));
85
86         while ((ch = getopt(ac, av, "o:T:u")) != -1) {
87                 switch(ch) {
88                 case 'T':
89                         info.asof = strtoull(optarg, NULL, 0);
90                         break;
91                 case 'o':
92                         getmntopts(optarg, mopts, &mount_flags, &info.hflags);
93
94                         /*
95                          * Handle extended flags with parameters.
96                          */
97                         if (info.hflags & HMNT_MASTERID) {
98                                 ptr = strstr(optarg, "master=");
99                                 if (ptr) {
100                                         info.master_id = strtol(ptr + 7, NULL, 0);
101                                         if (info.master_id == 0) {
102                                                 fprintf(stderr,
103         "mount_hammer: Warning: a master id of 0 is the default, explicit\n"
104         "settings should probably use 1-15\n");
105                                         }
106                                 }
107                         }
108                         if (info.hflags & HMNT_NOMIRROR) {
109                                 ptr = strstr(optarg, "nomirror");
110                                 if (ptr)
111                                         info.master_id = -1;
112                         }
113                         break;
114                 case 'u':
115                         init_flags |= MNT_UPDATE;
116                         break;
117                 default:
118                         usage();
119                         /* not reached */
120                 }
121         }
122         ac -= optind;
123         av += optind;
124         mount_flags |= init_flags;
125
126         /*
127          * Only the mount point need be specified in update mode.
128          */
129         if (init_flags & MNT_UPDATE) {
130                 if (ac != 1) {
131                         usage();
132                         /* not reached */
133                 }
134                 mountpt = av[0];
135                 if (mount(vfc.vfc_name, mountpt, mount_flags, &info))
136                         err(1, "mountpoint %s", mountpt);
137                 exit(0);
138         }
139
140         if (ac < 2) {
141                 usage();
142                 /* not reached */
143         }
144
145         /*
146          * Mount arguments: vol [vol...] mountpt
147          */
148         extract_volumes(&info, av, ac - 1);
149         mountpt = av[ac - 1];
150
151         /*
152          * Load the hammer module if necessary (this bit stolen from
153          * mount_null).
154          */
155         error = getvfsbyname("hammer", &vfc);
156         if (error && vfsisloadable("hammer")) {
157                 if (vfsload("hammer") != 0)
158                         err(1, "vfsload(hammer)");
159                 endvfsent();
160                 error = getvfsbyname("hammer", &vfc);
161         }
162         if (error)
163                 errx(1, "hammer filesystem is not available");
164
165         if (mount(vfc.vfc_name, mountpt, mount_flags, &info)) {
166                 /* Build fdevs in case of error to report failed devices */
167                 fdevs_size = ac * (PATH_MAX + 1);
168                 fdevs = malloc(fdevs_size);
169                 bzero(fdevs, fdevs_size);
170
171                 for (ax = 0; ax < info.nvolumes; ax++) {
172                         fdev = info.volumes[ax];
173                         fd = open(fdev, O_RDONLY);
174                         if (fd < 0) {
175                                 fprintf(stderr, "%s: open failed\n", fdev);
176                                 strlcat(fdevs, fdev, fdevs_size);
177                                 if (ax < ac - 2)
178                                         strlcat(fdevs, " ", fdevs_size);
179                                 continue;
180                         }
181
182                         od = malloc(HAMMER_BUFSIZE);
183                         if (od == NULL) {
184                                 close(fd);
185                                 perror("malloc");
186                                 continue;
187                         }
188
189                         bzero(od, HAMMER_BUFSIZE);
190                         pr = pread(fd, od, HAMMER_BUFSIZE, 0);
191                         if (pr != HAMMER_BUFSIZE ||
192                                 od->vol_signature != HAMMER_FSBUF_VOLUME) {
193                                 fprintf(stderr,
194                                         "%s: Not a valid HAMMER filesystem\n",
195                                         fdev);
196                                 strlcat(fdevs, fdev, fdevs_size);
197                                 if (ax < ac - 2)
198                                         strlcat(fdevs, " ", fdevs_size);
199                         }
200                         free(od);
201                         close(fd);
202                 }
203                 if (strlen(fdevs))
204                         err(1, "mount %s on %s", fdevs, mountpt);
205                 else
206                         err(1, "Unknown error");
207         }
208         free_volumes(&info);
209         exit (0);
210 }
211
212 /*
213  * Extract a volume list
214  */
215 static
216 void
217 extract_volumes(struct hammer_mount_info *info, char **av, int ac)
218 {
219         int idx = 0;
220         int arymax = 32;
221         const char **ary = malloc(sizeof(char *) * arymax);
222         char *ptr;
223         char *next;
224         char *orig;
225
226         while (ac) {
227                 if (idx == arymax) {
228                         arymax += 32;
229                         ary = realloc(ary, sizeof(char *) * arymax);
230                 }
231                 if (strchr(*av, ':') == NULL) {
232                         ary[idx++] = strdup(*av);
233                 } else {
234                         orig = next = strdup(*av);
235                         while ((ptr = next) != NULL) {
236                                 if (idx == arymax) {
237                                         arymax += 32;
238                                         ary = realloc(ary, sizeof(char *) *
239                                                       arymax);
240                                 }
241                                 if ((next = strchr(ptr, ':')) != NULL)
242                                         *next++ = 0;
243                                 ary[idx++] = strdup(ptr);
244                         }
245                         free(orig);
246                 }
247                 --ac;
248                 ++av;
249         }
250         info->nvolumes = idx;
251         info->volumes = ary;
252 }
253
254 static
255 void
256 free_volumes(struct hammer_mount_info *info)
257 {
258         int i;
259
260         for (i = 0; i < info->nvolumes; i++)
261                 ; /* free((char*)info->volumes[i]); */
262         free(info->volumes);
263 }
264
265 static
266 void
267 usage(void)
268 {
269         fprintf(stderr, "usage: mount_hammer [-o options] [-T transaction-id] "
270                         "special ... node\n");
271         fprintf(stderr, "       mount_hammer [-o options] [-T transaction-id] "
272                         "special[:special]* node\n");
273         fprintf(stderr, "       mount_hammer -u [-o options] node\n");
274         exit(1);
275 }