1 /*- 2 * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/disk.h> 32 #include <sys/endian.h> 33 #include <sys/uio.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <paths.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <stdarg.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <unistd.h> 43 #include <assert.h> 44 #include <libgeom.h> 45 46 #include "misc/subr.h" 47 48 49 struct std_metadata { 50 char md_magic[16]; 51 uint32_t md_version; 52 }; 53 54 static void 55 std_metadata_decode(const u_char *data, struct std_metadata *md) 56 { 57 58 bcopy(data, md->md_magic, sizeof(md->md_magic)); 59 md->md_version = le32dec(data + 16); 60 } 61 62 static void 63 pathgen(const char *name, char *path, size_t size) 64 { 65 66 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 67 snprintf(path, size, "%s%s", _PATH_DEV, name); 68 else 69 strlcpy(path, name, size); 70 } 71 72 /* 73 * Greatest Common Divisor. 74 */ 75 static unsigned 76 gcd(unsigned a, unsigned b) 77 { 78 u_int c; 79 80 while (b != 0) { 81 c = a; 82 a = b; 83 b = (c % b); 84 } 85 return (a); 86 } 87 88 /* 89 * Least Common Multiple. 90 */ 91 unsigned 92 g_lcm(unsigned a, unsigned b) 93 { 94 95 return ((a * b) / gcd(a, b)); 96 } 97 98 uint32_t 99 bitcount32(uint32_t x) 100 { 101 102 x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 103 x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 104 x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 105 x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 106 x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 107 return (x); 108 } 109 110 off_t 111 g_get_mediasize(const char *name) 112 { 113 char path[MAXPATHLEN]; 114 off_t mediasize; 115 int fd; 116 117 pathgen(name, path, sizeof(path)); 118 fd = open(path, O_RDONLY); 119 if (fd == -1) 120 return (0); 121 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 122 close(fd); 123 return (0); 124 } 125 close(fd); 126 return (mediasize); 127 } 128 129 unsigned 130 g_get_sectorsize(const char *name) 131 { 132 char path[MAXPATHLEN]; 133 unsigned sectorsize; 134 int fd; 135 136 pathgen(name, path, sizeof(path)); 137 fd = open(path, O_RDONLY); 138 if (fd == -1) 139 return (0); 140 if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 141 close(fd); 142 return (0); 143 } 144 close(fd); 145 return (sectorsize); 146 } 147 148 int 149 g_metadata_read(const char *name, u_char *md, size_t size, const char *magic) 150 { 151 struct std_metadata stdmd; 152 char path[MAXPATHLEN]; 153 unsigned sectorsize; 154 off_t mediasize; 155 u_char *sector; 156 int error, fd; 157 158 pathgen(name, path, sizeof(path)); 159 sector = NULL; 160 error = 0; 161 162 fd = open(path, O_RDONLY); 163 if (fd == -1) 164 return (errno); 165 mediasize = g_get_mediasize(name); 166 if (mediasize == 0) { 167 error = errno; 168 goto out; 169 } 170 sectorsize = g_get_sectorsize(name); 171 if (sectorsize == 0) { 172 error = errno; 173 goto out; 174 } 175 assert(sectorsize >= size); 176 sector = malloc(sectorsize); 177 if (sector == NULL) { 178 error = ENOMEM; 179 goto out; 180 } 181 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 182 (ssize_t)sectorsize) { 183 error = errno; 184 goto out; 185 } 186 if (magic != NULL) { 187 std_metadata_decode(sector, &stdmd); 188 if (strcmp(stdmd.md_magic, magic) != 0) { 189 error = EINVAL; 190 goto out; 191 } 192 } 193 bcopy(sector, md, size); 194 out: 195 if (sector != NULL) 196 free(sector); 197 close(fd); 198 return (error); 199 } 200 201 int 202 g_metadata_store(const char *name, u_char *md, size_t size) 203 { 204 char path[MAXPATHLEN]; 205 unsigned sectorsize; 206 off_t mediasize; 207 u_char *sector; 208 int error, fd; 209 210 pathgen(name, path, sizeof(path)); 211 sector = NULL; 212 error = 0; 213 214 fd = open(path, O_WRONLY); 215 if (fd == -1) 216 return (errno); 217 mediasize = g_get_mediasize(name); 218 if (mediasize == 0) { 219 error = errno; 220 goto out; 221 } 222 sectorsize = g_get_sectorsize(name); 223 if (sectorsize == 0) { 224 error = errno; 225 goto out; 226 } 227 assert(sectorsize >= size); 228 sector = malloc(sectorsize); 229 if (sector == NULL) { 230 error = ENOMEM; 231 goto out; 232 } 233 bcopy(md, sector, size); 234 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 235 (ssize_t)sectorsize) { 236 error = errno; 237 goto out; 238 } 239 out: 240 if (sector != NULL) 241 free(sector); 242 close(fd); 243 return (error); 244 } 245 246 int 247 g_metadata_clear(const char *name, const char *magic) 248 { 249 struct std_metadata md; 250 char path[MAXPATHLEN]; 251 unsigned sectorsize; 252 off_t mediasize; 253 u_char *sector; 254 int error, fd; 255 256 pathgen(name, path, sizeof(path)); 257 sector = NULL; 258 error = 0; 259 260 fd = open(path, O_RDWR); 261 if (fd == -1) 262 return (errno); 263 mediasize = g_get_mediasize(name); 264 if (mediasize == 0) { 265 error = errno; 266 goto out; 267 } 268 sectorsize = g_get_sectorsize(name); 269 if (sectorsize == 0) { 270 error = errno; 271 goto out; 272 } 273 sector = malloc(sectorsize); 274 if (sector == NULL) { 275 error = ENOMEM; 276 goto out; 277 } 278 if (magic != NULL) { 279 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 280 (ssize_t)sectorsize) { 281 error = errno; 282 goto out; 283 } 284 std_metadata_decode(sector, &md); 285 if (strcmp(md.md_magic, magic) != 0) { 286 error = EINVAL; 287 goto out; 288 } 289 } 290 bzero(sector, sectorsize); 291 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 292 (ssize_t)sectorsize) { 293 error = errno; 294 goto out; 295 } 296 out: 297 if (sector != NULL) 298 free(sector); 299 close(fd); 300 return (error); 301 } 302 303 /* 304 * Set an error message, if one does not already exist. 305 */ 306 void 307 gctl_error(struct gctl_req *req, const char *error, ...) 308 { 309 va_list ap; 310 311 if (req->error != NULL) 312 return; 313 va_start(ap, error); 314 vasprintf(&req->error, error, ap); 315 va_end(ap); 316 } 317 318 void * 319 gctl_get_param(struct gctl_req *req, const char *param, int *len) 320 { 321 unsigned i; 322 void *p; 323 struct gctl_req_arg *ap; 324 325 for (i = 0; i < req->narg; i++) { 326 ap = &req->arg[i]; 327 if (strcmp(param, ap->name)) 328 continue; 329 if (!(ap->flag & GCTL_PARAM_RD)) 330 continue; 331 p = ap->value; 332 if (len != NULL) 333 *len = ap->len; 334 return (p); 335 } 336 return (NULL); 337 } 338 339 char const * 340 gctl_get_asciiparam(struct gctl_req *req, const char *param) 341 { 342 unsigned i; 343 char const *p; 344 struct gctl_req_arg *ap; 345 346 for (i = 0; i < req->narg; i++) { 347 ap = &req->arg[i]; 348 if (strcmp(param, ap->name)) 349 continue; 350 if (!(ap->flag & GCTL_PARAM_RD)) 351 continue; 352 p = ap->value; 353 if (ap->len < 1) { 354 gctl_error(req, "No length argument (%s)", param); 355 return (NULL); 356 } 357 if (p[ap->len - 1] != '\0') { 358 gctl_error(req, "Unterminated argument (%s)", param); 359 return (NULL); 360 } 361 return (p); 362 } 363 return (NULL); 364 } 365 366 void * 367 gctl_get_paraml(struct gctl_req *req, const char *param, int len) 368 { 369 int i; 370 void *p; 371 372 p = gctl_get_param(req, param, &i); 373 if (p == NULL) 374 gctl_error(req, "Missing %s argument", param); 375 else if (i != len) { 376 p = NULL; 377 gctl_error(req, "Wrong length %s argument", param); 378 } 379 return (p); 380 } 381