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 static void * 319 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 320 { 321 struct gctl_req_arg *argp; 322 char param[256]; 323 void *p; 324 unsigned i; 325 326 vsnprintf(param, sizeof(param), pfmt, ap); 327 for (i = 0; i < req->narg; i++) { 328 argp = &req->arg[i]; 329 if (strcmp(param, argp->name)) 330 continue; 331 if (!(argp->flag & GCTL_PARAM_RD)) 332 continue; 333 p = argp->value; 334 if (len == 0) { 335 /* We are looking for a string. */ 336 if (argp->len < 1) { 337 fprintf(stderr, "No length argument (%s).\n", 338 param); 339 abort(); 340 } 341 if (((char *)p)[argp->len - 1] != '\0') { 342 fprintf(stderr, "Unterminated argument (%s).\n", 343 param); 344 abort(); 345 } 346 } else if ((int)len != argp->len) { 347 fprintf(stderr, "Wrong length %s argument.\n", param); 348 abort(); 349 } 350 return (p); 351 } 352 fprintf(stderr, "No such argument (%s).\n", param); 353 abort(); 354 } 355 356 int 357 gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 358 { 359 int *p; 360 va_list ap; 361 362 va_start(ap, pfmt); 363 p = gctl_get_param(req, sizeof(int), pfmt, ap); 364 va_end(ap); 365 return (*p); 366 } 367 368 intmax_t 369 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 370 { 371 intmax_t *p; 372 va_list ap; 373 374 va_start(ap, pfmt); 375 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 376 va_end(ap); 377 return (*p); 378 } 379 380 const char * 381 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 382 { 383 const char *p; 384 va_list ap; 385 386 va_start(ap, pfmt); 387 p = gctl_get_param(req, 0, pfmt, ap); 388 va_end(ap); 389 return (p); 390 } 391 392 int 393 gctl_change_param(struct gctl_req *req, const char *name, int len, 394 const void *value) 395 { 396 struct gctl_req_arg *ap; 397 unsigned i; 398 399 if (req == NULL || req->error != NULL) 400 return (EDOOFUS); 401 for (i = 0; i < req->narg; i++) { 402 ap = &req->arg[i]; 403 if (strcmp(ap->name, name) != 0) 404 continue; 405 ap->value = __DECONST(void *, value); 406 if (len >= 0) { 407 ap->flag &= ~GCTL_PARAM_ASCII; 408 ap->len = len; 409 } else if (len < 0) { 410 ap->flag |= GCTL_PARAM_ASCII; 411 ap->len = strlen(value) + 1; 412 } 413 return (0); 414 } 415 return (ENOENT); 416 } 417