geom_part.c revision 215671
11541Srgrimes/*- 21541Srgrimes * Copyright (c) 2007, 2008 Marcel Moolenaar 31541Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 151541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 181541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241541Srgrimes * SUCH DAMAGE. 251541Srgrimes */ 261541Srgrimes 271541Srgrimes#include <sys/cdefs.h> 281541Srgrimes__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 215671 2010-11-22 10:08:33Z ae $"); 291541Srgrimes 301541Srgrimes#include <sys/stat.h> 311541Srgrimes#include <sys/vtoc.h> 321541Srgrimes 331541Srgrimes#include <assert.h> 342165Spaul#include <ctype.h> 351541Srgrimes#include <err.h> 361541Srgrimes#include <errno.h> 372165Spaul#include <fcntl.h> 382165Spaul#include <libgeom.h> 392165Spaul#include <libutil.h> 401541Srgrimes#include <paths.h> 411541Srgrimes#include <stdint.h> 421541Srgrimes#include <stdio.h> 431541Srgrimes#include <stdlib.h> 441541Srgrimes#include <limits.h> 451541Srgrimes#include <inttypes.h> 461541Srgrimes#include <string.h> 471541Srgrimes#include <strings.h> 481541Srgrimes#include <unistd.h> 491541Srgrimes 501541Srgrimes#include "core/geom.h" 511541Srgrimes#include "misc/subr.h" 521541Srgrimes 531541Srgrimes#ifdef STATIC_GEOM_CLASSES 541541Srgrimes#define PUBSYM(x) gpart_##x 551541Srgrimes#else 561541Srgrimes#define PUBSYM(x) x 571541Srgrimes#endif 581541Srgrimes 591541Srgrimesuint32_t PUBSYM(lib_version) = G_LIB_VERSION; 601541Srgrimesuint32_t PUBSYM(version) = 0; 611541Srgrimes 621541Srgrimesstatic char sstart[32]; 631541Srgrimesstatic char ssize[32]; 641541Srgrimes 651541Srgrimes#define GPART_AUTOFILL "*" 661541Srgrimes#define GPART_FLAGS "C" 671541Srgrimes 681541Srgrimes#define GPART_PARAM_BOOTCODE "bootcode" 691541Srgrimes#define GPART_PARAM_INDEX "index" 701541Srgrimes#define GPART_PARAM_PARTCODE "partcode" 711541Srgrimes 721541Srgrimesstatic struct gclass *find_class(struct gmesh *, const char *); 731541Srgrimesstatic struct ggeom * find_geom(struct gclass *, const char *); 741541Srgrimesstatic const char *find_geomcfg(struct ggeom *, const char *); 751541Srgrimesstatic const char *find_provcfg(struct gprovider *, const char *); 761541Srgrimesstatic struct gprovider *find_provider(struct ggeom *, off_t); 771541Srgrimesstatic const char *fmtsize(int64_t); 781541Srgrimesstatic int gpart_autofill(struct gctl_req *); 791541Srgrimesstatic int gpart_autofill_resize(struct gctl_req *); 801541Srgrimesstatic void gpart_bootcode(struct gctl_req *, unsigned int); 811541Srgrimesstatic void *gpart_bootfile_read(const char *, ssize_t *); 821541Srgrimesstatic void gpart_issue(struct gctl_req *, unsigned int); 831541Srgrimesstatic void gpart_show(struct gctl_req *, unsigned int); 841541Srgrimesstatic void gpart_show_geom(struct ggeom *, const char *); 851541Srgrimesstatic int gpart_show_hasopt(struct gctl_req *, const char *, const char *); 861541Srgrimesstatic void gpart_write_partcode(struct ggeom *, int, void *, ssize_t); 871541Srgrimesstatic void gpart_write_partcode_vtoc8(struct ggeom *, int, void *); 881541Srgrimesstatic void gpart_print_error(const char *); 891541Srgrimesstatic void gpart_backup(struct gctl_req *, unsigned int); 901541Srgrimesstatic void gpart_restore(struct gctl_req *, unsigned int); 911541Srgrimes 921541Srgrimesstruct g_command PUBSYM(class_commands)[] = { 931541Srgrimes { "add", 0, gpart_issue, { 941541Srgrimes { 'b', "start", GPART_AUTOFILL, G_TYPE_STRING }, 951541Srgrimes { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, 961541Srgrimes { 't', "type", NULL, G_TYPE_STRING }, 971541Srgrimes { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 981541Srgrimes { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, 991541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1001541Srgrimes G_OPT_SENTINEL }, 1011541Srgrimes "[-b start] [-s size] -t type [-i index] [-l label] [-f flags] geom" 1021541Srgrimes }, 1031541Srgrimes { "backup", 0, gpart_backup, G_NULL_OPTS, 1041541Srgrimes "geom" 1051541Srgrimes }, 1061541Srgrimes { "bootcode", 0, gpart_bootcode, { 1071541Srgrimes { 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, 1081541Srgrimes { 'p', GPART_PARAM_PARTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, 1091541Srgrimes { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 1101541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1111541Srgrimes G_OPT_SENTINEL }, 1121541Srgrimes "[-b bootcode] [-p partcode] [-i index] [-f flags] geom" 1131541Srgrimes }, 1141541Srgrimes { "commit", 0, gpart_issue, G_NULL_OPTS, 1151541Srgrimes "geom" 1161541Srgrimes }, 1171541Srgrimes { "create", 0, gpart_issue, { 1181541Srgrimes { 's', "scheme", NULL, G_TYPE_STRING }, 1191541Srgrimes { 'n', "entries", G_VAL_OPTIONAL, G_TYPE_NUMBER }, 1201541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1211541Srgrimes G_OPT_SENTINEL }, 1221541Srgrimes "-s scheme [-n entries] [-f flags] provider" 1231541Srgrimes }, 1241541Srgrimes { "delete", 0, gpart_issue, { 1251541Srgrimes { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 1261541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1271541Srgrimes G_OPT_SENTINEL }, 1281541Srgrimes "-i index [-f flags] geom" 1291541Srgrimes }, 1301541Srgrimes { "destroy", 0, gpart_issue, { 1311541Srgrimes { 'F', "force", NULL, G_TYPE_BOOL }, 1321541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1331541Srgrimes G_OPT_SENTINEL }, 1341541Srgrimes "[-F] [-f flags] geom" 1351541Srgrimes }, 1361541Srgrimes { "modify", 0, gpart_issue, { 1371541Srgrimes { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 1381541Srgrimes { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, 1391541Srgrimes { 't', "type", G_VAL_OPTIONAL, G_TYPE_STRING }, 1401541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1411541Srgrimes G_OPT_SENTINEL }, 1421541Srgrimes "-i index [-l label] [-t type] [-f flags] geom" 1431541Srgrimes }, 1441541Srgrimes { "set", 0, gpart_issue, { 1451541Srgrimes { 'a', "attrib", NULL, G_TYPE_STRING }, 1461541Srgrimes { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 1471541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1481541Srgrimes G_OPT_SENTINEL }, 1491541Srgrimes "-a attrib -i index [-f flags] geom" 1501541Srgrimes }, 1511541Srgrimes { "show", 0, gpart_show, { 1521541Srgrimes { 'l', "show_label", NULL, G_TYPE_BOOL }, 1531541Srgrimes { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, 1541541Srgrimes G_OPT_SENTINEL }, 1551541Srgrimes "[-lr] [geom ...]" 1561541Srgrimes }, 1571541Srgrimes { "undo", 0, gpart_issue, G_NULL_OPTS, 1581541Srgrimes "geom" 1591541Srgrimes }, 1601541Srgrimes { "unset", 0, gpart_issue, { 1611541Srgrimes { 'a', "attrib", NULL, G_TYPE_STRING }, 1621541Srgrimes { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 1631541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1641541Srgrimes G_OPT_SENTINEL }, 1651541Srgrimes "-a attrib -i index [-f flags] geom" 1661541Srgrimes }, 1671541Srgrimes { "resize", 0, gpart_issue, { 1681541Srgrimes { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, 1691541Srgrimes { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 1701541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1711541Srgrimes G_OPT_SENTINEL }, 1721541Srgrimes "[-s size] -i index [-f flags] geom" 1731541Srgrimes }, 1741541Srgrimes { "restore", 0, gpart_restore, { 1751541Srgrimes { 'F', "force", NULL, G_TYPE_BOOL }, 1761541Srgrimes { 'l', "restore_labels", NULL, G_TYPE_BOOL }, 1771541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1781541Srgrimes G_OPT_SENTINEL }, 1791541Srgrimes "[-lF] [-f flags] provider [...]" 1801541Srgrimes }, 1811541Srgrimes { "recover", 0, gpart_issue, { 1821541Srgrimes { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 1831541Srgrimes G_OPT_SENTINEL }, 1841541Srgrimes "[-f flags] geom" 1851541Srgrimes }, 1861541Srgrimes G_CMD_SENTINEL 1871541Srgrimes}; 1881541Srgrimes 1891541Srgrimesstatic struct gclass * 1901541Srgrimesfind_class(struct gmesh *mesh, const char *name) 1911541Srgrimes{ 1921541Srgrimes struct gclass *classp; 1931541Srgrimes 1941541Srgrimes LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1952112Swollman if (strcmp(classp->lg_name, name) == 0) 1961541Srgrimes return (classp); 1971541Srgrimes } 1981541Srgrimes return (NULL); 1991541Srgrimes} 2001541Srgrimes 2011541Srgrimesstatic struct ggeom * 2021541Srgrimesfind_geom(struct gclass *classp, const char *name) 2031541Srgrimes{ 2041541Srgrimes struct ggeom *gp; 2051541Srgrimes 2061541Srgrimes if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2071541Srgrimes name += sizeof(_PATH_DEV) - 1; 2081541Srgrimes LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 2091541Srgrimes if (strcmp(gp->lg_name, name) == 0) 2101541Srgrimes return (gp); 2111541Srgrimes } 2122165Spaul return (NULL); 2132165Spaul} 214 215static const char * 216find_geomcfg(struct ggeom *gp, const char *cfg) 217{ 218 struct gconfig *gc; 219 220 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 221 if (!strcmp(gc->lg_name, cfg)) 222 return (gc->lg_val); 223 } 224 return (NULL); 225} 226 227static const char * 228find_provcfg(struct gprovider *pp, const char *cfg) 229{ 230 struct gconfig *gc; 231 232 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 233 if (!strcmp(gc->lg_name, cfg)) 234 return (gc->lg_val); 235 } 236 return (NULL); 237} 238 239static struct gprovider * 240find_provider(struct ggeom *gp, off_t minsector) 241{ 242 struct gprovider *pp, *bestpp; 243 const char *s; 244 off_t sector, bestsector; 245 246 bestpp = NULL; 247 bestsector = 0; 248 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 249 s = find_provcfg(pp, "start"); 250 if (s == NULL) { 251 s = find_provcfg(pp, "offset"); 252 sector = 253 (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; 254 } else 255 sector = (off_t)strtoimax(s, NULL, 0); 256 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 298static int 299gpart_autofill_resize(struct gctl_req *req) 300{ 301 struct gmesh mesh; 302 struct gclass *cp; 303 struct ggeom *gp; 304 struct gprovider *pp; 305 off_t last, size, start, new_size; 306 off_t lba, new_lba; 307 const char *s; 308 int error, idx; 309 310 idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 311 if (idx < 1) 312 errx(EXIT_FAILURE, "invalid partition index"); 313 314 error = geom_gettree(&mesh); 315 if (error) 316 return (error); 317 s = gctl_get_ascii(req, "class"); 318 if (s == NULL) 319 abort(); 320 cp = find_class(&mesh, s); 321 if (cp == NULL) 322 errx(EXIT_FAILURE, "Class %s not found.", s); 323 s = gctl_get_ascii(req, "arg0"); 324 if (s == NULL) 325 abort(); 326 gp = find_geom(cp, s); 327 if (gp == NULL) 328 errx(EXIT_FAILURE, "No such geom: %s.", s); 329 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 330 if (pp == NULL) 331 errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 332 333 s = gctl_get_ascii(req, "size"); 334 if (*s == '*') 335 new_size = 0; 336 else { 337 error = g_parse_lba(s, pp->lg_sectorsize, &new_size); 338 if (error) 339 errc(EXIT_FAILURE, error, "Invalid size param"); 340 /* no autofill necessary. */ 341 goto done; 342 } 343 344 last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); 345 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 346 s = find_provcfg(pp, "index"); 347 if (s == NULL) 348 continue; 349 if (atoi(s) == idx) 350 break; 351 } 352 if (pp == NULL) 353 errx(EXIT_FAILURE, "invalid partition index"); 354 355 s = find_provcfg(pp, "start"); 356 if (s == NULL) { 357 s = find_provcfg(pp, "offset"); 358 start = (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; 359 } else 360 start = (off_t)strtoimax(s, NULL, 0); 361 s = find_provcfg(pp, "end"); 362 if (s == NULL) { 363 s = find_provcfg(pp, "length"); 364 lba = start + 365 (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; 366 } else 367 lba = (off_t)strtoimax(s, NULL, 0) + 1; 368 369 if (lba > last) { 370 geom_deletetree(&mesh); 371 return (ENOSPC); 372 } 373 size = lba - start; 374 pp = find_provider(gp, lba); 375 if (pp == NULL) 376 new_size = last - start + 1; 377 else { 378 s = find_provcfg(pp, "start"); 379 if (s == NULL) { 380 s = find_provcfg(pp, "offset"); 381 new_lba = 382 (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; 383 } else 384 new_lba = (off_t)strtoimax(s, NULL, 0); 385 /* 386 * Is there any free space between current and 387 * next providers? 388 */ 389 if (new_lba > lba) 390 new_size = new_lba - start; 391 else { 392 geom_deletetree(&mesh); 393 return (ENOSPC); 394 } 395 } 396done: 397 snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size); 398 gctl_change_param(req, "size", -1, ssize); 399 geom_deletetree(&mesh); 400 return (0); 401} 402 403static int 404gpart_autofill(struct gctl_req *req) 405{ 406 struct gmesh mesh; 407 struct gclass *cp; 408 struct ggeom *gp; 409 struct gprovider *pp; 410 off_t first, last; 411 off_t size, start; 412 off_t lba, len; 413 uintmax_t grade; 414 const char *s; 415 int error, has_size, has_start; 416 417 s = gctl_get_ascii(req, "verb"); 418 if (strcmp(s, "resize") == 0) 419 return gpart_autofill_resize(req); 420 if (strcmp(s, "add") != 0) 421 return (0); 422 423 error = geom_gettree(&mesh); 424 if (error) 425 return (error); 426 s = gctl_get_ascii(req, "class"); 427 if (s == NULL) 428 abort(); 429 cp = find_class(&mesh, s); 430 if (cp == NULL) 431 errx(EXIT_FAILURE, "Class %s not found.", s); 432 s = gctl_get_ascii(req, "arg0"); 433 if (s == NULL) 434 abort(); 435 gp = find_geom(cp, s); 436 if (gp == NULL) 437 errx(EXIT_FAILURE, "No such geom: %s.", s); 438 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 439 if (pp == NULL) 440 errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 441 442 s = gctl_get_ascii(req, "size"); 443 has_size = (*s == '*') ? 0 : 1; 444 size = 0; 445 if (has_size) { 446 error = g_parse_lba(s, pp->lg_sectorsize, &size); 447 if (error) 448 errc(EXIT_FAILURE, error, "Invalid size param"); 449 } 450 451 s = gctl_get_ascii(req, "start"); 452 has_start = (*s == '*') ? 0 : 1; 453 start = 0ULL; 454 if (has_start) { 455 error = g_parse_lba(s, pp->lg_sectorsize, &start); 456 if (error) 457 errc(EXIT_FAILURE, error, "Invalid start param"); 458 } 459 460 /* No autofill necessary. */ 461 if (has_size && has_start) 462 goto done; 463 464 first = (off_t)strtoimax(find_geomcfg(gp, "first"), NULL, 0); 465 last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); 466 grade = ~0ULL; 467 while ((pp = find_provider(gp, first)) != NULL) { 468 s = find_provcfg(pp, "start"); 469 if (s == NULL) { 470 s = find_provcfg(pp, "offset"); 471 lba = (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; 472 } else 473 lba = (off_t)strtoimax(s, NULL, 0); 474 475 if (first < lba) { 476 /* Free space [first, lba> */ 477 len = lba - first; 478 if (has_size) { 479 if (len >= size && 480 (uintmax_t)(len - size) < grade) { 481 start = first; 482 grade = len - size; 483 } 484 } else if (has_start) { 485 if (start >= first && start < lba) { 486 size = lba - start; 487 grade = start - first; 488 } 489 } else { 490 if (grade == ~0ULL || len > size) { 491 start = first; 492 size = len; 493 grade = 0; 494 } 495 } 496 } 497 498 s = find_provcfg(pp, "end"); 499 if (s == NULL) { 500 s = find_provcfg(pp, "length"); 501 first = lba + 502 (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; 503 } else 504 first = (off_t)strtoimax(s, NULL, 0) + 1; 505 } 506 if (first <= last) { 507 /* Free space [first-last] */ 508 len = last - first + 1; 509 if (has_size) { 510 if (len >= size && 511 (uintmax_t)(len - size) < grade) { 512 start = first; 513 grade = len - size; 514 } 515 } else if (has_start) { 516 if (start >= first && start <= last) { 517 size = last - start + 1; 518 grade = start - first; 519 } 520 } else { 521 if (grade == ~0ULL || len > size) { 522 start = first; 523 size = len; 524 grade = 0; 525 } 526 } 527 } 528 529 if (grade == ~0ULL) { 530 geom_deletetree(&mesh); 531 return (ENOSPC); 532 } 533 534done: 535 snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size); 536 gctl_change_param(req, "size", -1, ssize); 537 snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start); 538 gctl_change_param(req, "start", -1, sstart); 539 geom_deletetree(&mesh); 540 return (0); 541} 542 543static void 544gpart_show_geom(struct ggeom *gp, const char *element) 545{ 546 struct gprovider *pp; 547 const char *s, *scheme; 548 off_t first, last, sector, end; 549 off_t length, secsz; 550 int idx, wblocks, wname; 551 552 scheme = find_geomcfg(gp, "scheme"); 553 s = find_geomcfg(gp, "first"); 554 first = (off_t)strtoimax(s, NULL, 0); 555 s = find_geomcfg(gp, "last"); 556 last = (off_t)strtoimax(s, NULL, 0); 557 wblocks = strlen(s); 558 s = find_geomcfg(gp, "state"); 559 if (s != NULL && *s != 'C') 560 s = NULL; 561 wname = strlen(gp->lg_name); 562 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 563 secsz = pp->lg_sectorsize; 564 printf("=>%*jd %*jd %*s %s (%s)%s\n", 565 wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1), 566 wname, gp->lg_name, 567 scheme, fmtsize(pp->lg_mediasize), 568 s ? " [CORRUPT]": ""); 569 570 while ((pp = find_provider(gp, first)) != NULL) { 571 s = find_provcfg(pp, "start"); 572 if (s == NULL) { 573 s = find_provcfg(pp, "offset"); 574 sector = (off_t)strtoimax(s, NULL, 0) / secsz; 575 } else 576 sector = (off_t)strtoimax(s, NULL, 0); 577 578 s = find_provcfg(pp, "end"); 579 if (s == NULL) { 580 s = find_provcfg(pp, "length"); 581 length = (off_t)strtoimax(s, NULL, 0) / secsz; 582 end = sector + length - 1; 583 } else { 584 end = (off_t)strtoimax(s, NULL, 0); 585 length = end - sector + 1; 586 } 587 s = find_provcfg(pp, "index"); 588 idx = atoi(s); 589 if (first < sector) { 590 printf(" %*jd %*jd %*s - free - (%s)\n", 591 wblocks, (intmax_t)first, wblocks, 592 (intmax_t)(sector - first), wname, "", 593 fmtsize((sector - first) * secsz)); 594 } 595 printf(" %*jd %*jd %*d %s %s (%s)\n", 596 wblocks, (intmax_t)sector, wblocks, (intmax_t)length, 597 wname, idx, find_provcfg(pp, element), 598 fmtattrib(pp), fmtsize(pp->lg_mediasize)); 599 first = end + 1; 600 } 601 if (first <= last) { 602 length = last - first + 1; 603 printf(" %*jd %*jd %*s - free - (%s)\n", 604 wblocks, (intmax_t)first, wblocks, (intmax_t)length, 605 wname, "", 606 fmtsize(length * secsz)); 607 } 608 printf("\n"); 609} 610 611static int 612gpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 613{ 614 615 if (!gctl_get_int(req, opt)) 616 return (0); 617 618 if (elt != NULL) 619 errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 620 621 return (1); 622} 623 624static void 625gpart_show(struct gctl_req *req, unsigned int fl __unused) 626{ 627 struct gmesh mesh; 628 struct gclass *classp; 629 struct ggeom *gp; 630 const char *element, *name; 631 int error, i, nargs; 632 633 element = NULL; 634 if (gpart_show_hasopt(req, "show_label", element)) 635 element = "label"; 636 if (gpart_show_hasopt(req, "show_rawtype", element)) 637 element = "rawtype"; 638 if (element == NULL) 639 element = "type"; 640 641 name = gctl_get_ascii(req, "class"); 642 if (name == NULL) 643 abort(); 644 error = geom_gettree(&mesh); 645 if (error != 0) 646 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 647 classp = find_class(&mesh, name); 648 if (classp == NULL) { 649 geom_deletetree(&mesh); 650 errx(EXIT_FAILURE, "Class %s not found.", name); 651 } 652 nargs = gctl_get_int(req, "nargs"); 653 if (nargs > 0) { 654 for (i = 0; i < nargs; i++) { 655 name = gctl_get_ascii(req, "arg%d", i); 656 gp = find_geom(classp, name); 657 if (gp != NULL) 658 gpart_show_geom(gp, element); 659 else 660 errx(EXIT_FAILURE, "No such geom: %s.", name); 661 } 662 } else { 663 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 664 gpart_show_geom(gp, element); 665 } 666 } 667 geom_deletetree(&mesh); 668} 669 670static void 671gpart_backup(struct gctl_req *req, unsigned int fl __unused) 672{ 673 struct gmesh mesh; 674 struct gclass *classp; 675 struct gprovider *pp; 676 struct ggeom *gp; 677 const char *s, *scheme; 678 off_t sector, end; 679 off_t length, secsz; 680 int error, i, windex, wblocks, wtype; 681 682 if (gctl_get_int(req, "nargs") != 1) 683 errx(EXIT_FAILURE, "Invalid number of arguments."); 684 error = geom_gettree(&mesh); 685 if (error != 0) 686 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 687 s = gctl_get_ascii(req, "class"); 688 if (s == NULL) 689 abort(); 690 classp = find_class(&mesh, s); 691 if (classp == NULL) { 692 geom_deletetree(&mesh); 693 errx(EXIT_FAILURE, "Class %s not found.", s); 694 } 695 s = gctl_get_ascii(req, "arg0"); 696 if (s == NULL) 697 abort(); 698 gp = find_geom(classp, s); 699 if (gp == NULL) 700 errx(EXIT_FAILURE, "No such geom: %s.", s); 701 scheme = find_geomcfg(gp, "scheme"); 702 if (scheme == NULL) 703 abort(); 704 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 705 secsz = pp->lg_sectorsize; 706 s = find_geomcfg(gp, "last"); 707 wblocks = strlen(s); 708 wtype = 0; 709 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 710 s = find_provcfg(pp, "type"); 711 i = strlen(s); 712 if (i > wtype) 713 wtype = i; 714 } 715 s = find_geomcfg(gp, "entries"); 716 windex = strlen(s); 717 printf("%s %s\n", scheme, s); 718 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 719 s = find_provcfg(pp, "start"); 720 if (s == NULL) { 721 s = find_provcfg(pp, "offset"); 722 sector = (off_t)strtoimax(s, NULL, 0) / secsz; 723 } else 724 sector = (off_t)strtoimax(s, NULL, 0); 725 726 s = find_provcfg(pp, "end"); 727 if (s == NULL) { 728 s = find_provcfg(pp, "length"); 729 length = (off_t)strtoimax(s, NULL, 0) / secsz; 730 } else { 731 end = (off_t)strtoimax(s, NULL, 0); 732 length = end - sector + 1; 733 } 734 s = find_provcfg(pp, "label"); 735 printf("%-*s %*s %*jd %*jd %s %s\n", 736 windex, find_provcfg(pp, "index"), 737 wtype, find_provcfg(pp, "type"), 738 wblocks, (intmax_t)sector, 739 wblocks, (intmax_t)length, 740 (s != NULL) ? s: "", fmtattrib(pp)); 741 } 742 geom_deletetree(&mesh); 743} 744 745static int 746skip_line(const char *p) 747{ 748 749 while (*p != '\0') { 750 if (*p == '#') 751 return (1); 752 if (isspace(*p) == 0) 753 return (0); 754 p++; 755 } 756 return (1); 757} 758 759static void 760gpart_restore(struct gctl_req *req, unsigned int fl __unused) 761{ 762 struct gmesh mesh; 763 struct gclass *classp; 764 struct gctl_req *r; 765 struct ggeom *gp; 766 const char *s, *flags, *errstr, *label; 767 char **ap, *argv[6], line[BUFSIZ], *pline; 768 int error, forced, i, l, nargs, created, rl; 769 intmax_t n; 770 771 nargs = gctl_get_int(req, "nargs"); 772 if (nargs < 1) 773 errx(EXIT_FAILURE, "Invalid number of arguments."); 774 775 forced = gctl_get_int(req, "force"); 776 flags = gctl_get_ascii(req, "flags"); 777 rl = gctl_get_int(req, "restore_labels"); 778 s = gctl_get_ascii(req, "class"); 779 if (s == NULL) 780 abort(); 781 error = geom_gettree(&mesh); 782 if (error != 0) 783 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 784 classp = find_class(&mesh, s); 785 if (classp == NULL) { 786 geom_deletetree(&mesh); 787 errx(EXIT_FAILURE, "Class %s not found.", s); 788 } 789 if (forced) { 790 /* destroy existent partition table before restore */ 791 for (i = 0; i < nargs; i++) { 792 s = gctl_get_ascii(req, "arg%d", i); 793 gp = find_geom(classp, s); 794 if (gp != NULL) { 795 r = gctl_get_handle(); 796 gctl_ro_param(r, "class", -1, 797 classp->lg_name); 798 gctl_ro_param(r, "verb", -1, "destroy"); 799 gctl_ro_param(r, "flags", -1, "restore"); 800 gctl_ro_param(r, "force", sizeof(forced), 801 &forced); 802 gctl_ro_param(r, "arg0", -1, s); 803 errstr = gctl_issue(r); 804 if (errstr != NULL && errstr[0] != '\0') { 805 gpart_print_error(errstr); 806 gctl_free(r); 807 goto backout; 808 } 809 gctl_free(r); 810 } 811 } 812 } 813 created = 0; 814 while (fgets(line, sizeof(line) - 1, stdin)) { 815 /* Format of backup entries: 816 * <scheme name> <number of entries> 817 * <index> <type> <start> <size> [label] ['['attrib[,attrib]']'] 818 */ 819 pline = (char *)line; 820 pline[strlen(line) - 1] = 0; 821 if (skip_line(pline)) 822 continue; 823 for (ap = argv; 824 (*ap = strsep(&pline, " \t")) != NULL;) 825 if (**ap != '\0' && ++ap >= &argv[6]) 826 break; 827 l = ap - &argv[0]; 828 label = pline = NULL; 829 if (l == 1 || l == 2) { /* create table */ 830 if (created) 831 errx(EXIT_FAILURE, "Incorrect backup format."); 832 if (l == 2) 833 n = strtoimax(argv[1], NULL, 0); 834 for (i = 0; i < nargs; i++) { 835 s = gctl_get_ascii(req, "arg%d", i); 836 r = gctl_get_handle(); 837 gctl_ro_param(r, "class", -1, 838 classp->lg_name); 839 gctl_ro_param(r, "verb", -1, "create"); 840 gctl_ro_param(r, "scheme", -1, argv[0]); 841 if (l == 2) 842 gctl_ro_param(r, "entries", 843 sizeof(n), &n); 844 gctl_ro_param(r, "flags", -1, "restore"); 845 gctl_ro_param(r, "arg0", -1, s); 846 errstr = gctl_issue(r); 847 if (errstr != NULL && errstr[0] != '\0') { 848 gpart_print_error(errstr); 849 gctl_free(r); 850 goto backout; 851 } 852 gctl_free(r); 853 } 854 created = 1; 855 continue; 856 } else if (l < 4 || created == 0) 857 errx(EXIT_FAILURE, "Incorrect backup format."); 858 else if (l == 5) { 859 if (strchr(argv[4], '[') == NULL) 860 label = argv[4]; 861 else 862 pline = argv[4]; 863 } else if (l == 6) { 864 label = argv[4]; 865 pline = argv[5]; 866 } 867 /* Add partitions to each table */ 868 for (i = 0; i < nargs; i++) { 869 s = gctl_get_ascii(req, "arg%d", i); 870 r = gctl_get_handle(); 871 n = strtoimax(argv[0], NULL, 0); 872 gctl_ro_param(r, "class", -1, classp->lg_name); 873 gctl_ro_param(r, "verb", -1, "add"); 874 gctl_ro_param(r, "flags", -1, "restore"); 875 gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n); 876 gctl_ro_param(r, "type", -1, argv[1]); 877 gctl_ro_param(r, "start", -1, argv[2]); 878 gctl_ro_param(r, "size", -1, argv[3]); 879 if (rl != 0 && label != NULL) 880 gctl_ro_param(r, "label", -1, argv[4]); 881 gctl_ro_param(r, "arg0", -1, s); 882 error = gpart_autofill(r); 883 if (error != 0) 884 errc(EXIT_FAILURE, error, "autofill"); 885 errstr = gctl_issue(r); 886 if (errstr != NULL && errstr[0] != '\0') { 887 gpart_print_error(errstr); 888 gctl_free(r); 889 goto backout; 890 } 891 gctl_free(r); 892 } 893 if (pline == NULL || *pline != '[') 894 continue; 895 /* set attributes */ 896 pline++; 897 for (ap = argv; 898 (*ap = strsep(&pline, ",]")) != NULL;) 899 if (**ap != '\0' && ++ap >= &argv[6]) 900 break; 901 for (i = 0; i < nargs; i++) { 902 l = ap - &argv[0]; 903 s = gctl_get_ascii(req, "arg%d", i); 904 while (l > 0) { 905 r = gctl_get_handle(); 906 gctl_ro_param(r, "class", -1, classp->lg_name); 907 gctl_ro_param(r, "verb", -1, "set"); 908 gctl_ro_param(r, "flags", -1, "restore"); 909 gctl_ro_param(r, GPART_PARAM_INDEX, 910 sizeof(n), &n); 911 gctl_ro_param(r, "attrib", -1, argv[--l]); 912 gctl_ro_param(r, "arg0", -1, s); 913 errstr = gctl_issue(r); 914 if (errstr != NULL && errstr[0] != '\0') { 915 gpart_print_error(errstr); 916 gctl_free(r); 917 goto backout; 918 } 919 gctl_free(r); 920 } 921 } 922 } 923 /* commit changes if needed */ 924 if (strchr(flags, 'C') != NULL) { 925 for (i = 0; i < nargs; i++) { 926 s = gctl_get_ascii(req, "arg%d", i); 927 r = gctl_get_handle(); 928 gctl_ro_param(r, "class", -1, classp->lg_name); 929 gctl_ro_param(r, "verb", -1, "commit"); 930 gctl_ro_param(r, "arg0", -1, s); 931 errstr = gctl_issue(r); 932 if (errstr != NULL && errstr[0] != '\0') { 933 gpart_print_error(errstr); 934 gctl_free(r); 935 goto backout; 936 } 937 gctl_free(r); 938 } 939 } 940 gctl_free(req); 941 geom_deletetree(&mesh); 942 exit(EXIT_SUCCESS); 943 944backout: 945 for (i = 0; i < nargs; i++) { 946 s = gctl_get_ascii(req, "arg%d", i); 947 r = gctl_get_handle(); 948 gctl_ro_param(r, "class", -1, classp->lg_name); 949 gctl_ro_param(r, "verb", -1, "undo"); 950 gctl_ro_param(r, "arg0", -1, s); 951 gctl_issue(r); 952 gctl_free(r); 953 } 954 gctl_free(req); 955 geom_deletetree(&mesh); 956 exit(EXIT_FAILURE); 957} 958 959static void * 960gpart_bootfile_read(const char *bootfile, ssize_t *size) 961{ 962 struct stat sb; 963 void *code; 964 int fd; 965 966 if (stat(bootfile, &sb) == -1) 967 err(EXIT_FAILURE, "%s", bootfile); 968 if (!S_ISREG(sb.st_mode)) 969 errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 970 if (sb.st_size == 0) 971 errx(EXIT_FAILURE, "%s: empty file", bootfile); 972 if (*size > 0 && sb.st_size > *size) 973 errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 974 *size); 975 976 *size = sb.st_size; 977 978 fd = open(bootfile, O_RDONLY); 979 if (fd == -1) 980 err(EXIT_FAILURE, "%s", bootfile); 981 code = malloc(*size); 982 if (code == NULL) 983 err(EXIT_FAILURE, NULL); 984 if (read(fd, code, *size) != *size) 985 err(EXIT_FAILURE, "%s", bootfile); 986 close(fd); 987 988 return (code); 989} 990 991static void 992gpart_write_partcode(struct ggeom *gp, int idx, void *code, ssize_t size) 993{ 994 char dsf[128]; 995 struct gprovider *pp; 996 const char *s; 997 char *buf; 998 off_t bsize; 999 int fd; 1000 1001 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1002 s = find_provcfg(pp, "index"); 1003 if (s == NULL) 1004 continue; 1005 if (atoi(s) == idx) 1006 break; 1007 } 1008 1009 if (pp != NULL) { 1010 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1011 fd = open(dsf, O_WRONLY); 1012 if (fd == -1) 1013 err(EXIT_FAILURE, "%s", dsf); 1014 if (lseek(fd, size, SEEK_SET) != size) 1015 errx(EXIT_FAILURE, "%s: not enough space", dsf); 1016 if (lseek(fd, 0, SEEK_SET) != 0) 1017 err(EXIT_FAILURE, "%s", dsf); 1018 1019 /* 1020 * When writing to a disk device, the write must be 1021 * sector aligned and not write to any partial sectors, 1022 * so round up the buffer size to the next sector and zero it. 1023 */ 1024 bsize = (size + pp->lg_sectorsize - 1) / 1025 pp->lg_sectorsize * pp->lg_sectorsize; 1026 buf = calloc(1, bsize); 1027 if (buf == NULL) 1028 err(EXIT_FAILURE, "%s", dsf); 1029 bcopy(code, buf, size); 1030 if (write(fd, buf, bsize) != bsize) 1031 err(EXIT_FAILURE, "%s", dsf); 1032 free(buf); 1033 close(fd); 1034 } else 1035 errx(EXIT_FAILURE, "invalid partition index"); 1036} 1037 1038static void 1039gpart_write_partcode_vtoc8(struct ggeom *gp, int idx, void *code) 1040{ 1041 char dsf[128]; 1042 struct gprovider *pp; 1043 const char *s; 1044 int installed, fd; 1045 1046 installed = 0; 1047 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1048 s = find_provcfg(pp, "index"); 1049 if (s == NULL) 1050 continue; 1051 if (idx != 0 && atoi(s) != idx) 1052 continue; 1053 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1054 if (pp->lg_sectorsize != sizeof(struct vtoc8)) 1055 errx(EXIT_FAILURE, "%s: unexpected sector " 1056 "size (%d)\n", dsf, pp->lg_sectorsize); 1057 fd = open(dsf, O_WRONLY); 1058 if (fd == -1) 1059 err(EXIT_FAILURE, "%s", dsf); 1060 if (lseek(fd, VTOC_BOOTSIZE, SEEK_SET) != VTOC_BOOTSIZE) 1061 continue; 1062 /* 1063 * We ignore the first VTOC_BOOTSIZE bytes of boot code in 1064 * order to avoid overwriting the label. 1065 */ 1066 if (lseek(fd, sizeof(struct vtoc8), SEEK_SET) != 1067 sizeof(struct vtoc8)) 1068 err(EXIT_FAILURE, "%s", dsf); 1069 if (write(fd, (caddr_t)code + sizeof(struct vtoc8), 1070 VTOC_BOOTSIZE - sizeof(struct vtoc8)) != VTOC_BOOTSIZE - 1071 sizeof(struct vtoc8)) 1072 err(EXIT_FAILURE, "%s", dsf); 1073 installed++; 1074 close(fd); 1075 if (idx != 0 && atoi(s) == idx) 1076 break; 1077 } 1078 if (installed == 0) 1079 errx(EXIT_FAILURE, "%s: no partitions", gp->lg_name); 1080} 1081 1082static void 1083gpart_bootcode(struct gctl_req *req, unsigned int fl) 1084{ 1085 struct gmesh mesh; 1086 struct gclass *classp; 1087 struct ggeom *gp; 1088 const char *s; 1089 void *bootcode, *partcode; 1090 size_t bootsize, partsize; 1091 int error, idx, vtoc8; 1092 1093 if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) { 1094 s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE); 1095 bootsize = 800 * 1024; /* Arbitrary limit. */ 1096 bootcode = gpart_bootfile_read(s, &bootsize); 1097 error = gctl_change_param(req, GPART_PARAM_BOOTCODE, bootsize, 1098 bootcode); 1099 if (error) 1100 errc(EXIT_FAILURE, error, "internal error"); 1101 } else { 1102 bootcode = NULL; 1103 bootsize = 0; 1104 } 1105 1106 s = gctl_get_ascii(req, "class"); 1107 if (s == NULL) 1108 abort(); 1109 error = geom_gettree(&mesh); 1110 if (error != 0) 1111 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 1112 classp = find_class(&mesh, s); 1113 if (classp == NULL) { 1114 geom_deletetree(&mesh); 1115 errx(EXIT_FAILURE, "Class %s not found.", s); 1116 } 1117 s = gctl_get_ascii(req, "arg0"); 1118 if (s == NULL) 1119 abort(); 1120 gp = find_geom(classp, s); 1121 if (gp == NULL) 1122 errx(EXIT_FAILURE, "No such geom: %s.", s); 1123 s = find_geomcfg(gp, "scheme"); 1124 vtoc8 = 0; 1125 if (strcmp(s, "VTOC8") == 0) 1126 vtoc8 = 1; 1127 1128 if (gctl_has_param(req, GPART_PARAM_PARTCODE)) { 1129 s = gctl_get_ascii(req, GPART_PARAM_PARTCODE); 1130 partsize = vtoc8 != 0 ? VTOC_BOOTSIZE : bootsize * 1024; 1131 partcode = gpart_bootfile_read(s, &partsize); 1132 error = gctl_delete_param(req, GPART_PARAM_PARTCODE); 1133 if (error) 1134 errc(EXIT_FAILURE, error, "internal error"); 1135 } else { 1136 partcode = NULL; 1137 partsize = 0; 1138 } 1139 1140 if (gctl_has_param(req, GPART_PARAM_INDEX)) { 1141 if (partcode == NULL) 1142 errx(EXIT_FAILURE, "-i is only valid with -p"); 1143 idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 1144 if (idx < 1) 1145 errx(EXIT_FAILURE, "invalid partition index"); 1146 error = gctl_delete_param(req, GPART_PARAM_INDEX); 1147 if (error) 1148 errc(EXIT_FAILURE, error, "internal error"); 1149 } else 1150 idx = 0; 1151 1152 if (partcode != NULL) { 1153 if (vtoc8 == 0) { 1154 if (idx == 0) 1155 errx(EXIT_FAILURE, "missing -i option"); 1156 gpart_write_partcode(gp, idx, partcode, partsize); 1157 } else 1158 gpart_write_partcode_vtoc8(gp, idx, partcode); 1159 } else 1160 if (bootcode == NULL) 1161 errx(EXIT_FAILURE, "no -b nor -p"); 1162 1163 if (bootcode != NULL) 1164 gpart_issue(req, fl); 1165 1166 geom_deletetree(&mesh); 1167} 1168 1169static void 1170gpart_print_error(const char *errstr) 1171{ 1172 char *errmsg; 1173 int error; 1174 1175 error = strtol(errstr, &errmsg, 0); 1176 if (errmsg != errstr) { 1177 while (errmsg[0] == ' ') 1178 errmsg++; 1179 if (errmsg[0] != '\0') 1180 warnc(error, "%s", errmsg); 1181 else 1182 warnc(error, NULL); 1183 } else 1184 warnx("%s", errmsg); 1185} 1186 1187static void 1188gpart_issue(struct gctl_req *req, unsigned int fl __unused) 1189{ 1190 char buf[4096]; 1191 const char *errstr; 1192 int error, status; 1193 1194 if (gctl_get_int(req, "nargs") != 1) 1195 errx(EXIT_FAILURE, "Invalid number of arguments."); 1196 (void)gctl_delete_param(req, "nargs"); 1197 1198 /* autofill parameters (if applicable). */ 1199 error = gpart_autofill(req); 1200 if (error) { 1201 warnc(error, "autofill"); 1202 status = EXIT_FAILURE; 1203 goto done; 1204 } 1205 1206 bzero(buf, sizeof(buf)); 1207 gctl_rw_param(req, "output", sizeof(buf), buf); 1208 errstr = gctl_issue(req); 1209 if (errstr == NULL || errstr[0] == '\0') { 1210 if (buf[0] != '\0') 1211 printf("%s", buf); 1212 status = EXIT_SUCCESS; 1213 goto done; 1214 } 1215 1216 gpart_print_error(errstr); 1217 status = EXIT_FAILURE; 1218 1219 done: 1220 gctl_free(req); 1221 exit(status); 1222} 1223