subr.c revision 206666
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: head/sbin/geom/misc/subr.c 206666 2010-04-15 16:35:34Z pjd $"); 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 49struct std_metadata { 50 char md_magic[16]; 51 uint32_t md_version; 52}; 53 54static void 55std_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 62static void 63pathgen(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 */ 75static unsigned 76gcd(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 */ 91unsigned 92g_lcm(unsigned a, unsigned b) 93{ 94 95 return ((a * b) / gcd(a, b)); 96} 97 98uint32_t 99bitcount32(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 110off_t 111g_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 129unsigned 130g_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 148int 149g_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); 194out: 195 if (sector != NULL) 196 free(sector); 197 close(fd); 198 return (error); 199} 200 201int 202g_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 (void)ioctl(fd, DIOCGFLUSH, NULL); 240out: 241 if (sector != NULL) 242 free(sector); 243 close(fd); 244 return (error); 245} 246 247int 248g_metadata_clear(const char *name, const char *magic) 249{ 250 struct std_metadata md; 251 char path[MAXPATHLEN]; 252 unsigned sectorsize; 253 off_t mediasize; 254 u_char *sector; 255 int error, fd; 256 257 pathgen(name, path, sizeof(path)); 258 sector = NULL; 259 error = 0; 260 261 fd = open(path, O_RDWR); 262 if (fd == -1) 263 return (errno); 264 mediasize = g_get_mediasize(name); 265 if (mediasize == 0) { 266 error = errno; 267 goto out; 268 } 269 sectorsize = g_get_sectorsize(name); 270 if (sectorsize == 0) { 271 error = errno; 272 goto out; 273 } 274 sector = malloc(sectorsize); 275 if (sector == NULL) { 276 error = ENOMEM; 277 goto out; 278 } 279 if (magic != NULL) { 280 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 281 (ssize_t)sectorsize) { 282 error = errno; 283 goto out; 284 } 285 std_metadata_decode(sector, &md); 286 if (strcmp(md.md_magic, magic) != 0) { 287 error = EINVAL; 288 goto out; 289 } 290 } 291 bzero(sector, sectorsize); 292 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 293 (ssize_t)sectorsize) { 294 error = errno; 295 goto out; 296 } 297 (void)ioctl(fd, DIOCGFLUSH, NULL); 298out: 299 if (sector != NULL) 300 free(sector); 301 close(fd); 302 return (error); 303} 304 305/* 306 * Set an error message, if one does not already exist. 307 */ 308void 309gctl_error(struct gctl_req *req, const char *error, ...) 310{ 311 va_list ap; 312 313 if (req->error != NULL) 314 return; 315 va_start(ap, error); 316 vasprintf(&req->error, error, ap); 317 va_end(ap); 318} 319 320static void * 321gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 322{ 323 struct gctl_req_arg *argp; 324 char param[256]; 325 void *p; 326 unsigned i; 327 328 vsnprintf(param, sizeof(param), pfmt, ap); 329 for (i = 0; i < req->narg; i++) { 330 argp = &req->arg[i]; 331 if (strcmp(param, argp->name)) 332 continue; 333 if (!(argp->flag & GCTL_PARAM_RD)) 334 continue; 335 p = argp->value; 336 if (len == 0) { 337 /* We are looking for a string. */ 338 if (argp->len < 1) { 339 fprintf(stderr, "No length argument (%s).\n", 340 param); 341 abort(); 342 } 343 if (((char *)p)[argp->len - 1] != '\0') { 344 fprintf(stderr, "Unterminated argument (%s).\n", 345 param); 346 abort(); 347 } 348 } else if ((int)len != argp->len) { 349 fprintf(stderr, "Wrong length %s argument.\n", param); 350 abort(); 351 } 352 return (p); 353 } 354 fprintf(stderr, "No such argument (%s).\n", param); 355 abort(); 356} 357 358int 359gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 360{ 361 int *p; 362 va_list ap; 363 364 va_start(ap, pfmt); 365 p = gctl_get_param(req, sizeof(int), pfmt, ap); 366 va_end(ap); 367 return (*p); 368} 369 370intmax_t 371gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 372{ 373 intmax_t *p; 374 va_list ap; 375 376 va_start(ap, pfmt); 377 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 378 va_end(ap); 379 return (*p); 380} 381 382const char * 383gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 384{ 385 const char *p; 386 va_list ap; 387 388 va_start(ap, pfmt); 389 p = gctl_get_param(req, 0, pfmt, ap); 390 va_end(ap); 391 return (p); 392} 393 394int 395gctl_change_param(struct gctl_req *req, const char *name, int len, 396 const void *value) 397{ 398 struct gctl_req_arg *ap; 399 unsigned i; 400 401 if (req == NULL || req->error != NULL) 402 return (EDOOFUS); 403 for (i = 0; i < req->narg; i++) { 404 ap = &req->arg[i]; 405 if (strcmp(ap->name, name) != 0) 406 continue; 407 ap->value = __DECONST(void *, value); 408 if (len >= 0) { 409 ap->flag &= ~GCTL_PARAM_ASCII; 410 ap->len = len; 411 } else if (len < 0) { 412 ap->flag |= GCTL_PARAM_ASCII; 413 ap->len = strlen(value) + 1; 414 } 415 return (0); 416 } 417 return (ENOENT); 418} 419 420int 421gctl_delete_param(struct gctl_req *req, const char *name) 422{ 423 struct gctl_req_arg *ap; 424 unsigned int i; 425 426 if (req == NULL || req->error != NULL) 427 return (EDOOFUS); 428 429 i = 0; 430 while (i < req->narg) { 431 ap = &req->arg[i]; 432 if (strcmp(ap->name, name) == 0) 433 break; 434 i++; 435 } 436 if (i == req->narg) 437 return (ENOENT); 438 439 req->narg--; 440 while (i < req->narg) { 441 req->arg[i] = req->arg[i + 1]; 442 i++; 443 } 444 return (0); 445} 446 447int 448gctl_has_param(struct gctl_req *req, const char *name) 449{ 450 struct gctl_req_arg *ap; 451 unsigned int i; 452 453 if (req == NULL || req->error != NULL) 454 return (0); 455 456 for (i = 0; i < req->narg; i++) { 457 ap = &req->arg[i]; 458 if (strcmp(ap->name, name) == 0) 459 return (1); 460 } 461 return (0); 462} 463