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