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