HAMMER - Implement volume-list command
[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  */
43
44 #include "hammer.h"
45 #include <string.h>
46 #include <stdlib.h>
47
48 static uint64_t check_volume(const char *vol_name);
49
50 /*
51  * volume-add <device> <filesystem>
52  */
53 void
54 hammer_cmd_volume_add(char **av, int ac)
55 {
56         struct hammer_ioc_volume ioc;
57         int fd;
58
59         if (ac != 2) {
60                 fprintf(stderr, "hammer volume-add <device> <filesystem>\n");
61                 exit(1);
62         }
63
64         char *device = av[0];
65         char *filesystem = av[1];
66
67         fd = open(filesystem, O_RDONLY);
68         if (fd < 0) {
69                 fprintf(stderr, "hammer volume-add: unable to access %s: %s\n",
70                         filesystem, strerror(errno));
71                 exit(1);
72         }
73
74         /*
75          * volume-add ioctl
76          */
77         bzero(&ioc, sizeof(ioc));
78         strncpy(ioc.device_name, device, MAXPATHLEN);
79         ioc.vol_size = check_volume(device);
80         ioc.boot_area_size = HAMMER_BOOT_NOMBYTES;
81         ioc.mem_area_size = HAMMER_MEM_NOMBYTES;
82
83         if (ioctl(fd, HAMMERIOC_ADD_VOLUME, &ioc) < 0) {
84                 fprintf(stderr, "hammer volume-add ioctl: %s\n",
85                         strerror(errno));
86                 exit(1);
87         }
88
89         close(fd);
90 }
91
92 /*
93  * volume-del <device> <filesystem>
94  */
95 void
96 hammer_cmd_volume_del(char **av, int ac)
97 {
98         struct hammer_ioc_volume ioc;
99         int fd;
100
101         if (ac != 2) {
102                 fprintf(stderr, "hammer volume-del <device> <filesystem>\n");
103                 exit(1);
104         }
105
106
107         char *device = av[0];
108         char *filesystem = av[1];
109
110         fd = open(filesystem, O_RDONLY);
111         if (fd < 0) {
112                 fprintf(stderr, "hammer volume-del: unable to access %s: %s\n",
113                         filesystem, strerror(errno));
114                 exit(1);
115         }
116
117         /*
118          * volume-del ioctl
119          */
120         bzero(&ioc, sizeof(ioc));
121         strncpy(ioc.device_name, device, MAXPATHLEN);
122
123         if (ioctl(fd, HAMMERIOC_DEL_VOLUME, &ioc) < 0) {
124                 fprintf(stderr, "hammer volume-del ioctl: %s\n",
125                         strerror(errno));
126                 exit(1);
127         }
128
129         close(fd);
130 }
131
132 /*
133  * volume-list <filesystem>
134  */
135 void
136 hammer_cmd_volume_list(char **av, int ac)
137 {
138         struct hammer_ioc_volume_list ioc;
139         int fd;
140
141         if (ac != 1) {
142                 fprintf(stderr, "hammer volume-list <filesystem>\n");
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 volume-list: unable to access %s: %s\n",
152                     filesystem, strerror(errno));
153                 exit(1);
154         }
155
156         /*
157          * volume-list ioctl
158          */
159         bzero(&ioc, sizeof(ioc));
160         ioc.vols = malloc(HAMMER_MAX_VOLUMES *
161                           sizeof(struct hammer_ioc_volume));
162         if (ioc.vols == NULL) {
163                 fprintf(stderr,
164                     "hammer volume-list: unable to allocate memory: %s\n",
165                     strerror(errno));
166                 exit(1);
167         }
168         ioc.nvols = HAMMER_MAX_VOLUMES;
169
170         if (ioctl(fd, HAMMERIOC_LIST_VOLUMES, &ioc) < 0) {
171                 fprintf(stderr, "hammer volume-list ioctl: %s\n",
172                         strerror(errno));
173                 free(ioc.vols);
174                 exit(1);
175         }
176
177         int i;
178         for (i = 0; i < ioc.nvols; i++)
179                 printf("%s\n", ioc.vols[i].device_name);
180
181         free(ioc.vols);
182         close(fd);
183 }
184
185 /*
186  * Check basic volume characteristics.  HAMMER filesystems use a minimum
187  * of a 16KB filesystem buffer size.
188  *
189  * Returns the size of the device.
190  *
191  * From newfs_hammer.c
192  */
193 static
194 uint64_t
195 check_volume(const char *vol_name)
196 {
197         struct partinfo pinfo;
198         int fd;
199
200         /*
201          * Get basic information about the volume
202          */
203         fd = open(vol_name, O_RDWR);
204         if (fd < 0)
205                 errx(1, "Unable to open %s R+W", vol_name);
206
207         if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
208                 errx(1, "No block device: %s", vol_name);
209         }
210         /*
211          * When formatting a block device as a HAMMER volume the
212          * sector size must be compatible. HAMMER uses 16384 byte
213          * filesystem buffers.
214          */
215         if (pinfo.reserved_blocks) {
216                 errx(1, "HAMMER cannot be placed in a partition "
217                         "which overlaps the disklabel or MBR");
218         }
219         if (pinfo.media_blksize > 16384 ||
220             16384 % pinfo.media_blksize) {
221                 errx(1, "A media sector size of %d is not supported",
222                      pinfo.media_blksize);
223         }
224
225         close(fd);
226         return pinfo.media_size;
227 }