geom_part.c revision 208777
1/*- 2 * Copyright (c) 2007, 2008 Marcel Moolenaar 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/class/part/geom_part.c 208777 2010-06-03 13:01:55Z marius $"); 29 30#include <sys/stat.h> 31#include <sys/vtoc.h> 32 33#include <assert.h> 34#include <err.h> 35#include <errno.h> 36#include <fcntl.h> 37#include <libgeom.h> 38#include <libutil.h> 39#include <paths.h> 40#include <stdint.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <strings.h> 45#include <unistd.h> 46 47#include "core/geom.h" 48#include "misc/subr.h" 49 50#ifdef STATIC_GEOM_CLASSES 51#define PUBSYM(x) gpart_##x 52#else 53#define PUBSYM(x) x 54#endif 55 56uint32_t PUBSYM(lib_version) = G_LIB_VERSION; 57uint32_t PUBSYM(version) = 0; 58 59static char autofill[] = "*"; 60static char optional[] = ""; 61static char flags[] = "C"; 62 63static const char const bootcode_param[] = "bootcode"; 64static const char const index_param[] = "index"; 65static const char const partcode_param[] = "partcode"; 66 67static struct gclass *find_class(struct gmesh *, const char *); 68static struct ggeom * find_geom(struct gclass *, const char *); 69static const char *find_geomcfg(struct ggeom *, const char *); 70static const char *find_provcfg(struct gprovider *, const char *); 71static struct gprovider *find_provider(struct ggeom *, 72 unsigned long long); 73static const char *fmtsize(int64_t); 74static int gpart_autofill(struct gctl_req *); 75static int gpart_autofill_resize(struct gctl_req *); 76static void gpart_bootcode(struct gctl_req *, unsigned int); 77static void *gpart_bootfile_read(const char *, ssize_t *); 78static void gpart_issue(struct gctl_req *, unsigned int); 79static void gpart_show(struct gctl_req *, unsigned int); 80static void gpart_show_geom(struct ggeom *, const char *); 81static int gpart_show_hasopt(struct gctl_req *, const char *, const char *); 82static void gpart_write_partcode(struct ggeom *, int, void *, ssize_t); 83static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *); 84 85struct g_command PUBSYM(class_commands)[] = { 86 { "add", 0, gpart_issue, { 87 { 'b', "start", autofill, G_TYPE_ASCLBA }, 88 { 's', "size", autofill, G_TYPE_ASCLBA }, 89 { 't', "type", NULL, G_TYPE_STRING }, 90 { 'i', index_param, optional, G_TYPE_ASCNUM }, 91 { 'l', "label", optional, G_TYPE_STRING }, 92 { 'f', "flags", flags, G_TYPE_STRING }, 93 G_OPT_SENTINEL }, 94 "geom", NULL 95 }, 96 { "bootcode", 0, gpart_bootcode, { 97 { 'b', bootcode_param, optional, G_TYPE_STRING }, 98 { 'p', partcode_param, optional, G_TYPE_STRING }, 99 { 'i', index_param, optional, G_TYPE_ASCNUM }, 100 { 'f', "flags", flags, G_TYPE_STRING }, 101 G_OPT_SENTINEL }, 102 "geom", NULL 103 }, 104 { "commit", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, 105 { "create", 0, gpart_issue, { 106 { 's', "scheme", NULL, G_TYPE_STRING }, 107 { 'n', "entries", optional, G_TYPE_ASCNUM }, 108 { 'f', "flags", flags, G_TYPE_STRING }, 109 G_OPT_SENTINEL }, 110 "provider", NULL 111 }, 112 { "delete", 0, gpart_issue, { 113 { 'i', index_param, NULL, G_TYPE_ASCNUM }, 114 { 'f', "flags", flags, G_TYPE_STRING }, 115 G_OPT_SENTINEL }, 116 "geom", NULL 117 }, 118 { "destroy", 0, gpart_issue, { 119 { 'f', "flags", flags, G_TYPE_STRING }, 120 G_OPT_SENTINEL }, 121 "geom", NULL }, 122 { "modify", 0, gpart_issue, { 123 { 'i', index_param, NULL, G_TYPE_ASCNUM }, 124 { 'l', "label", optional, G_TYPE_STRING }, 125 { 't', "type", optional, G_TYPE_STRING }, 126 { 'f', "flags", flags, G_TYPE_STRING }, 127 G_OPT_SENTINEL }, 128 "geom", NULL 129 }, 130 { "set", 0, gpart_issue, { 131 { 'a', "attrib", NULL, G_TYPE_STRING }, 132 { 'i', index_param, NULL, G_TYPE_ASCNUM }, 133 { 'f', "flags", flags, G_TYPE_STRING }, 134 G_OPT_SENTINEL }, 135 "geom", NULL 136 }, 137 { "show", 0, gpart_show, { 138 { 'l', "show_label", NULL, G_TYPE_BOOL }, 139 { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, 140 G_OPT_SENTINEL }, 141 NULL, "[-lr] [geom ...]" 142 }, 143 { "undo", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, 144 { "unset", 0, gpart_issue, { 145 { 'a', "attrib", NULL, G_TYPE_STRING }, 146 { 'i', index_param, NULL, G_TYPE_ASCNUM }, 147 { 'f', "flags", flags, G_TYPE_STRING }, 148 G_OPT_SENTINEL }, 149 "geom", NULL 150 }, 151 { "resize", 0, gpart_issue, { 152 { 's', "size", autofill, G_TYPE_ASCLBA }, 153 { 'i', index_param, NULL, G_TYPE_ASCNUM }, 154 { 'f', "flags", flags, G_TYPE_STRING }, 155 G_OPT_SENTINEL }, 156 "geom", NULL 157 }, 158 G_CMD_SENTINEL 159}; 160 161static struct gclass * 162find_class(struct gmesh *mesh, const char *name) 163{ 164 struct gclass *classp; 165 166 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 167 if (strcmp(classp->lg_name, name) == 0) 168 return (classp); 169 } 170 return (NULL); 171} 172 173static struct ggeom * 174find_geom(struct gclass *classp, const char *name) 175{ 176 struct ggeom *gp; 177 178 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 179 if (strcmp(gp->lg_name, name) == 0) 180 return (gp); 181 } 182 return (NULL); 183} 184 185static const char * 186find_geomcfg(struct ggeom *gp, const char *cfg) 187{ 188 struct gconfig *gc; 189 190 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 191 if (!strcmp(gc->lg_name, cfg)) 192 return (gc->lg_val); 193 } 194 return (NULL); 195} 196 197static const char * 198find_provcfg(struct gprovider *pp, const char *cfg) 199{ 200 struct gconfig *gc; 201 202 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 203 if (!strcmp(gc->lg_name, cfg)) 204 return (gc->lg_val); 205 } 206 return (NULL); 207} 208 209static struct gprovider * 210find_provider(struct ggeom *gp, unsigned long long minsector) 211{ 212 struct gprovider *pp, *bestpp; 213 const char *s; 214 unsigned long long sector, bestsector; 215 216 bestpp = NULL; 217 bestsector = 0; 218 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 219 s = find_provcfg(pp, "start"); 220 if (s == NULL) { 221 s = find_provcfg(pp, "offset"); 222 sector = atoll(s) / pp->lg_sectorsize; 223 } else 224 sector = atoll(s); 225 226 if (sector < minsector) 227 continue; 228 if (bestpp != NULL && sector >= bestsector) 229 continue; 230 231 bestpp = pp; 232 bestsector = sector; 233 } 234 return (bestpp); 235} 236 237static const char * 238fmtsize(int64_t rawsz) 239{ 240 static char buf[5]; 241 242 humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, 243 HN_B | HN_NOSPACE | HN_DECIMAL); 244 return (buf); 245} 246 247static const char * 248fmtattrib(struct gprovider *pp) 249{ 250 static char buf[128]; 251 struct gconfig *gc; 252 u_int idx; 253 254 buf[0] = '\0'; 255 idx = 0; 256 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 257 if (strcmp(gc->lg_name, "attrib") != 0) 258 continue; 259 idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", 260 (idx == 0) ? " [" : ",", gc->lg_val); 261 } 262 if (idx > 0) 263 snprintf(buf + idx, sizeof(buf) - idx, "] "); 264 return (buf); 265} 266 267static int 268gpart_autofill_resize(struct gctl_req *req) 269{ 270 struct gmesh mesh; 271 struct gclass *cp; 272 struct ggeom *gp; 273 struct gprovider *pp; 274 unsigned long long last, size, start, new_size; 275 unsigned long long lba, new_lba; 276 const char *s; 277 char *val; 278 int error, idx; 279 280 s = gctl_get_ascii(req, "size"); 281 if (*s == '*') 282 new_size = (unsigned long long)atoll(s); 283 else 284 return (0); 285 286 s = gctl_get_ascii(req, index_param); 287 idx = strtol(s, &val, 10); 288 if (idx < 1 || *s == '\0' || *val != '\0') 289 errx(EXIT_FAILURE, "invalid partition index"); 290 291 error = geom_gettree(&mesh); 292 if (error) 293 return (error); 294 s = gctl_get_ascii(req, "class"); 295 if (s == NULL) 296 abort(); 297 cp = find_class(&mesh, s); 298 if (cp == NULL) 299 errx(EXIT_FAILURE, "Class %s not found.", s); 300 s = gctl_get_ascii(req, "geom"); 301 if (s == NULL) 302 abort(); 303 gp = find_geom(cp, s); 304 if (gp == NULL) 305 errx(EXIT_FAILURE, "No such geom: %s.", s); 306 last = atoll(find_geomcfg(gp, "last")); 307 308 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 309 s = find_provcfg(pp, "index"); 310 if (s == NULL) 311 continue; 312 if (atoi(s) == idx) 313 break; 314 } 315 if (pp == NULL) 316 errx(EXIT_FAILURE, "invalid partition index"); 317 318 s = find_provcfg(pp, "start"); 319 if (s == NULL) { 320 s = find_provcfg(pp, "offset"); 321 start = atoll(s) / pp->lg_sectorsize; 322 } else 323 start = atoll(s); 324 s = find_provcfg(pp, "end"); 325 if (s == NULL) { 326 s = find_provcfg(pp, "length"); 327 lba = start + atoll(s) / pp->lg_sectorsize; 328 } else 329 lba = atoll(s) + 1; 330 331 if (lba > last) 332 return (ENOSPC); 333 size = lba - start; 334 pp = find_provider(gp, lba); 335 if (pp == NULL) 336 new_size = last - start + 1; 337 else { 338 s = find_provcfg(pp, "start"); 339 if (s == NULL) { 340 s = find_provcfg(pp, "offset"); 341 new_lba = atoll(s) / pp->lg_sectorsize; 342 } else 343 new_lba = atoll(s); 344 /* Is there any free space between current and 345 * next providers? 346 */ 347 if (new_lba > lba) 348 new_size = new_lba - start; 349 else 350 return (ENOSPC); 351 } 352 asprintf(&val, "%llu", new_size); 353 if (val == NULL) 354 return (ENOMEM); 355 gctl_change_param(req, "size", -1, val); 356 357 return (0); 358} 359 360static int 361gpart_autofill(struct gctl_req *req) 362{ 363 struct gmesh mesh; 364 struct gclass *cp; 365 struct ggeom *gp; 366 struct gprovider *pp; 367 unsigned long long first, last; 368 unsigned long long size, start; 369 unsigned long long lba, len, grade; 370 const char *s; 371 char *val; 372 int error, has_size, has_start; 373 374 s = gctl_get_ascii(req, "verb"); 375 if (strcmp(s, "resize") == 0) 376 return gpart_autofill_resize(req); 377 if (strcmp(s, "add") != 0) 378 return (0); 379 380 s = gctl_get_ascii(req, "size"); 381 has_size = (*s == '*') ? 0 : 1; 382 size = (has_size) ? (unsigned long long)atoll(s) : 0ULL; 383 384 s = gctl_get_ascii(req, "start"); 385 has_start = (*s == '*') ? 0 : 1; 386 start = (has_start) ? (unsigned long long)atoll(s) : ~0ULL; 387 388 /* No autofill necessary. */ 389 if (has_size && has_start) 390 return (0); 391 392 error = geom_gettree(&mesh); 393 if (error) 394 return (error); 395 s = gctl_get_ascii(req, "class"); 396 if (s == NULL) 397 abort(); 398 cp = find_class(&mesh, s); 399 if (cp == NULL) 400 errx(EXIT_FAILURE, "Class %s not found.", s); 401 s = gctl_get_ascii(req, "geom"); 402 if (s == NULL) 403 abort(); 404 gp = find_geom(cp, s); 405 if (gp == NULL) 406 errx(EXIT_FAILURE, "No such geom: %s.", s); 407 first = atoll(find_geomcfg(gp, "first")); 408 last = atoll(find_geomcfg(gp, "last")); 409 grade = ~0ULL; 410 while ((pp = find_provider(gp, first)) != NULL) { 411 s = find_provcfg(pp, "start"); 412 if (s == NULL) { 413 s = find_provcfg(pp, "offset"); 414 lba = atoll(s) / pp->lg_sectorsize; 415 } else 416 lba = atoll(s); 417 418 if (first < lba) { 419 /* Free space [first, lba> */ 420 len = lba - first; 421 if (has_size) { 422 if (len >= size && len - size < grade) { 423 start = first; 424 grade = len - size; 425 } 426 } else if (has_start) { 427 if (start >= first && start < lba) { 428 size = lba - start; 429 grade = start - first; 430 } 431 } else { 432 if (grade == ~0ULL || len > size) { 433 start = first; 434 size = len; 435 grade = 0; 436 } 437 } 438 } 439 440 s = find_provcfg(pp, "end"); 441 if (s == NULL) { 442 s = find_provcfg(pp, "length"); 443 first = lba + atoll(s) / pp->lg_sectorsize; 444 } else 445 first = atoll(s) + 1; 446 } 447 if (first <= last) { 448 /* Free space [first-last] */ 449 len = last - first + 1; 450 if (has_size) { 451 if (len >= size && len - size < grade) { 452 start = first; 453 grade = len - size; 454 } 455 } else if (has_start) { 456 if (start >= first && start <= last) { 457 size = last - start + 1; 458 grade = start - first; 459 } 460 } else { 461 if (grade == ~0ULL || len > size) { 462 start = first; 463 size = len; 464 grade = 0; 465 } 466 } 467 } 468 469 if (grade == ~0ULL) 470 return (ENOSPC); 471 472 if (!has_size) { 473 asprintf(&val, "%llu", size); 474 if (val == NULL) 475 return (ENOMEM); 476 gctl_change_param(req, "size", -1, val); 477 } 478 if (!has_start) { 479 asprintf(&val, "%llu", start); 480 if (val == NULL) 481 return (ENOMEM); 482 gctl_change_param(req, "start", -1, val); 483 } 484 return (0); 485} 486 487static void 488gpart_show_geom(struct ggeom *gp, const char *element) 489{ 490 struct gprovider *pp; 491 const char *s, *scheme; 492 unsigned long long first, last, sector, end; 493 unsigned long long length, secsz; 494 int idx, wblocks, wname; 495 496 scheme = find_geomcfg(gp, "scheme"); 497 s = find_geomcfg(gp, "first"); 498 first = atoll(s); 499 s = find_geomcfg(gp, "last"); 500 last = atoll(s); 501 wblocks = strlen(s); 502 wname = strlen(gp->lg_name); 503 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 504 secsz = pp->lg_sectorsize; 505 printf("=>%*llu %*llu %*s %s (%s)\n", 506 wblocks, first, wblocks, (last - first + 1), 507 wname, gp->lg_name, 508 scheme, fmtsize(pp->lg_mediasize)); 509 510 while ((pp = find_provider(gp, first)) != NULL) { 511 s = find_provcfg(pp, "start"); 512 if (s == NULL) { 513 s = find_provcfg(pp, "offset"); 514 sector = atoll(s) / secsz; 515 } else 516 sector = atoll(s); 517 518 s = find_provcfg(pp, "end"); 519 if (s == NULL) { 520 s = find_provcfg(pp, "length"); 521 length = atoll(s) / secsz; 522 end = sector + length - 1; 523 } else { 524 end = atoll(s); 525 length = end - sector + 1; 526 } 527 s = find_provcfg(pp, "index"); 528 idx = atoi(s); 529 if (first < sector) { 530 printf(" %*llu %*llu %*s - free - (%s)\n", 531 wblocks, first, wblocks, sector - first, 532 wname, "", 533 fmtsize((sector - first) * secsz)); 534 } 535 printf(" %*llu %*llu %*d %s %s (%s)\n", 536 wblocks, sector, wblocks, length, 537 wname, idx, find_provcfg(pp, element), 538 fmtattrib(pp), fmtsize(pp->lg_mediasize)); 539 first = end + 1; 540 } 541 if (first <= last) { 542 length = last - first + 1; 543 printf(" %*llu %*llu %*s - free - (%s)\n", 544 wblocks, first, wblocks, length, 545 wname, "", 546 fmtsize(length * secsz)); 547 } 548 printf("\n"); 549} 550 551static int 552gpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 553{ 554 555 if (!gctl_get_int(req, opt)) 556 return (0); 557 558 if (elt != NULL) 559 errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 560 561 return (1); 562} 563 564static void 565gpart_show(struct gctl_req *req, unsigned int fl __unused) 566{ 567 struct gmesh mesh; 568 struct gclass *classp; 569 struct ggeom *gp; 570 const char *element, *name; 571 int error, i, nargs; 572 573 element = NULL; 574 if (gpart_show_hasopt(req, "show_label", element)) 575 element = "label"; 576 if (gpart_show_hasopt(req, "show_rawtype", element)) 577 element = "rawtype"; 578 if (element == NULL) 579 element = "type"; 580 581 name = gctl_get_ascii(req, "class"); 582 if (name == NULL) 583 abort(); 584 error = geom_gettree(&mesh); 585 if (error != 0) 586 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 587 classp = find_class(&mesh, name); 588 if (classp == NULL) { 589 geom_deletetree(&mesh); 590 errx(EXIT_FAILURE, "Class %s not found.", name); 591 } 592 nargs = gctl_get_int(req, "nargs"); 593 if (nargs > 0) { 594 for (i = 0; i < nargs; i++) { 595 name = gctl_get_ascii(req, "arg%d", i); 596 gp = find_geom(classp, name); 597 if (gp != NULL) 598 gpart_show_geom(gp, element); 599 else 600 errx(EXIT_FAILURE, "No such geom: %s.", name); 601 } 602 } else { 603 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 604 gpart_show_geom(gp, element); 605 } 606 } 607 geom_deletetree(&mesh); 608} 609 610static void * 611gpart_bootfile_read(const char *bootfile, ssize_t *size) 612{ 613 struct stat sb; 614 void *code; 615 int fd; 616 617 if (stat(bootfile, &sb) == -1) 618 err(EXIT_FAILURE, "%s", bootfile); 619 if (!S_ISREG(sb.st_mode)) 620 errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 621 if (sb.st_size == 0) 622 errx(EXIT_FAILURE, "%s: empty file", bootfile); 623 if (*size > 0 && sb.st_size > *size) 624 errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 625 *size); 626 627 *size = sb.st_size; 628 629 fd = open(bootfile, O_RDONLY); 630 if (fd == -1) 631 err(EXIT_FAILURE, "%s", bootfile); 632 code = malloc(*size); 633 if (code == NULL) 634 err(EXIT_FAILURE, NULL); 635 if (read(fd, code, *size) != *size) 636 err(EXIT_FAILURE, "%s", bootfile); 637 close(fd); 638 639 return (code); 640} 641 642static void 643gpart_write_partcode(struct ggeom *gp, int idx, void *code, ssize_t size) 644{ 645 char dsf[128]; 646 struct gprovider *pp; 647 const char *s; 648 char *buf; 649 off_t bsize; 650 int fd; 651 652 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 653 s = find_provcfg(pp, "index"); 654 if (s == NULL) 655 continue; 656 if (atoi(s) == idx) 657 break; 658 } 659 660 if (pp != NULL) { 661 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 662 fd = open(dsf, O_WRONLY); 663 if (fd == -1) 664 err(EXIT_FAILURE, "%s", dsf); 665 if (lseek(fd, size, SEEK_SET) != size) 666 errx(EXIT_FAILURE, "%s: not enough space", dsf); 667 if (lseek(fd, 0, SEEK_SET) != 0) 668 err(EXIT_FAILURE, "%s", dsf); 669 670 /* 671 * When writing to a disk device, the write must be 672 * sector aligned and not write to any partial sectors, 673 * so round up the buffer size to the next sector and zero it. 674 */ 675 bsize = (size + pp->lg_sectorsize - 1) / 676 pp->lg_sectorsize * pp->lg_sectorsize; 677 buf = calloc(1, bsize); 678 if (buf == NULL) 679 err(EXIT_FAILURE, "%s", dsf); 680 bcopy(code, buf, size); 681 if (write(fd, buf, bsize) != bsize) 682 err(EXIT_FAILURE, "%s", dsf); 683 free(buf); 684 close(fd); 685 } else 686 errx(EXIT_FAILURE, "invalid partition index"); 687} 688 689static void 690gpart_write_partcode_vtoc8(struct ggeom *gp, int idx, void *code) 691{ 692 char dsf[128]; 693 struct gprovider *pp; 694 const char *s; 695 int installed, fd; 696 697 installed = 0; 698 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 699 s = find_provcfg(pp, "index"); 700 if (s == NULL) 701 continue; 702 if (idx != 0 && atoi(s) != idx) 703 continue; 704 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 705 if (pp->lg_sectorsize != sizeof(struct vtoc8)) 706 errx(EXIT_FAILURE, "%s: unexpected sector " 707 "size (%d)\n", dsf, pp->lg_sectorsize); 708 fd = open(dsf, O_WRONLY); 709 if (fd == -1) 710 err(EXIT_FAILURE, "%s", dsf); 711 if (lseek(fd, VTOC_BOOTSIZE, SEEK_SET) != VTOC_BOOTSIZE) 712 continue; 713 /* 714 * We ignore the first VTOC_BOOTSIZE bytes of boot code in 715 * order to avoid overwriting the label. 716 */ 717 if (lseek(fd, sizeof(struct vtoc8), SEEK_SET) != 718 sizeof(struct vtoc8)) 719 err(EXIT_FAILURE, "%s", dsf); 720 if (write(fd, (caddr_t)code + sizeof(struct vtoc8), 721 VTOC_BOOTSIZE - sizeof(struct vtoc8)) != VTOC_BOOTSIZE - 722 sizeof(struct vtoc8)) 723 err(EXIT_FAILURE, "%s", dsf); 724 installed++; 725 close(fd); 726 if (idx != 0 && atoi(s) == idx) 727 break; 728 } 729 if (installed == 0) 730 errx(EXIT_FAILURE, "%s: no partitions", gp->lg_name); 731} 732 733static void 734gpart_bootcode(struct gctl_req *req, unsigned int fl) 735{ 736 struct gmesh mesh; 737 struct gclass *classp; 738 struct ggeom *gp; 739 const char *s; 740 char *sp; 741 void *bootcode, *partcode; 742 size_t bootsize, partsize; 743 int error, idx, vtoc8; 744 745 if (gctl_has_param(req, bootcode_param)) { 746 s = gctl_get_ascii(req, bootcode_param); 747 bootsize = 800 * 1024; /* Arbitrary limit. */ 748 bootcode = gpart_bootfile_read(s, &bootsize); 749 error = gctl_change_param(req, bootcode_param, bootsize, 750 bootcode); 751 if (error) 752 errc(EXIT_FAILURE, error, "internal error"); 753 } else { 754 bootcode = NULL; 755 bootsize = 0; 756 } 757 758 s = gctl_get_ascii(req, "class"); 759 if (s == NULL) 760 abort(); 761 error = geom_gettree(&mesh); 762 if (error != 0) 763 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 764 classp = find_class(&mesh, s); 765 if (classp == NULL) { 766 geom_deletetree(&mesh); 767 errx(EXIT_FAILURE, "Class %s not found.", s); 768 } 769 s = gctl_get_ascii(req, "geom"); 770 if (s == NULL) 771 abort(); 772 gp = find_geom(classp, s); 773 if (gp == NULL) 774 errx(EXIT_FAILURE, "No such geom: %s.", s); 775 s = find_geomcfg(gp, "scheme"); 776 vtoc8 = 0; 777 if (strcmp(s, "VTOC8") == 0) 778 vtoc8 = 1; 779 780 if (gctl_has_param(req, partcode_param)) { 781 s = gctl_get_ascii(req, partcode_param); 782 partsize = vtoc8 != 0 ? VTOC_BOOTSIZE : bootsize * 1024; 783 partcode = gpart_bootfile_read(s, &partsize); 784 error = gctl_delete_param(req, partcode_param); 785 if (error) 786 errc(EXIT_FAILURE, error, "internal error"); 787 } else { 788 partcode = NULL; 789 partsize = 0; 790 } 791 792 if (gctl_has_param(req, index_param)) { 793 if (partcode == NULL) 794 errx(EXIT_FAILURE, "-i is only valid with -p"); 795 s = gctl_get_ascii(req, index_param); 796 idx = strtol(s, &sp, 10); 797 if (idx < 1 || *s == '\0' || *sp != '\0') 798 errx(EXIT_FAILURE, "invalid partition index"); 799 error = gctl_delete_param(req, index_param); 800 if (error) 801 errc(EXIT_FAILURE, error, "internal error"); 802 } else 803 idx = 0; 804 805 if (partcode != NULL) { 806 if (vtoc8 == 0) { 807 if (idx == 0) 808 errx(EXIT_FAILURE, "missing -i option"); 809 gpart_write_partcode(gp, idx, partcode, partsize); 810 } else 811 gpart_write_partcode_vtoc8(gp, idx, partcode); 812 } else 813 if (bootcode == NULL) 814 errx(EXIT_FAILURE, "no -b nor -p"); 815 816 if (bootcode != NULL) 817 gpart_issue(req, fl); 818 819 geom_deletetree(&mesh); 820} 821 822static void 823gpart_issue(struct gctl_req *req, unsigned int fl __unused) 824{ 825 char buf[4096]; 826 char *errmsg; 827 const char *errstr; 828 int error, status; 829 830 /* autofill parameters (if applicable). */ 831 error = gpart_autofill(req); 832 if (error) { 833 warnc(error, "autofill"); 834 status = EXIT_FAILURE; 835 goto done; 836 } 837 838 bzero(buf, sizeof(buf)); 839 gctl_rw_param(req, "output", sizeof(buf), buf); 840 errstr = gctl_issue(req); 841 if (errstr == NULL || errstr[0] == '\0') { 842 if (buf[0] != '\0') 843 printf("%s", buf); 844 status = EXIT_SUCCESS; 845 goto done; 846 } 847 848 error = strtol(errstr, &errmsg, 0); 849 if (errmsg != errstr) { 850 while (errmsg[0] == ' ') 851 errmsg++; 852 if (errmsg[0] != '\0') 853 warnc(error, "%s", errmsg); 854 else 855 warnc(error, NULL); 856 } else 857 warnx("%s", errmsg); 858 859 status = EXIT_FAILURE; 860 861 done: 862 gctl_free(req); 863 exit(status); 864} 865