0d030b1ce1303dbe04548ea3e84b64c4b38e1742
[dragonfly.git] / sbin / hammer / cmd_volume.c
1 /*
2  * Copyright (c) 2009 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> and
6  * Michael Neumann <mneumann@ntecs.de>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36 /*
37  * Volume operations:
38  *
39  *   - volume-add: Add new volume to HAMMER filesystem
40  *   - volume-del: Remove volume from HAMMER filesystem
41  *   - volume-list: List volumes making up a HAMMER filesystem
42  *   - volume-blkdevs: List volumes making up a HAMMER filesystem
43  *     in blkdevs format
44  */
45
46 #include "hammer.h"
47 #include <string.h>
48 #include <stdlib.h>
49
50 static uint64_t check_volume(const char *vol_name);
51
52 /*
53  * volume-add <device> <filesystem>
54  */
55 void
56 hammer_cmd_volume_add(char **av, int ac)
57 {
58         struct hammer_ioc_volume ioc;
59         int fd;
60
61         if (ac != 2) {
62                 fprintf(stderr, "hammer volume-add <device> <filesystem>\n");
63                 exit(1);
64         }
65
66         char *device = av[0];
67         char *filesystem = av[1];
68
69         fd = open(filesystem, O_RDONLY);
70         if (fd < 0) {
71                 fprintf(stderr, "hammer volume-add: unable to access %s: %s\n",
72                         filesystem, strerror(errno));
73                 exit(1);
74         }
75
76         /*
77          * volume-add ioctl
78          */
79         bzero(&ioc, sizeof(ioc));
80         strncpy(ioc.device_name, device, MAXPATHLEN);
81         ioc.vol_size = check_volume(device);
82         ioc.boot_area_size = HAMMER_BOOT_NOMBYTES;
83         ioc.mem_area_size = HAMMER_MEM_NOMBYTES;
84
85         if (ioctl(fd, HAMMERIOC_ADD_VOLUME, &ioc) < 0) {
86                 fprintf(stderr, "hammer volume-add ioctl: %s\n",
87                         strerror(errno));
88                 exit(1);
89         }
90
91         close(fd);
92 }
93
94 /*
95  * volume-del <device> <filesystem>
96  */
97 void
98 hammer_cmd_volume_del(char **av, int ac)
99 {
100         struct hammer_ioc_volume ioc;
101         int fd;
102
103         if (ac != 2) {
104                 fprintf(stderr, "hammer volume-del <device> <filesystem>\n");
105                 exit(1);
106         }
107
108
109         char *device = av[0];
110         char *filesystem = av[1];
111
112         fd = open(filesystem, O_RDONLY);
113         if (fd < 0) {
114                 fprintf(stderr, "hammer volume-del: unable to access %s: %s\n",
115                         filesystem, strerror(errno));
116                 exit(1);
117         }
118
119         /*
120          * volume-del ioctl
121          */
122         bzero(&ioc, sizeof(ioc));
123         strncpy(ioc.device_name, device, MAXPATHLEN);
124
125         if (ioctl(fd, HAMMERIOC_DEL_VOLUME, &ioc) < 0) {
126                 fprintf(stderr, "hammer volume-del ioctl: %s\n",
127                         strerror(errno));
128                 exit(1);
129         }
130
131         close(fd);
132 }
133
134 static void
135 hammer_print_volumes(char **av, int ac, char *cmd, char sep)
136 {
137         struct hammer_ioc_volume_list ioc;
138         int fd;
139         int i;
140
141         if (ac != 1) {
142                 fprintf(stderr, "hammer %s <filesystem>\n", cmd);
143                 exit(1);
144         }
145
146         char *filesystem = av[0];
147
148         fd = open(filesystem, O_RDONLY);
149         if (fd < 0) {
150                 fprintf(stderr,
151                     "hammer %s: unable to access %s: %s\n",
152                     cmd, filesystem, strerror(errno));
153                 exit(1);
154         }
155
156         bzero(&ioc, sizeof(ioc));
157         ioc.vols = malloc(HAMMER_MAX_VOLUMES *
158                           sizeof(struct hammer_ioc_volume));
159         if (ioc.vols == NULL) {
160                 fprintf(stderr,
161                     "hammer %s: unable to allocate memory: %s\n",
162                     cmd, strerror(errno));
163                 exit(1);
164         }
165         ioc.nvols = HAMMER_MAX_VOLUMES;
166
167         if (ioctl(fd, HAMMERIOC_LIST_VOLUMES, &ioc) < 0) {
168                 fprintf(stderr, "hammer %s ioctl: %s\n",
169                         cmd, strerror(errno));
170                 free(ioc.vols);
171                 exit(1);
172         }
173
174         for (i = 0; i < ioc.nvols; i++) {
175                 printf("%s", ioc.vols[i].device_name);
176                 if (i != ioc.nvols - 1)
177                         printf("%c", sep);
178         }
179         printf("\n");
180
181         free(ioc.vols);
182         close(fd);
183 }
184
185 /*
186  * volume-list <filesystem>
187  */
188 void
189 hammer_cmd_volume_list(char **av, int ac, char *cmd)
190 {
191         hammer_print_volumes(av, ac, cmd, '\n');
192 }
193
194 /*
195  * volume-blkdevs <filesystem>
196  */
197 void
198 hammer_cmd_volume_blkdevs(char **av, int ac, char *cmd)
199 {
200         hammer_print_volumes(av, ac, cmd, ':');
201 }
202
203 /*
204  * Check basic volume characteristics.  HAMMER filesystems use a minimum
205  * of a 16KB filesystem buffer size.
206  *
207  * Returns the size of the device.
208  *
209  * From newfs_hammer.c
210  */
211 static
212 uint64_t
213 check_volume(const char *vol_name)
214 {
215         struct partinfo pinfo;
216         int fd;
217
218         /*
219          * Get basic information about the volume
220          */
221         fd = open(vol_name, O_RDWR);
222         if (fd < 0)
223                 errx(1, "Unable to open %s R+W", vol_name);
224
225         if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
226                 errx(1, "No block device: %s", vol_name);
227         }
228         /*
229          * When formatting a block device as a HAMMER volume the
230          * sector size must be compatible. HAMMER uses 16384 byte
231          * filesystem buffers.
232          */
233         if (pinfo.reserved_blocks) {
234                 errx(1, "HAMMER cannot be placed in a partition "
235                         "which overlaps the disklabel or MBR");
236         }
237         if (pinfo.media_blksize > 16384 ||
238             16384 % pinfo.media_blksize) {
239                 errx(1, "A media sector size of %d is not supported",
240                      pinfo.media_blksize);
241         }
242
243         close(fd);
244         return pinfo.media_size;
245 }