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