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