geom_part.c revision 281303
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: stable/10/sbin/geom/class/part/geom_part.c 281303 2015-04-09 10:10:05Z mav $"); 29 30#include <sys/stat.h> 31#include <sys/vtoc.h> 32 33#include <assert.h> 34#include <ctype.h> 35#include <err.h> 36#include <errno.h> 37#include <fcntl.h> 38#include <libgeom.h> 39#include <libutil.h> 40#include <paths.h> 41#include <signal.h> 42#include <stdint.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <limits.h> 46#include <inttypes.h> 47#include <string.h> 48#include <strings.h> 49#include <unistd.h> 50 51#include "core/geom.h" 52#include "misc/subr.h" 53 54#ifdef STATIC_GEOM_CLASSES 55#define PUBSYM(x) gpart_##x 56#else 57#define PUBSYM(x) x 58#endif 59 60uint32_t PUBSYM(lib_version) = G_LIB_VERSION; 61uint32_t PUBSYM(version) = 0; 62 63static char sstart[32]; 64static char ssize[32]; 65volatile sig_atomic_t undo_restore; 66 67#define GPART_AUTOFILL "*" 68#define GPART_FLAGS "C" 69 70#define GPART_PARAM_BOOTCODE "bootcode" 71#define GPART_PARAM_INDEX "index" 72#define GPART_PARAM_PARTCODE "partcode" 73 74static struct gclass *find_class(struct gmesh *, const char *); 75static struct ggeom * find_geom(struct gclass *, const char *); 76static const char *find_geomcfg(struct ggeom *, const char *); 77static const char *find_provcfg(struct gprovider *, const char *); 78static struct gprovider *find_provider(struct ggeom *, off_t); 79static const char *fmtsize(int64_t); 80static int gpart_autofill(struct gctl_req *); 81static int gpart_autofill_resize(struct gctl_req *); 82static void gpart_bootcode(struct gctl_req *, unsigned int); 83static void *gpart_bootfile_read(const char *, ssize_t *); 84static void gpart_issue(struct gctl_req *, unsigned int); 85static void gpart_show(struct gctl_req *, unsigned int); 86static void gpart_show_geom(struct ggeom *, const char *, int); 87static int gpart_show_hasopt(struct gctl_req *, const char *, const char *); 88static void gpart_write_partcode(struct ggeom *, int, void *, ssize_t); 89static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *); 90static void gpart_print_error(const char *); 91static void gpart_backup(struct gctl_req *, unsigned int); 92static void gpart_restore(struct gctl_req *, unsigned int); 93 94struct g_command PUBSYM(class_commands)[] = { 95 { "add", 0, gpart_issue, { 96 { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, 97 { 'b', "start", GPART_AUTOFILL, G_TYPE_STRING }, 98 { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, 99 { 't', "type", NULL, G_TYPE_STRING }, 100 { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 101 { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, 102 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 103 G_OPT_SENTINEL }, 104 "-t type [-a alignment] [-b start] [-s size] [-i index] " 105 "[-l label] [-f flags] geom" 106 }, 107 { "backup", 0, gpart_backup, G_NULL_OPTS, 108 "geom" 109 }, 110 { "bootcode", 0, gpart_bootcode, { 111 { 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, 112 { 'p', GPART_PARAM_PARTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, 113 { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 114 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 115 G_OPT_SENTINEL }, 116 "[-b bootcode] [-p partcode -i index] [-f flags] geom" 117 }, 118 { "commit", 0, gpart_issue, G_NULL_OPTS, 119 "geom" 120 }, 121 { "create", 0, gpart_issue, { 122 { 's', "scheme", NULL, G_TYPE_STRING }, 123 { 'n', "entries", G_VAL_OPTIONAL, G_TYPE_NUMBER }, 124 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 125 G_OPT_SENTINEL }, 126 "-s scheme [-n entries] [-f flags] provider" 127 }, 128 { "delete", 0, gpart_issue, { 129 { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 130 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 131 G_OPT_SENTINEL }, 132 "-i index [-f flags] geom" 133 }, 134 { "destroy", 0, gpart_issue, { 135 { 'F', "force", NULL, G_TYPE_BOOL }, 136 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 137 G_OPT_SENTINEL }, 138 "[-F] [-f flags] geom" 139 }, 140 { "modify", 0, gpart_issue, { 141 { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 142 { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, 143 { 't', "type", G_VAL_OPTIONAL, G_TYPE_STRING }, 144 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 145 G_OPT_SENTINEL }, 146 "-i index [-l label] [-t type] [-f flags] geom" 147 }, 148 { "set", 0, gpart_issue, { 149 { 'a', "attrib", NULL, G_TYPE_STRING }, 150 { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 151 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 152 G_OPT_SENTINEL }, 153 "-a attrib [-i index] [-f flags] geom" 154 }, 155 { "show", 0, gpart_show, { 156 { 'l', "show_label", NULL, G_TYPE_BOOL }, 157 { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, 158 { 'p', "show_providers", NULL, G_TYPE_BOOL }, 159 G_OPT_SENTINEL }, 160 "[-l | -r] [-p] [geom ...]" 161 }, 162 { "undo", 0, gpart_issue, G_NULL_OPTS, 163 "geom" 164 }, 165 { "unset", 0, gpart_issue, { 166 { 'a', "attrib", NULL, G_TYPE_STRING }, 167 { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 168 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 169 G_OPT_SENTINEL }, 170 "-a attrib [-i index] [-f flags] geom" 171 }, 172 { "resize", 0, gpart_issue, { 173 { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, 174 { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, 175 { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 176 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 177 G_OPT_SENTINEL }, 178 "-i index [-a alignment] [-s size] [-f flags] geom" 179 }, 180 { "restore", 0, gpart_restore, { 181 { 'F', "force", NULL, G_TYPE_BOOL }, 182 { 'l', "restore_labels", NULL, G_TYPE_BOOL }, 183 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 184 G_OPT_SENTINEL }, 185 "[-lF] [-f flags] provider [...]" 186 }, 187 { "recover", 0, gpart_issue, { 188 { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 189 G_OPT_SENTINEL }, 190 "[-f flags] geom" 191 }, 192 G_CMD_SENTINEL 193}; 194 195static struct gclass * 196find_class(struct gmesh *mesh, const char *name) 197{ 198 struct gclass *classp; 199 200 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 201 if (strcmp(classp->lg_name, name) == 0) 202 return (classp); 203 } 204 return (NULL); 205} 206 207static struct ggeom * 208find_geom(struct gclass *classp, const char *name) 209{ 210 struct ggeom *gp, *wgp; 211 212 if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 213 name += sizeof(_PATH_DEV) - 1; 214 wgp = NULL; 215 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 216 if (strcmp(gp->lg_name, name) != 0) 217 continue; 218 if (find_geomcfg(gp, "wither") == NULL) 219 return (gp); 220 else 221 wgp = gp; 222 } 223 return (wgp); 224} 225 226static const char * 227find_geomcfg(struct ggeom *gp, const char *cfg) 228{ 229 struct gconfig *gc; 230 231 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 232 if (!strcmp(gc->lg_name, cfg)) 233 return (gc->lg_val); 234 } 235 return (NULL); 236} 237 238static const char * 239find_provcfg(struct gprovider *pp, const char *cfg) 240{ 241 struct gconfig *gc; 242 243 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 244 if (!strcmp(gc->lg_name, cfg)) 245 return (gc->lg_val); 246 } 247 return (NULL); 248} 249 250static struct gprovider * 251find_provider(struct ggeom *gp, off_t minsector) 252{ 253 struct gprovider *pp, *bestpp; 254 const char *s; 255 off_t sector, bestsector; 256 257 bestpp = NULL; 258 bestsector = 0; 259 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 260 s = find_provcfg(pp, "start"); 261 sector = (off_t)strtoimax(s, NULL, 0); 262 if (sector < minsector) 263 continue; 264 if (bestpp != NULL && sector >= bestsector) 265 continue; 266 267 bestpp = pp; 268 bestsector = sector; 269 } 270 return (bestpp); 271} 272 273static const char * 274fmtsize(int64_t rawsz) 275{ 276 static char buf[5]; 277 278 humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, 279 HN_B | HN_NOSPACE | HN_DECIMAL); 280 return (buf); 281} 282 283static const char * 284fmtattrib(struct gprovider *pp) 285{ 286 static char buf[128]; 287 struct gconfig *gc; 288 u_int idx; 289 290 buf[0] = '\0'; 291 idx = 0; 292 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 293 if (strcmp(gc->lg_name, "attrib") != 0) 294 continue; 295 idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", 296 (idx == 0) ? " [" : ",", gc->lg_val); 297 } 298 if (idx > 0) 299 snprintf(buf + idx, sizeof(buf) - idx, "] "); 300 return (buf); 301} 302 303#define ALIGNDOWN(d, a) ((d) - (d) % (a)) 304#define ALIGNUP(d, a) ((d) % (a) ? (d) - (d) % (a) + (a): (d)) 305 306static int 307gpart_autofill_resize(struct gctl_req *req) 308{ 309 struct gmesh mesh; 310 struct gclass *cp; 311 struct ggeom *gp; 312 struct gprovider *pp; 313 off_t last, size, start, new_size; 314 off_t lba, new_lba, alignment, offset; 315 const char *s; 316 int error, idx, has_alignment; 317 318 idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 319 if (idx < 1) 320 errx(EXIT_FAILURE, "invalid partition index"); 321 322 error = geom_gettree(&mesh); 323 if (error) 324 return (error); 325 s = gctl_get_ascii(req, "class"); 326 if (s == NULL) 327 abort(); 328 cp = find_class(&mesh, s); 329 if (cp == NULL) 330 errx(EXIT_FAILURE, "Class %s not found.", s); 331 s = gctl_get_ascii(req, "arg0"); 332 if (s == NULL) 333 abort(); 334 gp = find_geom(cp, s); 335 if (gp == NULL) 336 errx(EXIT_FAILURE, "No such geom: %s.", s); 337 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 338 if (pp == NULL) 339 errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 340 341 s = gctl_get_ascii(req, "alignment"); 342 has_alignment = (*s == '*') ? 0 : 1; 343 alignment = 1; 344 if (has_alignment) { 345 error = g_parse_lba(s, pp->lg_sectorsize, &alignment); 346 if (error) 347 errc(EXIT_FAILURE, error, "Invalid alignment param"); 348 if (alignment == 0) 349 errx(EXIT_FAILURE, "Invalid alignment param"); 350 } else { 351 lba = pp->lg_stripesize / pp->lg_sectorsize; 352 if (lba > 0) 353 alignment = lba; 354 } 355 error = gctl_delete_param(req, "alignment"); 356 if (error) 357 errc(EXIT_FAILURE, error, "internal error"); 358 359 s = gctl_get_ascii(req, "size"); 360 if (*s == '*') 361 new_size = 0; 362 else { 363 error = g_parse_lba(s, pp->lg_sectorsize, &new_size); 364 if (error) 365 errc(EXIT_FAILURE, error, "Invalid size param"); 366 /* no autofill necessary. */ 367 if (has_alignment == 0) 368 goto done; 369 } 370 371 offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; 372 s = find_geomcfg(gp, "last"); 373 if (s == NULL) 374 errx(EXIT_FAILURE, "Final block not found for geom %s", 375 gp->lg_name); 376 last = (off_t)strtoimax(s, NULL, 0); 377 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 378 s = find_provcfg(pp, "index"); 379 if (s == NULL) 380 continue; 381 if (atoi(s) == idx) 382 break; 383 } 384 if (pp == NULL) 385 errx(EXIT_FAILURE, "invalid partition index"); 386 387 s = find_provcfg(pp, "start"); 388 start = (off_t)strtoimax(s, NULL, 0); 389 s = find_provcfg(pp, "end"); 390 lba = (off_t)strtoimax(s, NULL, 0); 391 size = lba - start + 1; 392 393 pp = find_provider(gp, lba + 1); 394 if (new_size > 0 && (new_size <= size || pp == NULL)) { 395 /* The start offset may be not aligned, so we align the end 396 * offset and then calculate the size. 397 */ 398 new_size = ALIGNDOWN(start + offset + new_size, 399 alignment) - start - offset; 400 goto done; 401 } 402 if (pp == NULL) { 403 new_size = ALIGNDOWN(last + offset + 1, alignment) - 404 start - offset; 405 if (new_size < size) 406 return (ENOSPC); 407 } else { 408 s = find_provcfg(pp, "start"); 409 new_lba = (off_t)strtoimax(s, NULL, 0); 410 /* 411 * Is there any free space between current and 412 * next providers? 413 */ 414 new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset; 415 if (new_lba > lba) 416 new_size = new_lba - start; 417 else { 418 geom_deletetree(&mesh); 419 return (ENOSPC); 420 } 421 } 422done: 423 snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size); 424 gctl_change_param(req, "size", -1, ssize); 425 geom_deletetree(&mesh); 426 return (0); 427} 428 429static int 430gpart_autofill(struct gctl_req *req) 431{ 432 struct gmesh mesh; 433 struct gclass *cp; 434 struct ggeom *gp; 435 struct gprovider *pp; 436 off_t first, last, a_first; 437 off_t size, start, a_lba; 438 off_t lba, len, alignment, offset; 439 uintmax_t grade; 440 const char *s; 441 int error, has_size, has_start, has_alignment; 442 443 s = gctl_get_ascii(req, "verb"); 444 if (strcmp(s, "resize") == 0) 445 return gpart_autofill_resize(req); 446 if (strcmp(s, "add") != 0) 447 return (0); 448 449 error = geom_gettree(&mesh); 450 if (error) 451 return (error); 452 s = gctl_get_ascii(req, "class"); 453 if (s == NULL) 454 abort(); 455 cp = find_class(&mesh, s); 456 if (cp == NULL) 457 errx(EXIT_FAILURE, "Class %s not found.", s); 458 s = gctl_get_ascii(req, "arg0"); 459 if (s == NULL) 460 abort(); 461 gp = find_geom(cp, s); 462 if (gp == NULL) 463 errx(EXIT_FAILURE, "No such geom: %s.", s); 464 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 465 if (pp == NULL) 466 errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 467 468 s = gctl_get_ascii(req, "alignment"); 469 has_alignment = (*s == '*') ? 0 : 1; 470 alignment = 1; 471 if (has_alignment) { 472 error = g_parse_lba(s, pp->lg_sectorsize, &alignment); 473 if (error) 474 errc(EXIT_FAILURE, error, "Invalid alignment param"); 475 if (alignment == 0) 476 errx(EXIT_FAILURE, "Invalid alignment param"); 477 } 478 error = gctl_delete_param(req, "alignment"); 479 if (error) 480 errc(EXIT_FAILURE, error, "internal error"); 481 482 s = gctl_get_ascii(req, "size"); 483 has_size = (*s == '*') ? 0 : 1; 484 size = 0; 485 if (has_size) { 486 error = g_parse_lba(s, pp->lg_sectorsize, &size); 487 if (error) 488 errc(EXIT_FAILURE, error, "Invalid size param"); 489 } 490 491 s = gctl_get_ascii(req, "start"); 492 has_start = (*s == '*') ? 0 : 1; 493 start = 0ULL; 494 if (has_start) { 495 error = g_parse_lba(s, pp->lg_sectorsize, &start); 496 if (error) 497 errc(EXIT_FAILURE, error, "Invalid start param"); 498 } 499 500 /* No autofill necessary. */ 501 if (has_size && has_start && !has_alignment) 502 goto done; 503 504 len = pp->lg_stripesize / pp->lg_sectorsize; 505 if (len > 0 && !has_alignment) 506 alignment = len; 507 508 /* Adjust parameters to stripeoffset */ 509 offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; 510 start = ALIGNUP(start + offset, alignment); 511 if (size > alignment) 512 size = ALIGNDOWN(size, alignment); 513 514 s = find_geomcfg(gp, "first"); 515 if (s == NULL) 516 errx(EXIT_FAILURE, "Starting block not found for geom %s", 517 gp->lg_name); 518 first = (off_t)strtoimax(s, NULL, 0); 519 s = find_geomcfg(gp, "last"); 520 if (s == NULL) 521 errx(EXIT_FAILURE, "Final block not found for geom %s", 522 gp->lg_name); 523 last = (off_t)strtoimax(s, NULL, 0); 524 grade = ~0ULL; 525 a_first = ALIGNUP(first + offset, alignment); 526 last = ALIGNDOWN(last + offset, alignment); 527 if (a_first < start) 528 a_first = start; 529 while ((pp = find_provider(gp, first)) != NULL) { 530 s = find_provcfg(pp, "start"); 531 lba = (off_t)strtoimax(s, NULL, 0); 532 a_lba = ALIGNDOWN(lba + offset, alignment); 533 if (first < a_lba && a_first < a_lba) { 534 /* Free space [first, lba> */ 535 len = a_lba - a_first; 536 if (has_size) { 537 if (len >= size && 538 (uintmax_t)(len - size) < grade) { 539 start = a_first; 540 grade = len - size; 541 } 542 } else if (has_start) { 543 if (start >= a_first && start < a_lba) { 544 size = a_lba - start; 545 grade = start - a_first; 546 } 547 } else { 548 if (grade == ~0ULL || len > size) { 549 start = a_first; 550 size = len; 551 grade = 0; 552 } 553 } 554 } 555 556 s = find_provcfg(pp, "end"); 557 first = (off_t)strtoimax(s, NULL, 0) + 1; 558 if (first + offset > a_first) 559 a_first = ALIGNUP(first + offset, alignment); 560 } 561 if (a_first <= last) { 562 /* Free space [first-last] */ 563 len = ALIGNDOWN(last - a_first + 1, alignment); 564 if (has_size) { 565 if (len >= size && 566 (uintmax_t)(len - size) < grade) { 567 start = a_first; 568 grade = len - size; 569 } 570 } else if (has_start) { 571 if (start >= a_first && start <= last) { 572 size = ALIGNDOWN(last - start + 1, alignment); 573 grade = start - a_first; 574 } 575 } else { 576 if (grade == ~0ULL || len > size) { 577 start = a_first; 578 size = len; 579 grade = 0; 580 } 581 } 582 } 583 if (grade == ~0ULL) { 584 geom_deletetree(&mesh); 585 return (ENOSPC); 586 } 587 start -= offset; /* Return back to real offset */ 588done: 589 snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size); 590 gctl_change_param(req, "size", -1, ssize); 591 snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start); 592 gctl_change_param(req, "start", -1, sstart); 593 geom_deletetree(&mesh); 594 return (0); 595} 596 597static void 598gpart_show_geom(struct ggeom *gp, const char *element, int show_providers) 599{ 600 struct gprovider *pp; 601 const char *s, *scheme; 602 off_t first, last, sector, end; 603 off_t length, secsz; 604 int idx, wblocks, wname, wmax; 605 606 if (find_geomcfg(gp, "wither")) 607 return; 608 scheme = find_geomcfg(gp, "scheme"); 609 if (scheme == NULL) 610 errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); 611 s = find_geomcfg(gp, "first"); 612 if (s == NULL) 613 errx(EXIT_FAILURE, "Starting block not found for geom %s", 614 gp->lg_name); 615 first = (off_t)strtoimax(s, NULL, 0); 616 s = find_geomcfg(gp, "last"); 617 if (s == NULL) 618 errx(EXIT_FAILURE, "Final block not found for geom %s", 619 gp->lg_name); 620 last = (off_t)strtoimax(s, NULL, 0); 621 wblocks = strlen(s); 622 s = find_geomcfg(gp, "state"); 623 if (s == NULL) 624 errx(EXIT_FAILURE, "State not found for geom %s", gp->lg_name); 625 if (s != NULL && *s != 'C') 626 s = NULL; 627 wmax = strlen(gp->lg_name); 628 if (show_providers) { 629 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 630 wname = strlen(pp->lg_name); 631 if (wname > wmax) 632 wmax = wname; 633 } 634 } 635 wname = wmax; 636 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 637 secsz = pp->lg_sectorsize; 638 printf("=>%*jd %*jd %*s %s (%s)%s\n", 639 wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1), 640 wname, gp->lg_name, 641 scheme, fmtsize(pp->lg_mediasize), 642 s ? " [CORRUPT]": ""); 643 644 while ((pp = find_provider(gp, first)) != NULL) { 645 s = find_provcfg(pp, "start"); 646 sector = (off_t)strtoimax(s, NULL, 0); 647 648 s = find_provcfg(pp, "end"); 649 end = (off_t)strtoimax(s, NULL, 0); 650 length = end - sector + 1; 651 652 s = find_provcfg(pp, "index"); 653 idx = atoi(s); 654 if (first < sector) { 655 printf(" %*jd %*jd %*s - free - (%s)\n", 656 wblocks, (intmax_t)first, wblocks, 657 (intmax_t)(sector - first), wname, "", 658 fmtsize((sector - first) * secsz)); 659 } 660 if (show_providers) { 661 printf(" %*jd %*jd %*s %s %s (%s)\n", 662 wblocks, (intmax_t)sector, wblocks, 663 (intmax_t)length, wname, pp->lg_name, 664 find_provcfg(pp, element), fmtattrib(pp), 665 fmtsize(pp->lg_mediasize)); 666 } else 667 printf(" %*jd %*jd %*d %s %s (%s)\n", 668 wblocks, (intmax_t)sector, wblocks, 669 (intmax_t)length, wname, idx, 670 find_provcfg(pp, element), fmtattrib(pp), 671 fmtsize(pp->lg_mediasize)); 672 first = end + 1; 673 } 674 if (first <= last) { 675 length = last - first + 1; 676 printf(" %*jd %*jd %*s - free - (%s)\n", 677 wblocks, (intmax_t)first, wblocks, (intmax_t)length, 678 wname, "", 679 fmtsize(length * secsz)); 680 } 681 printf("\n"); 682} 683 684static int 685gpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 686{ 687 688 if (!gctl_get_int(req, "%s", opt)) 689 return (0); 690 691 if (elt != NULL) 692 errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 693 694 return (1); 695} 696 697static void 698gpart_show(struct gctl_req *req, unsigned int fl __unused) 699{ 700 struct gmesh mesh; 701 struct gclass *classp; 702 struct ggeom *gp; 703 const char *element, *name; 704 int error, i, nargs, show_providers; 705 706 element = NULL; 707 if (gpart_show_hasopt(req, "show_label", element)) 708 element = "label"; 709 if (gpart_show_hasopt(req, "show_rawtype", element)) 710 element = "rawtype"; 711 if (element == NULL) 712 element = "type"; 713 714 name = gctl_get_ascii(req, "class"); 715 if (name == NULL) 716 abort(); 717 error = geom_gettree(&mesh); 718 if (error != 0) 719 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 720 classp = find_class(&mesh, name); 721 if (classp == NULL) { 722 geom_deletetree(&mesh); 723 errx(EXIT_FAILURE, "Class %s not found.", name); 724 } 725 show_providers = gctl_get_int(req, "show_providers"); 726 nargs = gctl_get_int(req, "nargs"); 727 if (nargs > 0) { 728 for (i = 0; i < nargs; i++) { 729 name = gctl_get_ascii(req, "arg%d", i); 730 gp = find_geom(classp, name); 731 if (gp != NULL) 732 gpart_show_geom(gp, element, show_providers); 733 else 734 errx(EXIT_FAILURE, "No such geom: %s.", name); 735 } 736 } else { 737 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 738 gpart_show_geom(gp, element, show_providers); 739 } 740 } 741 geom_deletetree(&mesh); 742} 743 744static void 745gpart_backup(struct gctl_req *req, unsigned int fl __unused) 746{ 747 struct gmesh mesh; 748 struct gclass *classp; 749 struct gprovider *pp; 750 struct ggeom *gp; 751 const char *s, *scheme; 752 off_t sector, end; 753 off_t length; 754 int error, i, windex, wblocks, wtype; 755 756 if (gctl_get_int(req, "nargs") != 1) 757 errx(EXIT_FAILURE, "Invalid number of arguments."); 758 error = geom_gettree(&mesh); 759 if (error != 0) 760 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 761 s = gctl_get_ascii(req, "class"); 762 if (s == NULL) 763 abort(); 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, "arg0"); 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 scheme = find_geomcfg(gp, "scheme"); 776 if (scheme == NULL) 777 abort(); 778 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 779 s = find_geomcfg(gp, "last"); 780 if (s == NULL) 781 abort(); 782 wblocks = strlen(s); 783 wtype = 0; 784 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 785 s = find_provcfg(pp, "type"); 786 i = strlen(s); 787 if (i > wtype) 788 wtype = i; 789 } 790 s = find_geomcfg(gp, "entries"); 791 if (s == NULL) 792 abort(); 793 windex = strlen(s); 794 printf("%s %s\n", scheme, s); 795 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 796 s = find_provcfg(pp, "start"); 797 sector = (off_t)strtoimax(s, NULL, 0); 798 799 s = find_provcfg(pp, "end"); 800 end = (off_t)strtoimax(s, NULL, 0); 801 length = end - sector + 1; 802 803 s = find_provcfg(pp, "label"); 804 printf("%-*s %*s %*jd %*jd %s %s\n", 805 windex, find_provcfg(pp, "index"), 806 wtype, find_provcfg(pp, "type"), 807 wblocks, (intmax_t)sector, 808 wblocks, (intmax_t)length, 809 (s != NULL) ? s: "", fmtattrib(pp)); 810 } 811 geom_deletetree(&mesh); 812} 813 814static int 815skip_line(const char *p) 816{ 817 818 while (*p != '\0') { 819 if (*p == '#') 820 return (1); 821 if (isspace(*p) == 0) 822 return (0); 823 p++; 824 } 825 return (1); 826} 827 828static void 829gpart_sighndl(int sig __unused) 830{ 831 undo_restore = 1; 832} 833 834static void 835gpart_restore(struct gctl_req *req, unsigned int fl __unused) 836{ 837 struct gmesh mesh; 838 struct gclass *classp; 839 struct gctl_req *r; 840 struct ggeom *gp; 841 struct sigaction si_sa; 842 const char *s, *flags, *errstr, *label; 843 char **ap, *argv[6], line[BUFSIZ], *pline; 844 int error, forced, i, l, nargs, created, rl; 845 intmax_t n; 846 847 nargs = gctl_get_int(req, "nargs"); 848 if (nargs < 1) 849 errx(EXIT_FAILURE, "Invalid number of arguments."); 850 851 forced = gctl_get_int(req, "force"); 852 flags = gctl_get_ascii(req, "flags"); 853 rl = gctl_get_int(req, "restore_labels"); 854 s = gctl_get_ascii(req, "class"); 855 if (s == NULL) 856 abort(); 857 error = geom_gettree(&mesh); 858 if (error != 0) 859 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 860 classp = find_class(&mesh, s); 861 if (classp == NULL) { 862 geom_deletetree(&mesh); 863 errx(EXIT_FAILURE, "Class %s not found.", s); 864 } 865 866 sigemptyset(&si_sa.sa_mask); 867 si_sa.sa_flags = 0; 868 si_sa.sa_handler = gpart_sighndl; 869 if (sigaction(SIGINT, &si_sa, 0) == -1) 870 err(EXIT_FAILURE, "sigaction SIGINT"); 871 872 if (forced) { 873 /* destroy existent partition table before restore */ 874 for (i = 0; i < nargs; i++) { 875 s = gctl_get_ascii(req, "arg%d", i); 876 gp = find_geom(classp, s); 877 if (gp != NULL) { 878 r = gctl_get_handle(); 879 gctl_ro_param(r, "class", -1, 880 classp->lg_name); 881 gctl_ro_param(r, "verb", -1, "destroy"); 882 gctl_ro_param(r, "flags", -1, "restore"); 883 gctl_ro_param(r, "force", sizeof(forced), 884 &forced); 885 gctl_ro_param(r, "arg0", -1, s); 886 errstr = gctl_issue(r); 887 if (errstr != NULL && errstr[0] != '\0') { 888 gpart_print_error(errstr); 889 gctl_free(r); 890 goto backout; 891 } 892 gctl_free(r); 893 } 894 } 895 } 896 created = 0; 897 while (undo_restore == 0 && 898 fgets(line, sizeof(line) - 1, stdin) != NULL) { 899 /* Format of backup entries: 900 * <scheme name> <number of entries> 901 * <index> <type> <start> <size> [label] ['['attrib[,attrib]']'] 902 */ 903 pline = (char *)line; 904 pline[strlen(line) - 1] = 0; 905 if (skip_line(pline)) 906 continue; 907 for (ap = argv; 908 (*ap = strsep(&pline, " \t")) != NULL;) 909 if (**ap != '\0' && ++ap >= &argv[6]) 910 break; 911 l = ap - &argv[0]; 912 label = pline = NULL; 913 if (l == 1 || l == 2) { /* create table */ 914 if (created) 915 errx(EXIT_FAILURE, "Incorrect backup format."); 916 if (l == 2) 917 n = strtoimax(argv[1], NULL, 0); 918 for (i = 0; i < nargs; i++) { 919 s = gctl_get_ascii(req, "arg%d", i); 920 r = gctl_get_handle(); 921 gctl_ro_param(r, "class", -1, 922 classp->lg_name); 923 gctl_ro_param(r, "verb", -1, "create"); 924 gctl_ro_param(r, "scheme", -1, argv[0]); 925 if (l == 2) 926 gctl_ro_param(r, "entries", 927 sizeof(n), &n); 928 gctl_ro_param(r, "flags", -1, "restore"); 929 gctl_ro_param(r, "arg0", -1, s); 930 errstr = gctl_issue(r); 931 if (errstr != NULL && errstr[0] != '\0') { 932 gpart_print_error(errstr); 933 gctl_free(r); 934 goto backout; 935 } 936 gctl_free(r); 937 } 938 created = 1; 939 continue; 940 } else if (l < 4 || created == 0) 941 errx(EXIT_FAILURE, "Incorrect backup format."); 942 else if (l == 5) { 943 if (strchr(argv[4], '[') == NULL) 944 label = argv[4]; 945 else 946 pline = argv[4]; 947 } else if (l == 6) { 948 label = argv[4]; 949 pline = argv[5]; 950 } 951 /* Add partitions to each table */ 952 for (i = 0; i < nargs; i++) { 953 s = gctl_get_ascii(req, "arg%d", i); 954 r = gctl_get_handle(); 955 n = strtoimax(argv[0], NULL, 0); 956 gctl_ro_param(r, "class", -1, classp->lg_name); 957 gctl_ro_param(r, "verb", -1, "add"); 958 gctl_ro_param(r, "flags", -1, "restore"); 959 gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n); 960 gctl_ro_param(r, "type", -1, argv[1]); 961 gctl_ro_param(r, "start", -1, argv[2]); 962 gctl_ro_param(r, "size", -1, argv[3]); 963 if (rl != 0 && label != NULL) 964 gctl_ro_param(r, "label", -1, argv[4]); 965 gctl_ro_param(r, "alignment", -1, GPART_AUTOFILL); 966 gctl_ro_param(r, "arg0", -1, s); 967 error = gpart_autofill(r); 968 if (error != 0) 969 errc(EXIT_FAILURE, error, "autofill"); 970 errstr = gctl_issue(r); 971 if (errstr != NULL && errstr[0] != '\0') { 972 gpart_print_error(errstr); 973 gctl_free(r); 974 goto backout; 975 } 976 gctl_free(r); 977 } 978 if (pline == NULL || *pline != '[') 979 continue; 980 /* set attributes */ 981 pline++; 982 for (ap = argv; 983 (*ap = strsep(&pline, ",]")) != NULL;) 984 if (**ap != '\0' && ++ap >= &argv[6]) 985 break; 986 for (i = 0; i < nargs; i++) { 987 l = ap - &argv[0]; 988 s = gctl_get_ascii(req, "arg%d", i); 989 while (l > 0) { 990 r = gctl_get_handle(); 991 gctl_ro_param(r, "class", -1, classp->lg_name); 992 gctl_ro_param(r, "verb", -1, "set"); 993 gctl_ro_param(r, "flags", -1, "restore"); 994 gctl_ro_param(r, GPART_PARAM_INDEX, 995 sizeof(n), &n); 996 gctl_ro_param(r, "attrib", -1, argv[--l]); 997 gctl_ro_param(r, "arg0", -1, s); 998 errstr = gctl_issue(r); 999 if (errstr != NULL && errstr[0] != '\0') { 1000 gpart_print_error(errstr); 1001 gctl_free(r); 1002 goto backout; 1003 } 1004 gctl_free(r); 1005 } 1006 } 1007 } 1008 if (undo_restore) 1009 goto backout; 1010 /* commit changes if needed */ 1011 if (strchr(flags, 'C') != NULL) { 1012 for (i = 0; i < nargs; i++) { 1013 s = gctl_get_ascii(req, "arg%d", i); 1014 r = gctl_get_handle(); 1015 gctl_ro_param(r, "class", -1, classp->lg_name); 1016 gctl_ro_param(r, "verb", -1, "commit"); 1017 gctl_ro_param(r, "arg0", -1, s); 1018 errstr = gctl_issue(r); 1019 if (errstr != NULL && errstr[0] != '\0') { 1020 gpart_print_error(errstr); 1021 gctl_free(r); 1022 goto backout; 1023 } 1024 gctl_free(r); 1025 } 1026 } 1027 gctl_free(req); 1028 geom_deletetree(&mesh); 1029 exit(EXIT_SUCCESS); 1030 1031backout: 1032 for (i = 0; i < nargs; i++) { 1033 s = gctl_get_ascii(req, "arg%d", i); 1034 r = gctl_get_handle(); 1035 gctl_ro_param(r, "class", -1, classp->lg_name); 1036 gctl_ro_param(r, "verb", -1, "undo"); 1037 gctl_ro_param(r, "arg0", -1, s); 1038 gctl_issue(r); 1039 gctl_free(r); 1040 } 1041 gctl_free(req); 1042 geom_deletetree(&mesh); 1043 exit(EXIT_FAILURE); 1044} 1045 1046static void * 1047gpart_bootfile_read(const char *bootfile, ssize_t *size) 1048{ 1049 struct stat sb; 1050 void *code; 1051 int fd; 1052 1053 if (stat(bootfile, &sb) == -1) 1054 err(EXIT_FAILURE, "%s", bootfile); 1055 if (!S_ISREG(sb.st_mode)) 1056 errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 1057 if (sb.st_size == 0) 1058 errx(EXIT_FAILURE, "%s: empty file", bootfile); 1059 if (*size > 0 && sb.st_size > *size) 1060 errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 1061 *size); 1062 1063 *size = sb.st_size; 1064 1065 fd = open(bootfile, O_RDONLY); 1066 if (fd == -1) 1067 err(EXIT_FAILURE, "%s", bootfile); 1068 code = malloc(*size); 1069 if (code == NULL) 1070 err(EXIT_FAILURE, NULL); 1071 if (read(fd, code, *size) != *size) 1072 err(EXIT_FAILURE, "%s", bootfile); 1073 close(fd); 1074 1075 return (code); 1076} 1077 1078static void 1079gpart_write_partcode(struct ggeom *gp, int idx, void *code, ssize_t size) 1080{ 1081 char dsf[128]; 1082 struct gprovider *pp; 1083 const char *s; 1084 char *buf; 1085 off_t bsize; 1086 int fd; 1087 1088 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1089 s = find_provcfg(pp, "index"); 1090 if (s == NULL) 1091 continue; 1092 if (atoi(s) == idx) 1093 break; 1094 } 1095 1096 if (pp != NULL) { 1097 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1098 fd = open(dsf, O_WRONLY); 1099 if (fd == -1) 1100 err(EXIT_FAILURE, "%s", dsf); 1101 if (lseek(fd, size, SEEK_SET) != size) 1102 errx(EXIT_FAILURE, "%s: not enough space", dsf); 1103 if (lseek(fd, 0, SEEK_SET) != 0) 1104 err(EXIT_FAILURE, "%s", dsf); 1105 1106 /* 1107 * When writing to a disk device, the write must be 1108 * sector aligned and not write to any partial sectors, 1109 * so round up the buffer size to the next sector and zero it. 1110 */ 1111 bsize = (size + pp->lg_sectorsize - 1) / 1112 pp->lg_sectorsize * pp->lg_sectorsize; 1113 buf = calloc(1, bsize); 1114 if (buf == NULL) 1115 err(EXIT_FAILURE, "%s", dsf); 1116 bcopy(code, buf, size); 1117 if (write(fd, buf, bsize) != bsize) 1118 err(EXIT_FAILURE, "%s", dsf); 1119 free(buf); 1120 close(fd); 1121 } else 1122 errx(EXIT_FAILURE, "invalid partition index"); 1123} 1124 1125static void 1126gpart_write_partcode_vtoc8(struct ggeom *gp, int idx, void *code) 1127{ 1128 char dsf[128]; 1129 struct gprovider *pp; 1130 const char *s; 1131 int installed, fd; 1132 1133 installed = 0; 1134 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1135 s = find_provcfg(pp, "index"); 1136 if (s == NULL) 1137 continue; 1138 if (idx != 0 && atoi(s) != idx) 1139 continue; 1140 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1141 if (pp->lg_sectorsize != sizeof(struct vtoc8)) 1142 errx(EXIT_FAILURE, "%s: unexpected sector " 1143 "size (%d)\n", dsf, pp->lg_sectorsize); 1144 fd = open(dsf, O_WRONLY); 1145 if (fd == -1) 1146 err(EXIT_FAILURE, "%s", dsf); 1147 if (lseek(fd, VTOC_BOOTSIZE, SEEK_SET) != VTOC_BOOTSIZE) 1148 continue; 1149 /* 1150 * We ignore the first VTOC_BOOTSIZE bytes of boot code in 1151 * order to avoid overwriting the label. 1152 */ 1153 if (lseek(fd, sizeof(struct vtoc8), SEEK_SET) != 1154 sizeof(struct vtoc8)) 1155 err(EXIT_FAILURE, "%s", dsf); 1156 if (write(fd, (caddr_t)code + sizeof(struct vtoc8), 1157 VTOC_BOOTSIZE - sizeof(struct vtoc8)) != VTOC_BOOTSIZE - 1158 sizeof(struct vtoc8)) 1159 err(EXIT_FAILURE, "%s", dsf); 1160 installed++; 1161 close(fd); 1162 if (idx != 0 && atoi(s) == idx) 1163 break; 1164 } 1165 if (installed == 0) 1166 errx(EXIT_FAILURE, "%s: no partitions", gp->lg_name); 1167} 1168 1169static void 1170gpart_bootcode(struct gctl_req *req, unsigned int fl) 1171{ 1172 struct gmesh mesh; 1173 struct gclass *classp; 1174 struct ggeom *gp; 1175 const char *s; 1176 void *bootcode, *partcode; 1177 size_t bootsize, partsize; 1178 int error, idx, vtoc8; 1179 1180 if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) { 1181 s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE); 1182 bootsize = 800 * 1024; /* Arbitrary limit. */ 1183 bootcode = gpart_bootfile_read(s, &bootsize); 1184 error = gctl_change_param(req, GPART_PARAM_BOOTCODE, bootsize, 1185 bootcode); 1186 if (error) 1187 errc(EXIT_FAILURE, error, "internal error"); 1188 } else { 1189 bootcode = NULL; 1190 bootsize = 0; 1191 } 1192 1193 s = gctl_get_ascii(req, "class"); 1194 if (s == NULL) 1195 abort(); 1196 error = geom_gettree(&mesh); 1197 if (error != 0) 1198 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 1199 classp = find_class(&mesh, s); 1200 if (classp == NULL) { 1201 geom_deletetree(&mesh); 1202 errx(EXIT_FAILURE, "Class %s not found.", s); 1203 } 1204 if (gctl_get_int(req, "nargs") != 1) 1205 errx(EXIT_FAILURE, "Invalid number of arguments."); 1206 s = gctl_get_ascii(req, "arg0"); 1207 if (s == NULL) 1208 abort(); 1209 gp = find_geom(classp, s); 1210 if (gp == NULL) 1211 errx(EXIT_FAILURE, "No such geom: %s.", s); 1212 s = find_geomcfg(gp, "scheme"); 1213 if (s == NULL) 1214 errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); 1215 vtoc8 = 0; 1216 if (strcmp(s, "VTOC8") == 0) 1217 vtoc8 = 1; 1218 1219 if (gctl_has_param(req, GPART_PARAM_PARTCODE)) { 1220 s = gctl_get_ascii(req, GPART_PARAM_PARTCODE); 1221 partsize = vtoc8 != 0 ? VTOC_BOOTSIZE : bootsize * 1024; 1222 partcode = gpart_bootfile_read(s, &partsize); 1223 error = gctl_delete_param(req, GPART_PARAM_PARTCODE); 1224 if (error) 1225 errc(EXIT_FAILURE, error, "internal error"); 1226 } else { 1227 partcode = NULL; 1228 partsize = 0; 1229 } 1230 1231 if (gctl_has_param(req, GPART_PARAM_INDEX)) { 1232 if (partcode == NULL) 1233 errx(EXIT_FAILURE, "-i is only valid with -p"); 1234 idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 1235 if (idx < 1) 1236 errx(EXIT_FAILURE, "invalid partition index"); 1237 error = gctl_delete_param(req, GPART_PARAM_INDEX); 1238 if (error) 1239 errc(EXIT_FAILURE, error, "internal error"); 1240 } else 1241 idx = 0; 1242 1243 if (partcode != NULL) { 1244 if (vtoc8 == 0) { 1245 if (idx == 0) 1246 errx(EXIT_FAILURE, "missing -i option"); 1247 gpart_write_partcode(gp, idx, partcode, partsize); 1248 } else { 1249 if (partsize != VTOC_BOOTSIZE) 1250 errx(EXIT_FAILURE, "invalid bootcode"); 1251 gpart_write_partcode_vtoc8(gp, idx, partcode); 1252 } 1253 } else 1254 if (bootcode == NULL) 1255 errx(EXIT_FAILURE, "no -b nor -p"); 1256 1257 if (bootcode != NULL) 1258 gpart_issue(req, fl); 1259 1260 geom_deletetree(&mesh); 1261} 1262 1263static void 1264gpart_print_error(const char *errstr) 1265{ 1266 char *errmsg; 1267 int error; 1268 1269 error = strtol(errstr, &errmsg, 0); 1270 if (errmsg != errstr) { 1271 while (errmsg[0] == ' ') 1272 errmsg++; 1273 if (errmsg[0] != '\0') 1274 warnc(error, "%s", errmsg); 1275 else 1276 warnc(error, NULL); 1277 } else 1278 warnx("%s", errmsg); 1279} 1280 1281static void 1282gpart_issue(struct gctl_req *req, unsigned int fl __unused) 1283{ 1284 char buf[4096]; 1285 const char *errstr; 1286 int error, status; 1287 1288 if (gctl_get_int(req, "nargs") != 1) 1289 errx(EXIT_FAILURE, "Invalid number of arguments."); 1290 (void)gctl_delete_param(req, "nargs"); 1291 1292 /* autofill parameters (if applicable). */ 1293 error = gpart_autofill(req); 1294 if (error) { 1295 warnc(error, "autofill"); 1296 status = EXIT_FAILURE; 1297 goto done; 1298 } 1299 1300 bzero(buf, sizeof(buf)); 1301 gctl_rw_param(req, "output", sizeof(buf), buf); 1302 errstr = gctl_issue(req); 1303 if (errstr == NULL || errstr[0] == '\0') { 1304 if (buf[0] != '\0') 1305 printf("%s", buf); 1306 status = EXIT_SUCCESS; 1307 goto done; 1308 } 1309 1310 gpart_print_error(errstr); 1311 status = EXIT_FAILURE; 1312 1313 done: 1314 gctl_free(req); 1315 exit(status); 1316} 1317