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