xref: /dragonfly/sbin/hammer/cmd_volume.c (revision 267c04fd)
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, const char *cmd, const 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, const 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, const 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 }
246