1169586Smarcel/*- 2179854Smarcel * Copyright (c) 2007, 2008 Marcel Moolenaar 3169586Smarcel * All rights reserved. 4169586Smarcel * 5169586Smarcel * Redistribution and use in source and binary forms, with or without 6169586Smarcel * modification, are permitted provided that the following conditions 7169586Smarcel * are met: 8169586Smarcel * 1. Redistributions of source code must retain the above copyright 9169586Smarcel * notice, this list of conditions and the following disclaimer. 10169586Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11169586Smarcel * notice, this list of conditions and the following disclaimer in the 12169586Smarcel * documentation and/or other materials provided with the distribution. 13169586Smarcel * 14169586Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15169586Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169586Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169586Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18169586Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169586Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169586Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169586Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169586Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169586Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169586Smarcel * SUCH DAMAGE. 25169586Smarcel */ 26169586Smarcel 27169586Smarcel#include <sys/cdefs.h> 28169586Smarcel__FBSDID("$FreeBSD$"); 29169586Smarcel 30185044Smarcel#include <sys/stat.h> 31208777Smarius#include <sys/vtoc.h> 32185044Smarcel 33185044Smarcel#include <assert.h> 34215570Sae#include <ctype.h> 35185044Smarcel#include <err.h> 36185044Smarcel#include <errno.h> 37185044Smarcel#include <fcntl.h> 38185044Smarcel#include <libgeom.h> 39185046Smarcel#include <libutil.h> 40185044Smarcel#include <paths.h> 41215672Sae#include <signal.h> 42185044Smarcel#include <stdint.h> 43169586Smarcel#include <stdio.h> 44169586Smarcel#include <stdlib.h> 45209388Sae#include <limits.h> 46209388Sae#include <inttypes.h> 47169586Smarcel#include <string.h> 48169586Smarcel#include <strings.h> 49185044Smarcel#include <unistd.h> 50169586Smarcel 51169586Smarcel#include "core/geom.h" 52169586Smarcel#include "misc/subr.h" 53169586Smarcel 54179550Smarcel#ifdef STATIC_GEOM_CLASSES 55173313Smarcel#define PUBSYM(x) gpart_##x 56173313Smarcel#else 57173313Smarcel#define PUBSYM(x) x 58173313Smarcel#endif 59169586Smarcel 60173313Smarceluint32_t PUBSYM(lib_version) = G_LIB_VERSION; 61173313Smarceluint32_t PUBSYM(version) = 0; 62173313Smarcel 63209388Saestatic char sstart[32]; 64209388Saestatic char ssize[32]; 65215672Saevolatile sig_atomic_t undo_restore; 66209388Sae 67212554Spjd#define GPART_AUTOFILL "*" 68212554Spjd#define GPART_FLAGS "C" 69179629Smarcel 70212554Spjd#define GPART_PARAM_BOOTCODE "bootcode" 71212554Spjd#define GPART_PARAM_INDEX "index" 72212554Spjd#define GPART_PARAM_PARTCODE "partcode" 73212554Spjd 74208777Smariusstatic struct gclass *find_class(struct gmesh *, const char *); 75208777Smariusstatic struct ggeom * find_geom(struct gclass *, const char *); 76208777Smariusstatic const char *find_geomcfg(struct ggeom *, const char *); 77208777Smariusstatic const char *find_provcfg(struct gprovider *, const char *); 78209388Saestatic struct gprovider *find_provider(struct ggeom *, off_t); 79208777Smariusstatic const char *fmtsize(int64_t); 80208777Smariusstatic int gpart_autofill(struct gctl_req *); 81208777Smariusstatic int gpart_autofill_resize(struct gctl_req *); 82178180Smarcelstatic void gpart_bootcode(struct gctl_req *, unsigned int); 83208777Smariusstatic void *gpart_bootfile_read(const char *, ssize_t *); 84185454Smarcelstatic void gpart_issue(struct gctl_req *, unsigned int); 85178180Smarcelstatic void gpart_show(struct gctl_req *, unsigned int); 86219415Saestatic void gpart_show_geom(struct ggeom *, const char *, int); 87208777Smariusstatic int gpart_show_hasopt(struct gctl_req *, const char *, const char *); 88208777Smariusstatic void gpart_write_partcode(struct ggeom *, int, void *, ssize_t); 89208777Smariusstatic void gpart_write_partcode_vtoc8(struct ggeom *, int, void *); 90213097Saestatic void gpart_print_error(const char *); 91215570Saestatic void gpart_backup(struct gctl_req *, unsigned int); 92215570Saestatic void gpart_restore(struct gctl_req *, unsigned int); 93172837Smarcel 94173313Smarcelstruct g_command PUBSYM(class_commands)[] = { 95185454Smarcel { "add", 0, gpart_issue, { 96221363Sae { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, 97212554Spjd { 'b', "start", GPART_AUTOFILL, G_TYPE_STRING }, 98212554Spjd { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, 99169586Smarcel { 't', "type", NULL, G_TYPE_STRING }, 100212614Spjd { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 101212606Spjd { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, 102212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 103169586Smarcel G_OPT_SENTINEL }, 104222357Sae "-t type [-a alignment] [-b start] [-s size] [-i index] " 105221363Sae "[-l label] [-f flags] geom" 106169586Smarcel }, 107215671Sae { "backup", 0, gpart_backup, G_NULL_OPTS, 108215671Sae "geom" 109215570Sae }, 110178180Smarcel { "bootcode", 0, gpart_bootcode, { 111212606Spjd { 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, 112212606Spjd { 'p', GPART_PARAM_PARTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, 113212614Spjd { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 114212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 115178180Smarcel G_OPT_SENTINEL }, 116222357Sae "[-b bootcode] [-p partcode -i index] [-f flags] geom" 117178180Smarcel }, 118212554Spjd { "commit", 0, gpart_issue, G_NULL_OPTS, 119212554Spjd "geom" 120212554Spjd }, 121185454Smarcel { "create", 0, gpart_issue, { 122169586Smarcel { 's', "scheme", NULL, G_TYPE_STRING }, 123212614Spjd { 'n', "entries", G_VAL_OPTIONAL, G_TYPE_NUMBER }, 124212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 125169586Smarcel G_OPT_SENTINEL }, 126212554Spjd "-s scheme [-n entries] [-f flags] provider" 127169586Smarcel }, 128185454Smarcel { "delete", 0, gpart_issue, { 129212614Spjd { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 130212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 131169586Smarcel G_OPT_SENTINEL }, 132212554Spjd "-i index [-f flags] geom" 133169586Smarcel }, 134214352Sae { "destroy", 0, gpart_issue, { 135214352Sae { 'F', "force", NULL, G_TYPE_BOOL }, 136212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 137169586Smarcel G_OPT_SENTINEL }, 138213097Sae "[-F] [-f flags] geom" 139212554Spjd }, 140185454Smarcel { "modify", 0, gpart_issue, { 141212614Spjd { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 142212606Spjd { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, 143212606Spjd { 't', "type", G_VAL_OPTIONAL, G_TYPE_STRING }, 144212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 145169586Smarcel G_OPT_SENTINEL }, 146212554Spjd "-i index [-l label] [-t type] [-f flags] geom" 147169586Smarcel }, 148185454Smarcel { "set", 0, gpart_issue, { 149179854Smarcel { 'a', "attrib", NULL, G_TYPE_STRING }, 150251588Smarcel { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 151212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 152179854Smarcel G_OPT_SENTINEL }, 153251588Smarcel "-a attrib [-i index] [-f flags] geom" 154179854Smarcel }, 155179769Smarcel { "show", 0, gpart_show, { 156179769Smarcel { 'l', "show_label", NULL, G_TYPE_BOOL }, 157179769Smarcel { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, 158219415Sae { 'p', "show_providers", NULL, G_TYPE_BOOL }, 159179769Smarcel G_OPT_SENTINEL }, 160222357Sae "[-l | -r] [-p] [geom ...]" 161179769Smarcel }, 162212554Spjd { "undo", 0, gpart_issue, G_NULL_OPTS, 163212554Spjd "geom" 164212554Spjd }, 165185454Smarcel { "unset", 0, gpart_issue, { 166179854Smarcel { 'a', "attrib", NULL, G_TYPE_STRING }, 167251588Smarcel { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, 168212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 169179854Smarcel G_OPT_SENTINEL }, 170251588Smarcel "-a attrib [-i index] [-f flags] geom" 171208777Smarius }, 172207095Smarcel { "resize", 0, gpart_issue, { 173221363Sae { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, 174212554Spjd { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, 175212614Spjd { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, 176212554Spjd { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 177207095Smarcel G_OPT_SENTINEL }, 178222357Sae "-i index [-a alignment] [-s size] [-f flags] geom" 179207095Smarcel }, 180215570Sae { "restore", 0, gpart_restore, { 181215570Sae { 'F', "force", NULL, G_TYPE_BOOL }, 182215671Sae { 'l', "restore_labels", NULL, G_TYPE_BOOL }, 183215570Sae { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 184215570Sae G_OPT_SENTINEL }, 185215671Sae "[-lF] [-f flags] provider [...]" 186215570Sae }, 187214352Sae { "recover", 0, gpart_issue, { 188214352Sae { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, 189214352Sae G_OPT_SENTINEL }, 190214352Sae "[-f flags] geom" 191214352Sae }, 192169586Smarcel G_CMD_SENTINEL 193169586Smarcel}; 194172837Smarcel 195172837Smarcelstatic struct gclass * 196172837Smarcelfind_class(struct gmesh *mesh, const char *name) 197172837Smarcel{ 198172837Smarcel struct gclass *classp; 199172837Smarcel 200172837Smarcel LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 201172837Smarcel if (strcmp(classp->lg_name, name) == 0) 202172837Smarcel return (classp); 203172837Smarcel } 204172837Smarcel return (NULL); 205172837Smarcel} 206172837Smarcel 207172837Smarcelstatic struct ggeom * 208172837Smarcelfind_geom(struct gclass *classp, const char *name) 209172837Smarcel{ 210172837Smarcel struct ggeom *gp; 211172837Smarcel 212213662Sae if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 213213662Sae name += sizeof(_PATH_DEV) - 1; 214172837Smarcel LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 215172837Smarcel if (strcmp(gp->lg_name, name) == 0) 216172837Smarcel return (gp); 217172837Smarcel } 218172837Smarcel return (NULL); 219172837Smarcel} 220172837Smarcel 221172837Smarcelstatic const char * 222172837Smarcelfind_geomcfg(struct ggeom *gp, const char *cfg) 223172837Smarcel{ 224172837Smarcel struct gconfig *gc; 225172837Smarcel 226172837Smarcel LIST_FOREACH(gc, &gp->lg_config, lg_config) { 227172837Smarcel if (!strcmp(gc->lg_name, cfg)) 228172837Smarcel return (gc->lg_val); 229172837Smarcel } 230172837Smarcel return (NULL); 231172837Smarcel} 232172837Smarcel 233172837Smarcelstatic const char * 234172837Smarcelfind_provcfg(struct gprovider *pp, const char *cfg) 235172837Smarcel{ 236172837Smarcel struct gconfig *gc; 237172837Smarcel 238172837Smarcel LIST_FOREACH(gc, &pp->lg_config, lg_config) { 239172837Smarcel if (!strcmp(gc->lg_name, cfg)) 240172837Smarcel return (gc->lg_val); 241172837Smarcel } 242172837Smarcel return (NULL); 243172837Smarcel} 244172837Smarcel 245172837Smarcelstatic struct gprovider * 246209388Saefind_provider(struct ggeom *gp, off_t minsector) 247172837Smarcel{ 248172837Smarcel struct gprovider *pp, *bestpp; 249188330Smarcel const char *s; 250209388Sae off_t sector, bestsector; 251172837Smarcel 252172837Smarcel bestpp = NULL; 253198478Slulf bestsector = 0; 254172837Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 255188330Smarcel s = find_provcfg(pp, "start"); 256221952Sae sector = (off_t)strtoimax(s, NULL, 0); 257172837Smarcel if (sector < minsector) 258172837Smarcel continue; 259172837Smarcel if (bestpp != NULL && sector >= bestsector) 260172837Smarcel continue; 261188330Smarcel 262172837Smarcel bestpp = pp; 263172837Smarcel bestsector = sector; 264172837Smarcel } 265172837Smarcel return (bestpp); 266172837Smarcel} 267172837Smarcel 268172837Smarcelstatic const char * 269185046Smarcelfmtsize(int64_t rawsz) 270172837Smarcel{ 271185046Smarcel static char buf[5]; 272172837Smarcel 273185046Smarcel humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, 274185046Smarcel HN_B | HN_NOSPACE | HN_DECIMAL); 275172837Smarcel return (buf); 276172837Smarcel} 277172837Smarcel 278179854Smarcelstatic const char * 279179854Smarcelfmtattrib(struct gprovider *pp) 280179854Smarcel{ 281184070Smarcel static char buf[128]; 282184070Smarcel struct gconfig *gc; 283184070Smarcel u_int idx; 284179854Smarcel 285184070Smarcel buf[0] = '\0'; 286184070Smarcel idx = 0; 287184070Smarcel LIST_FOREACH(gc, &pp->lg_config, lg_config) { 288184070Smarcel if (strcmp(gc->lg_name, "attrib") != 0) 289184070Smarcel continue; 290184070Smarcel idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", 291184070Smarcel (idx == 0) ? " [" : ",", gc->lg_val); 292184070Smarcel } 293184070Smarcel if (idx > 0) 294184070Smarcel snprintf(buf + idx, sizeof(buf) - idx, "] "); 295179854Smarcel return (buf); 296179854Smarcel} 297179854Smarcel 298222264Sae#define ALIGNDOWN(d, a) ((d) - (d) % (a)) 299222263Sae#define ALIGNUP(d, a) ((d) % (a) ? (d) - (d) % (a) + (a): (d)) 300221363Sae 301193673Smarcelstatic int 302207095Smarcelgpart_autofill_resize(struct gctl_req *req) 303207095Smarcel{ 304207095Smarcel struct gmesh mesh; 305207095Smarcel struct gclass *cp; 306207095Smarcel struct ggeom *gp; 307207095Smarcel struct gprovider *pp; 308209388Sae off_t last, size, start, new_size; 309222630Sae off_t lba, new_lba, alignment, offset; 310207095Smarcel const char *s; 311225445Sae int error, idx, has_alignment; 312207095Smarcel 313212708Spjd idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 314212708Spjd if (idx < 1) 315207095Smarcel errx(EXIT_FAILURE, "invalid partition index"); 316207095Smarcel 317207095Smarcel error = geom_gettree(&mesh); 318207095Smarcel if (error) 319207095Smarcel return (error); 320207095Smarcel s = gctl_get_ascii(req, "class"); 321207095Smarcel if (s == NULL) 322207095Smarcel abort(); 323207095Smarcel cp = find_class(&mesh, s); 324207095Smarcel if (cp == NULL) 325207095Smarcel errx(EXIT_FAILURE, "Class %s not found.", s); 326212613Spjd s = gctl_get_ascii(req, "arg0"); 327207095Smarcel if (s == NULL) 328207095Smarcel abort(); 329207095Smarcel gp = find_geom(cp, s); 330207095Smarcel if (gp == NULL) 331207095Smarcel errx(EXIT_FAILURE, "No such geom: %s.", s); 332209388Sae pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 333209388Sae if (pp == NULL) 334209388Sae errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 335207095Smarcel 336221363Sae s = gctl_get_ascii(req, "alignment"); 337225445Sae has_alignment = (*s == '*') ? 0 : 1; 338221363Sae alignment = 1; 339225445Sae if (has_alignment) { 340221363Sae error = g_parse_lba(s, pp->lg_sectorsize, &alignment); 341221363Sae if (error) 342221363Sae errc(EXIT_FAILURE, error, "Invalid alignment param"); 343221363Sae if (alignment == 0) 344221363Sae errx(EXIT_FAILURE, "Invalid alignment param"); 345222819Sae } else { 346222630Sae lba = pp->lg_stripesize / pp->lg_sectorsize; 347222631Sae if (lba > 0) 348222819Sae alignment = lba; 349221363Sae } 350221363Sae error = gctl_delete_param(req, "alignment"); 351221363Sae if (error) 352221363Sae errc(EXIT_FAILURE, error, "internal error"); 353221363Sae 354209388Sae s = gctl_get_ascii(req, "size"); 355209388Sae if (*s == '*') 356209388Sae new_size = 0; 357209388Sae else { 358209388Sae error = g_parse_lba(s, pp->lg_sectorsize, &new_size); 359209388Sae if (error) 360209388Sae errc(EXIT_FAILURE, error, "Invalid size param"); 361209388Sae /* no autofill necessary. */ 362225445Sae if (has_alignment == 0) 363221363Sae goto done; 364209388Sae } 365209388Sae 366223356Sdelphij offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; 367209388Sae last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); 368207095Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 369207095Smarcel s = find_provcfg(pp, "index"); 370207095Smarcel if (s == NULL) 371207095Smarcel continue; 372207095Smarcel if (atoi(s) == idx) 373207095Smarcel break; 374207095Smarcel } 375207095Smarcel if (pp == NULL) 376207095Smarcel errx(EXIT_FAILURE, "invalid partition index"); 377207095Smarcel 378207095Smarcel s = find_provcfg(pp, "start"); 379221952Sae start = (off_t)strtoimax(s, NULL, 0); 380207095Smarcel s = find_provcfg(pp, "end"); 381222630Sae lba = (off_t)strtoimax(s, NULL, 0); 382222630Sae size = lba - start + 1; 383207095Smarcel 384225445Sae pp = find_provider(gp, lba + 1); 385225445Sae if (new_size > 0 && (new_size <= size || pp == NULL)) { 386222630Sae /* The start offset may be not aligned, so we align the end 387222630Sae * offset and then calculate the size. 388222630Sae */ 389222630Sae new_size = ALIGNDOWN(start + offset + new_size, 390222630Sae alignment) - start - offset; 391222630Sae goto done; 392209388Sae } 393222630Sae if (pp == NULL) { 394222630Sae new_size = ALIGNDOWN(last + offset + 1, alignment) - 395222630Sae start - offset; 396222630Sae if (new_size < size) 397222630Sae return (ENOSPC); 398222630Sae } else { 399207095Smarcel s = find_provcfg(pp, "start"); 400221952Sae new_lba = (off_t)strtoimax(s, NULL, 0); 401209388Sae /* 402209388Sae * Is there any free space between current and 403207095Smarcel * next providers? 404207095Smarcel */ 405222630Sae new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset; 406207095Smarcel if (new_lba > lba) 407207095Smarcel new_size = new_lba - start; 408209388Sae else { 409209388Sae geom_deletetree(&mesh); 410207095Smarcel return (ENOSPC); 411209388Sae } 412207095Smarcel } 413209388Saedone: 414209388Sae snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size); 415209388Sae gctl_change_param(req, "size", -1, ssize); 416209388Sae geom_deletetree(&mesh); 417207095Smarcel return (0); 418207095Smarcel} 419207095Smarcel 420207095Smarcelstatic int 421193673Smarcelgpart_autofill(struct gctl_req *req) 422193673Smarcel{ 423193673Smarcel struct gmesh mesh; 424193673Smarcel struct gclass *cp; 425193673Smarcel struct ggeom *gp; 426193673Smarcel struct gprovider *pp; 427221363Sae off_t first, last, a_first; 428221363Sae off_t size, start, a_lba; 429221967Sae off_t lba, len, alignment, offset; 430209388Sae uintmax_t grade; 431193673Smarcel const char *s; 432221363Sae int error, has_size, has_start, has_alignment; 433193673Smarcel 434193673Smarcel s = gctl_get_ascii(req, "verb"); 435207095Smarcel if (strcmp(s, "resize") == 0) 436207095Smarcel return gpart_autofill_resize(req); 437193673Smarcel if (strcmp(s, "add") != 0) 438193673Smarcel return (0); 439193673Smarcel 440193673Smarcel error = geom_gettree(&mesh); 441193673Smarcel if (error) 442193673Smarcel return (error); 443196278Smarcel s = gctl_get_ascii(req, "class"); 444196278Smarcel if (s == NULL) 445196278Smarcel abort(); 446196278Smarcel cp = find_class(&mesh, s); 447196278Smarcel if (cp == NULL) 448196278Smarcel errx(EXIT_FAILURE, "Class %s not found.", s); 449212613Spjd s = gctl_get_ascii(req, "arg0"); 450196278Smarcel if (s == NULL) 451196278Smarcel abort(); 452196278Smarcel gp = find_geom(cp, s); 453196278Smarcel if (gp == NULL) 454196278Smarcel errx(EXIT_FAILURE, "No such geom: %s.", s); 455209388Sae pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 456209388Sae if (pp == NULL) 457209388Sae errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 458209388Sae 459221363Sae s = gctl_get_ascii(req, "alignment"); 460221363Sae has_alignment = (*s == '*') ? 0 : 1; 461221363Sae alignment = 1; 462221363Sae if (has_alignment) { 463221363Sae error = g_parse_lba(s, pp->lg_sectorsize, &alignment); 464221363Sae if (error) 465221363Sae errc(EXIT_FAILURE, error, "Invalid alignment param"); 466221363Sae if (alignment == 0) 467221363Sae errx(EXIT_FAILURE, "Invalid alignment param"); 468221363Sae } 469221363Sae error = gctl_delete_param(req, "alignment"); 470221363Sae if (error) 471221363Sae errc(EXIT_FAILURE, error, "internal error"); 472221363Sae 473209388Sae s = gctl_get_ascii(req, "size"); 474209388Sae has_size = (*s == '*') ? 0 : 1; 475209388Sae size = 0; 476209388Sae if (has_size) { 477209388Sae error = g_parse_lba(s, pp->lg_sectorsize, &size); 478209388Sae if (error) 479209388Sae errc(EXIT_FAILURE, error, "Invalid size param"); 480209388Sae } 481209388Sae 482209388Sae s = gctl_get_ascii(req, "start"); 483209388Sae has_start = (*s == '*') ? 0 : 1; 484209388Sae start = 0ULL; 485209388Sae if (has_start) { 486209388Sae error = g_parse_lba(s, pp->lg_sectorsize, &start); 487209388Sae if (error) 488209388Sae errc(EXIT_FAILURE, error, "Invalid start param"); 489209388Sae } 490209388Sae 491209388Sae /* No autofill necessary. */ 492221363Sae if (has_size && has_start && !has_alignment) 493209388Sae goto done; 494209388Sae 495222630Sae len = pp->lg_stripesize / pp->lg_sectorsize; 496222819Sae if (len > 0 && !has_alignment) 497222819Sae alignment = len; 498222630Sae 499222630Sae /* Adjust parameters to stripeoffset */ 500223356Sdelphij offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; 501221967Sae start = ALIGNUP(start + offset, alignment); 502223355Sae if (size > alignment) 503223355Sae size = ALIGNDOWN(size, alignment); 504221967Sae 505209388Sae first = (off_t)strtoimax(find_geomcfg(gp, "first"), NULL, 0); 506209388Sae last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); 507193673Smarcel grade = ~0ULL; 508221967Sae a_first = ALIGNUP(first + offset, alignment); 509221967Sae last = ALIGNDOWN(last + offset, alignment); 510235033Sae if (a_first < start) 511235033Sae a_first = start; 512193673Smarcel while ((pp = find_provider(gp, first)) != NULL) { 513193673Smarcel s = find_provcfg(pp, "start"); 514221952Sae lba = (off_t)strtoimax(s, NULL, 0); 515221967Sae a_lba = ALIGNDOWN(lba + offset, alignment); 516221363Sae if (first < a_lba && a_first < a_lba) { 517193673Smarcel /* Free space [first, lba> */ 518221363Sae len = a_lba - a_first; 519193673Smarcel if (has_size) { 520209388Sae if (len >= size && 521209388Sae (uintmax_t)(len - size) < grade) { 522221363Sae start = a_first; 523193673Smarcel grade = len - size; 524193673Smarcel } 525193673Smarcel } else if (has_start) { 526221363Sae if (start >= a_first && start < a_lba) { 527221363Sae size = a_lba - start; 528221363Sae grade = start - a_first; 529193673Smarcel } 530193673Smarcel } else { 531193673Smarcel if (grade == ~0ULL || len > size) { 532221363Sae start = a_first; 533193673Smarcel size = len; 534193673Smarcel grade = 0; 535193673Smarcel } 536193673Smarcel } 537193673Smarcel } 538193673Smarcel 539193673Smarcel s = find_provcfg(pp, "end"); 540221952Sae first = (off_t)strtoimax(s, NULL, 0) + 1; 541235033Sae if (first > a_first) 542235033Sae a_first = ALIGNUP(first + offset, alignment); 543193673Smarcel } 544221363Sae if (a_first <= last) { 545193673Smarcel /* Free space [first-last] */ 546221363Sae len = ALIGNDOWN(last - a_first + 1, alignment); 547193673Smarcel if (has_size) { 548209388Sae if (len >= size && 549209388Sae (uintmax_t)(len - size) < grade) { 550221363Sae start = a_first; 551193673Smarcel grade = len - size; 552193673Smarcel } 553193673Smarcel } else if (has_start) { 554221363Sae if (start >= a_first && start <= last) { 555221363Sae size = ALIGNDOWN(last - start + 1, alignment); 556221363Sae grade = start - a_first; 557193673Smarcel } 558193673Smarcel } else { 559193673Smarcel if (grade == ~0ULL || len > size) { 560221363Sae start = a_first; 561193673Smarcel size = len; 562193673Smarcel grade = 0; 563193673Smarcel } 564193673Smarcel } 565193673Smarcel } 566209388Sae if (grade == ~0ULL) { 567209388Sae geom_deletetree(&mesh); 568193673Smarcel return (ENOSPC); 569209388Sae } 570221967Sae start -= offset; /* Return back to real offset */ 571209388Saedone: 572209388Sae snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size); 573209388Sae gctl_change_param(req, "size", -1, ssize); 574209388Sae snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start); 575209388Sae gctl_change_param(req, "start", -1, sstart); 576209388Sae geom_deletetree(&mesh); 577193673Smarcel return (0); 578193673Smarcel} 579193673Smarcel 580172837Smarcelstatic void 581219415Saegpart_show_geom(struct ggeom *gp, const char *element, int show_providers) 582172837Smarcel{ 583172837Smarcel struct gprovider *pp; 584172837Smarcel const char *s, *scheme; 585209388Sae off_t first, last, sector, end; 586209388Sae off_t length, secsz; 587219415Sae int idx, wblocks, wname, wmax; 588172837Smarcel 589172837Smarcel scheme = find_geomcfg(gp, "scheme"); 590172837Smarcel s = find_geomcfg(gp, "first"); 591209388Sae first = (off_t)strtoimax(s, NULL, 0); 592172837Smarcel s = find_geomcfg(gp, "last"); 593209388Sae last = (off_t)strtoimax(s, NULL, 0); 594172837Smarcel wblocks = strlen(s); 595214352Sae s = find_geomcfg(gp, "state"); 596214352Sae if (s != NULL && *s != 'C') 597214352Sae s = NULL; 598219415Sae wmax = strlen(gp->lg_name); 599219415Sae if (show_providers) { 600219415Sae LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 601219415Sae wname = strlen(pp->lg_name); 602219415Sae if (wname > wmax) 603219415Sae wmax = wname; 604219415Sae } 605219415Sae } 606219415Sae wname = wmax; 607172837Smarcel pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 608172837Smarcel secsz = pp->lg_sectorsize; 609214352Sae printf("=>%*jd %*jd %*s %s (%s)%s\n", 610209388Sae wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1), 611172837Smarcel wname, gp->lg_name, 612214352Sae scheme, fmtsize(pp->lg_mediasize), 613214352Sae s ? " [CORRUPT]": ""); 614172837Smarcel 615172837Smarcel while ((pp = find_provider(gp, first)) != NULL) { 616188330Smarcel s = find_provcfg(pp, "start"); 617221952Sae sector = (off_t)strtoimax(s, NULL, 0); 618188330Smarcel 619188330Smarcel s = find_provcfg(pp, "end"); 620221952Sae end = (off_t)strtoimax(s, NULL, 0); 621221952Sae length = end - sector + 1; 622221952Sae 623172837Smarcel s = find_provcfg(pp, "index"); 624172837Smarcel idx = atoi(s); 625172837Smarcel if (first < sector) { 626209388Sae printf(" %*jd %*jd %*s - free - (%s)\n", 627209388Sae wblocks, (intmax_t)first, wblocks, 628209388Sae (intmax_t)(sector - first), wname, "", 629172837Smarcel fmtsize((sector - first) * secsz)); 630172837Smarcel } 631219415Sae if (show_providers) { 632219415Sae printf(" %*jd %*jd %*s %s %s (%s)\n", 633219415Sae wblocks, (intmax_t)sector, wblocks, 634219415Sae (intmax_t)length, wname, pp->lg_name, 635219415Sae find_provcfg(pp, element), fmtattrib(pp), 636219415Sae fmtsize(pp->lg_mediasize)); 637219415Sae } else 638219415Sae printf(" %*jd %*jd %*d %s %s (%s)\n", 639219415Sae wblocks, (intmax_t)sector, wblocks, 640219415Sae (intmax_t)length, wname, idx, 641219415Sae find_provcfg(pp, element), fmtattrib(pp), 642219415Sae fmtsize(pp->lg_mediasize)); 643188330Smarcel first = end + 1; 644172837Smarcel } 645172837Smarcel if (first <= last) { 646188330Smarcel length = last - first + 1; 647209388Sae printf(" %*jd %*jd %*s - free - (%s)\n", 648209388Sae wblocks, (intmax_t)first, wblocks, (intmax_t)length, 649172837Smarcel wname, "", 650188330Smarcel fmtsize(length * secsz)); 651172837Smarcel } 652172837Smarcel printf("\n"); 653172837Smarcel} 654172837Smarcel 655179769Smarcelstatic int 656179769Smarcelgpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 657179769Smarcel{ 658179769Smarcel 659215704Sbrucec if (!gctl_get_int(req, "%s", opt)) 660179769Smarcel return (0); 661179769Smarcel 662179769Smarcel if (elt != NULL) 663179769Smarcel errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 664179769Smarcel 665179769Smarcel return (1); 666179769Smarcel} 667179769Smarcel 668172837Smarcelstatic void 669178180Smarcelgpart_show(struct gctl_req *req, unsigned int fl __unused) 670172837Smarcel{ 671172837Smarcel struct gmesh mesh; 672172837Smarcel struct gclass *classp; 673172837Smarcel struct ggeom *gp; 674179769Smarcel const char *element, *name; 675219415Sae int error, i, nargs, show_providers; 676172837Smarcel 677179769Smarcel element = NULL; 678179769Smarcel if (gpart_show_hasopt(req, "show_label", element)) 679179769Smarcel element = "label"; 680179769Smarcel if (gpart_show_hasopt(req, "show_rawtype", element)) 681179769Smarcel element = "rawtype"; 682179769Smarcel if (element == NULL) 683179769Smarcel element = "type"; 684179769Smarcel 685172837Smarcel name = gctl_get_ascii(req, "class"); 686172837Smarcel if (name == NULL) 687172837Smarcel abort(); 688172837Smarcel error = geom_gettree(&mesh); 689172837Smarcel if (error != 0) 690172837Smarcel errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 691172837Smarcel classp = find_class(&mesh, name); 692172837Smarcel if (classp == NULL) { 693172837Smarcel geom_deletetree(&mesh); 694172837Smarcel errx(EXIT_FAILURE, "Class %s not found.", name); 695172837Smarcel } 696219415Sae show_providers = gctl_get_int(req, "show_providers"); 697172837Smarcel nargs = gctl_get_int(req, "nargs"); 698172837Smarcel if (nargs > 0) { 699172837Smarcel for (i = 0; i < nargs; i++) { 700172837Smarcel name = gctl_get_ascii(req, "arg%d", i); 701172837Smarcel gp = find_geom(classp, name); 702172837Smarcel if (gp != NULL) 703219415Sae gpart_show_geom(gp, element, show_providers); 704172837Smarcel else 705172837Smarcel errx(EXIT_FAILURE, "No such geom: %s.", name); 706172837Smarcel } 707172837Smarcel } else { 708172837Smarcel LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 709219415Sae gpart_show_geom(gp, element, show_providers); 710172837Smarcel } 711172837Smarcel } 712172837Smarcel geom_deletetree(&mesh); 713172837Smarcel} 714178180Smarcel 715215570Saestatic void 716215570Saegpart_backup(struct gctl_req *req, unsigned int fl __unused) 717215570Sae{ 718215570Sae struct gmesh mesh; 719215570Sae struct gclass *classp; 720215570Sae struct gprovider *pp; 721215570Sae struct ggeom *gp; 722215570Sae const char *s, *scheme; 723215570Sae off_t sector, end; 724229916Seadler off_t length; 725215671Sae int error, i, windex, wblocks, wtype; 726215570Sae 727215570Sae if (gctl_get_int(req, "nargs") != 1) 728215570Sae errx(EXIT_FAILURE, "Invalid number of arguments."); 729215570Sae error = geom_gettree(&mesh); 730215570Sae if (error != 0) 731215570Sae errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 732215570Sae s = gctl_get_ascii(req, "class"); 733215570Sae if (s == NULL) 734215570Sae abort(); 735215570Sae classp = find_class(&mesh, s); 736215570Sae if (classp == NULL) { 737215570Sae geom_deletetree(&mesh); 738215570Sae errx(EXIT_FAILURE, "Class %s not found.", s); 739215570Sae } 740215570Sae s = gctl_get_ascii(req, "arg0"); 741215570Sae if (s == NULL) 742215570Sae abort(); 743215570Sae gp = find_geom(classp, s); 744215570Sae if (gp == NULL) 745215570Sae errx(EXIT_FAILURE, "No such geom: %s.", s); 746215570Sae scheme = find_geomcfg(gp, "scheme"); 747215570Sae if (scheme == NULL) 748215570Sae abort(); 749215570Sae pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 750215570Sae s = find_geomcfg(gp, "last"); 751215570Sae wblocks = strlen(s); 752215570Sae wtype = 0; 753215570Sae LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 754215570Sae s = find_provcfg(pp, "type"); 755215570Sae i = strlen(s); 756215570Sae if (i > wtype) 757215570Sae wtype = i; 758215570Sae } 759215570Sae s = find_geomcfg(gp, "entries"); 760215570Sae windex = strlen(s); 761215570Sae printf("%s %s\n", scheme, s); 762215570Sae LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 763215570Sae s = find_provcfg(pp, "start"); 764221952Sae sector = (off_t)strtoimax(s, NULL, 0); 765215570Sae 766215570Sae s = find_provcfg(pp, "end"); 767221952Sae end = (off_t)strtoimax(s, NULL, 0); 768221952Sae length = end - sector + 1; 769221952Sae 770215570Sae s = find_provcfg(pp, "label"); 771215671Sae printf("%-*s %*s %*jd %*jd %s %s\n", 772215570Sae windex, find_provcfg(pp, "index"), 773215570Sae wtype, find_provcfg(pp, "type"), 774215570Sae wblocks, (intmax_t)sector, 775215671Sae wblocks, (intmax_t)length, 776215671Sae (s != NULL) ? s: "", fmtattrib(pp)); 777215570Sae } 778215570Sae geom_deletetree(&mesh); 779215570Sae} 780215570Sae 781215570Saestatic int 782215570Saeskip_line(const char *p) 783215570Sae{ 784215570Sae 785215570Sae while (*p != '\0') { 786215570Sae if (*p == '#') 787215570Sae return (1); 788215570Sae if (isspace(*p) == 0) 789215570Sae return (0); 790215570Sae p++; 791215570Sae } 792215570Sae return (1); 793215570Sae} 794215570Sae 795215570Saestatic void 796215672Saegpart_sighndl(int sig __unused) 797215672Sae{ 798215672Sae undo_restore = 1; 799215672Sae} 800215672Sae 801215672Saestatic void 802215570Saegpart_restore(struct gctl_req *req, unsigned int fl __unused) 803215570Sae{ 804215570Sae struct gmesh mesh; 805215570Sae struct gclass *classp; 806215570Sae struct gctl_req *r; 807215570Sae struct ggeom *gp; 808215672Sae struct sigaction si_sa; 809215570Sae const char *s, *flags, *errstr, *label; 810215570Sae char **ap, *argv[6], line[BUFSIZ], *pline; 811215671Sae int error, forced, i, l, nargs, created, rl; 812215570Sae intmax_t n; 813215570Sae 814215570Sae nargs = gctl_get_int(req, "nargs"); 815215570Sae if (nargs < 1) 816215570Sae errx(EXIT_FAILURE, "Invalid number of arguments."); 817215570Sae 818215570Sae forced = gctl_get_int(req, "force"); 819215570Sae flags = gctl_get_ascii(req, "flags"); 820215671Sae rl = gctl_get_int(req, "restore_labels"); 821215570Sae s = gctl_get_ascii(req, "class"); 822215570Sae if (s == NULL) 823215570Sae abort(); 824215570Sae error = geom_gettree(&mesh); 825215570Sae if (error != 0) 826215570Sae errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 827215570Sae classp = find_class(&mesh, s); 828215570Sae if (classp == NULL) { 829215570Sae geom_deletetree(&mesh); 830215570Sae errx(EXIT_FAILURE, "Class %s not found.", s); 831215570Sae } 832215672Sae 833215672Sae sigemptyset(&si_sa.sa_mask); 834215672Sae si_sa.sa_flags = 0; 835215672Sae si_sa.sa_handler = gpart_sighndl; 836215672Sae if (sigaction(SIGINT, &si_sa, 0) == -1) 837215672Sae err(EXIT_FAILURE, "sigaction SIGINT"); 838215672Sae 839215570Sae if (forced) { 840215570Sae /* destroy existent partition table before restore */ 841215570Sae for (i = 0; i < nargs; i++) { 842215570Sae s = gctl_get_ascii(req, "arg%d", i); 843215570Sae gp = find_geom(classp, s); 844215570Sae if (gp != NULL) { 845215570Sae r = gctl_get_handle(); 846215570Sae gctl_ro_param(r, "class", -1, 847215570Sae classp->lg_name); 848215570Sae gctl_ro_param(r, "verb", -1, "destroy"); 849215570Sae gctl_ro_param(r, "flags", -1, "restore"); 850215570Sae gctl_ro_param(r, "force", sizeof(forced), 851215570Sae &forced); 852215570Sae gctl_ro_param(r, "arg0", -1, s); 853215570Sae errstr = gctl_issue(r); 854215570Sae if (errstr != NULL && errstr[0] != '\0') { 855215570Sae gpart_print_error(errstr); 856215570Sae gctl_free(r); 857215570Sae goto backout; 858215570Sae } 859215570Sae gctl_free(r); 860215570Sae } 861215570Sae } 862215570Sae } 863215570Sae created = 0; 864215672Sae while (undo_restore == 0 && 865215672Sae fgets(line, sizeof(line) - 1, stdin) != NULL) { 866215570Sae /* Format of backup entries: 867215570Sae * <scheme name> <number of entries> 868215570Sae * <index> <type> <start> <size> [label] ['['attrib[,attrib]']'] 869215570Sae */ 870215570Sae pline = (char *)line; 871215570Sae pline[strlen(line) - 1] = 0; 872215570Sae if (skip_line(pline)) 873215570Sae continue; 874215570Sae for (ap = argv; 875215570Sae (*ap = strsep(&pline, " \t")) != NULL;) 876215570Sae if (**ap != '\0' && ++ap >= &argv[6]) 877215570Sae break; 878215570Sae l = ap - &argv[0]; 879215570Sae label = pline = NULL; 880215671Sae if (l == 1 || l == 2) { /* create table */ 881215570Sae if (created) 882215570Sae errx(EXIT_FAILURE, "Incorrect backup format."); 883215671Sae if (l == 2) 884215671Sae n = strtoimax(argv[1], NULL, 0); 885215570Sae for (i = 0; i < nargs; i++) { 886215570Sae s = gctl_get_ascii(req, "arg%d", i); 887215570Sae r = gctl_get_handle(); 888215570Sae gctl_ro_param(r, "class", -1, 889215570Sae classp->lg_name); 890215570Sae gctl_ro_param(r, "verb", -1, "create"); 891215570Sae gctl_ro_param(r, "scheme", -1, argv[0]); 892215671Sae if (l == 2) 893215671Sae gctl_ro_param(r, "entries", 894215671Sae sizeof(n), &n); 895215570Sae gctl_ro_param(r, "flags", -1, "restore"); 896215570Sae gctl_ro_param(r, "arg0", -1, s); 897215570Sae errstr = gctl_issue(r); 898215570Sae if (errstr != NULL && errstr[0] != '\0') { 899215570Sae gpart_print_error(errstr); 900215570Sae gctl_free(r); 901215570Sae goto backout; 902215570Sae } 903215570Sae gctl_free(r); 904215570Sae } 905215570Sae created = 1; 906215570Sae continue; 907215570Sae } else if (l < 4 || created == 0) 908215570Sae errx(EXIT_FAILURE, "Incorrect backup format."); 909215570Sae else if (l == 5) { 910215570Sae if (strchr(argv[4], '[') == NULL) 911215570Sae label = argv[4]; 912215570Sae else 913215570Sae pline = argv[4]; 914215570Sae } else if (l == 6) { 915215570Sae label = argv[4]; 916215570Sae pline = argv[5]; 917215570Sae } 918215570Sae /* Add partitions to each table */ 919215570Sae for (i = 0; i < nargs; i++) { 920215570Sae s = gctl_get_ascii(req, "arg%d", i); 921215570Sae r = gctl_get_handle(); 922215570Sae n = strtoimax(argv[0], NULL, 0); 923215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 924215570Sae gctl_ro_param(r, "verb", -1, "add"); 925215570Sae gctl_ro_param(r, "flags", -1, "restore"); 926215570Sae gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n); 927215570Sae gctl_ro_param(r, "type", -1, argv[1]); 928215570Sae gctl_ro_param(r, "start", -1, argv[2]); 929215570Sae gctl_ro_param(r, "size", -1, argv[3]); 930215671Sae if (rl != 0 && label != NULL) 931215570Sae gctl_ro_param(r, "label", -1, argv[4]); 932223158Sae gctl_ro_param(r, "alignment", -1, GPART_AUTOFILL); 933215570Sae gctl_ro_param(r, "arg0", -1, s); 934215570Sae error = gpart_autofill(r); 935215570Sae if (error != 0) 936215570Sae errc(EXIT_FAILURE, error, "autofill"); 937215570Sae errstr = gctl_issue(r); 938215570Sae if (errstr != NULL && errstr[0] != '\0') { 939215570Sae gpart_print_error(errstr); 940215570Sae gctl_free(r); 941215570Sae goto backout; 942215570Sae } 943215570Sae gctl_free(r); 944215570Sae } 945215570Sae if (pline == NULL || *pline != '[') 946215570Sae continue; 947215570Sae /* set attributes */ 948215570Sae pline++; 949215570Sae for (ap = argv; 950215570Sae (*ap = strsep(&pline, ",]")) != NULL;) 951215570Sae if (**ap != '\0' && ++ap >= &argv[6]) 952215570Sae break; 953215570Sae for (i = 0; i < nargs; i++) { 954215570Sae l = ap - &argv[0]; 955215570Sae s = gctl_get_ascii(req, "arg%d", i); 956215570Sae while (l > 0) { 957215570Sae r = gctl_get_handle(); 958215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 959215570Sae gctl_ro_param(r, "verb", -1, "set"); 960215570Sae gctl_ro_param(r, "flags", -1, "restore"); 961215570Sae gctl_ro_param(r, GPART_PARAM_INDEX, 962215570Sae sizeof(n), &n); 963215570Sae gctl_ro_param(r, "attrib", -1, argv[--l]); 964215570Sae gctl_ro_param(r, "arg0", -1, s); 965215570Sae errstr = gctl_issue(r); 966215570Sae if (errstr != NULL && errstr[0] != '\0') { 967215570Sae gpart_print_error(errstr); 968215570Sae gctl_free(r); 969215570Sae goto backout; 970215570Sae } 971215570Sae gctl_free(r); 972215570Sae } 973215570Sae } 974215570Sae } 975215672Sae if (undo_restore) 976215672Sae goto backout; 977215570Sae /* commit changes if needed */ 978215570Sae if (strchr(flags, 'C') != NULL) { 979215570Sae for (i = 0; i < nargs; i++) { 980215570Sae s = gctl_get_ascii(req, "arg%d", i); 981215570Sae r = gctl_get_handle(); 982215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 983215570Sae gctl_ro_param(r, "verb", -1, "commit"); 984215570Sae gctl_ro_param(r, "arg0", -1, s); 985215570Sae errstr = gctl_issue(r); 986215570Sae if (errstr != NULL && errstr[0] != '\0') { 987215570Sae gpart_print_error(errstr); 988215570Sae gctl_free(r); 989215570Sae goto backout; 990215570Sae } 991215570Sae gctl_free(r); 992215570Sae } 993215570Sae } 994215570Sae gctl_free(req); 995215570Sae geom_deletetree(&mesh); 996215570Sae exit(EXIT_SUCCESS); 997215570Sae 998215570Saebackout: 999215570Sae for (i = 0; i < nargs; i++) { 1000215570Sae s = gctl_get_ascii(req, "arg%d", i); 1001215570Sae r = gctl_get_handle(); 1002215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 1003215570Sae gctl_ro_param(r, "verb", -1, "undo"); 1004215570Sae gctl_ro_param(r, "arg0", -1, s); 1005215570Sae gctl_issue(r); 1006215570Sae gctl_free(r); 1007215570Sae } 1008215570Sae gctl_free(req); 1009215570Sae geom_deletetree(&mesh); 1010215570Sae exit(EXIT_FAILURE); 1011215570Sae} 1012215570Sae 1013179629Smarcelstatic void * 1014179629Smarcelgpart_bootfile_read(const char *bootfile, ssize_t *size) 1015178180Smarcel{ 1016178180Smarcel struct stat sb; 1017178180Smarcel void *code; 1018179629Smarcel int fd; 1019178180Smarcel 1020179629Smarcel if (stat(bootfile, &sb) == -1) 1021179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 1022178180Smarcel if (!S_ISREG(sb.st_mode)) 1023178180Smarcel errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 1024179629Smarcel if (sb.st_size == 0) 1025179629Smarcel errx(EXIT_FAILURE, "%s: empty file", bootfile); 1026208777Smarius if (*size > 0 && sb.st_size > *size) 1027179629Smarcel errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 1028179629Smarcel *size); 1029178180Smarcel 1030179629Smarcel *size = sb.st_size; 1031178180Smarcel 1032178180Smarcel fd = open(bootfile, O_RDONLY); 1033178180Smarcel if (fd == -1) 1034179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 1035179629Smarcel code = malloc(*size); 1036178180Smarcel if (code == NULL) 1037179629Smarcel err(EXIT_FAILURE, NULL); 1038179629Smarcel if (read(fd, code, *size) != *size) 1039179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 1040178180Smarcel close(fd); 1041178180Smarcel 1042179629Smarcel return (code); 1043178180Smarcel} 1044179629Smarcel 1045179629Smarcelstatic void 1046208777Smariusgpart_write_partcode(struct ggeom *gp, int idx, void *code, ssize_t size) 1047179629Smarcel{ 1048179629Smarcel char dsf[128]; 1049179629Smarcel struct gprovider *pp; 1050179629Smarcel const char *s; 1051185038Smarcel char *buf; 1052185038Smarcel off_t bsize; 1053208777Smarius int fd; 1054179629Smarcel 1055179629Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1056179629Smarcel s = find_provcfg(pp, "index"); 1057179629Smarcel if (s == NULL) 1058179629Smarcel continue; 1059179629Smarcel if (atoi(s) == idx) 1060179629Smarcel break; 1061179629Smarcel } 1062179629Smarcel 1063179629Smarcel if (pp != NULL) { 1064179629Smarcel snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1065179629Smarcel fd = open(dsf, O_WRONLY); 1066179629Smarcel if (fd == -1) 1067179629Smarcel err(EXIT_FAILURE, "%s", dsf); 1068179629Smarcel if (lseek(fd, size, SEEK_SET) != size) 1069179629Smarcel errx(EXIT_FAILURE, "%s: not enough space", dsf); 1070179629Smarcel if (lseek(fd, 0, SEEK_SET) != 0) 1071179629Smarcel err(EXIT_FAILURE, "%s", dsf); 1072185038Smarcel 1073185038Smarcel /* 1074185038Smarcel * When writing to a disk device, the write must be 1075185038Smarcel * sector aligned and not write to any partial sectors, 1076185038Smarcel * so round up the buffer size to the next sector and zero it. 1077185038Smarcel */ 1078185038Smarcel bsize = (size + pp->lg_sectorsize - 1) / 1079185038Smarcel pp->lg_sectorsize * pp->lg_sectorsize; 1080185038Smarcel buf = calloc(1, bsize); 1081185038Smarcel if (buf == NULL) 1082179629Smarcel err(EXIT_FAILURE, "%s", dsf); 1083185038Smarcel bcopy(code, buf, size); 1084185038Smarcel if (write(fd, buf, bsize) != bsize) 1085185038Smarcel err(EXIT_FAILURE, "%s", dsf); 1086185038Smarcel free(buf); 1087179629Smarcel close(fd); 1088179629Smarcel } else 1089179629Smarcel errx(EXIT_FAILURE, "invalid partition index"); 1090208777Smarius} 1091179629Smarcel 1092208777Smariusstatic void 1093208777Smariusgpart_write_partcode_vtoc8(struct ggeom *gp, int idx, void *code) 1094208777Smarius{ 1095208777Smarius char dsf[128]; 1096208777Smarius struct gprovider *pp; 1097208777Smarius const char *s; 1098208777Smarius int installed, fd; 1099208777Smarius 1100208777Smarius installed = 0; 1101208777Smarius LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1102208777Smarius s = find_provcfg(pp, "index"); 1103208777Smarius if (s == NULL) 1104208777Smarius continue; 1105208777Smarius if (idx != 0 && atoi(s) != idx) 1106208777Smarius continue; 1107208777Smarius snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1108208777Smarius if (pp->lg_sectorsize != sizeof(struct vtoc8)) 1109208777Smarius errx(EXIT_FAILURE, "%s: unexpected sector " 1110208777Smarius "size (%d)\n", dsf, pp->lg_sectorsize); 1111208777Smarius fd = open(dsf, O_WRONLY); 1112208777Smarius if (fd == -1) 1113208777Smarius err(EXIT_FAILURE, "%s", dsf); 1114208777Smarius if (lseek(fd, VTOC_BOOTSIZE, SEEK_SET) != VTOC_BOOTSIZE) 1115208777Smarius continue; 1116208777Smarius /* 1117208777Smarius * We ignore the first VTOC_BOOTSIZE bytes of boot code in 1118208777Smarius * order to avoid overwriting the label. 1119208777Smarius */ 1120208777Smarius if (lseek(fd, sizeof(struct vtoc8), SEEK_SET) != 1121208777Smarius sizeof(struct vtoc8)) 1122208777Smarius err(EXIT_FAILURE, "%s", dsf); 1123208777Smarius if (write(fd, (caddr_t)code + sizeof(struct vtoc8), 1124208777Smarius VTOC_BOOTSIZE - sizeof(struct vtoc8)) != VTOC_BOOTSIZE - 1125208777Smarius sizeof(struct vtoc8)) 1126208777Smarius err(EXIT_FAILURE, "%s", dsf); 1127208777Smarius installed++; 1128208777Smarius close(fd); 1129208777Smarius if (idx != 0 && atoi(s) == idx) 1130208777Smarius break; 1131208777Smarius } 1132208777Smarius if (installed == 0) 1133208777Smarius errx(EXIT_FAILURE, "%s: no partitions", gp->lg_name); 1134179629Smarcel} 1135179629Smarcel 1136179629Smarcelstatic void 1137185454Smarcelgpart_bootcode(struct gctl_req *req, unsigned int fl) 1138179629Smarcel{ 1139208777Smarius struct gmesh mesh; 1140208777Smarius struct gclass *classp; 1141208777Smarius struct ggeom *gp; 1142179629Smarcel const char *s; 1143179629Smarcel void *bootcode, *partcode; 1144179629Smarcel size_t bootsize, partsize; 1145208777Smarius int error, idx, vtoc8; 1146179629Smarcel 1147212554Spjd if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) { 1148212554Spjd s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE); 1149208173Snwhitehorn bootsize = 800 * 1024; /* Arbitrary limit. */ 1150179629Smarcel bootcode = gpart_bootfile_read(s, &bootsize); 1151212554Spjd error = gctl_change_param(req, GPART_PARAM_BOOTCODE, bootsize, 1152179629Smarcel bootcode); 1153179629Smarcel if (error) 1154179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 1155179629Smarcel } else { 1156179629Smarcel bootcode = NULL; 1157179629Smarcel bootsize = 0; 1158179629Smarcel } 1159179629Smarcel 1160208777Smarius s = gctl_get_ascii(req, "class"); 1161208777Smarius if (s == NULL) 1162208777Smarius abort(); 1163208777Smarius error = geom_gettree(&mesh); 1164208777Smarius if (error != 0) 1165208777Smarius errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 1166208777Smarius classp = find_class(&mesh, s); 1167208777Smarius if (classp == NULL) { 1168208777Smarius geom_deletetree(&mesh); 1169208777Smarius errx(EXIT_FAILURE, "Class %s not found.", s); 1170208777Smarius } 1171216619Sae if (gctl_get_int(req, "nargs") != 1) 1172216619Sae errx(EXIT_FAILURE, "Invalid number of arguments."); 1173212554Spjd s = gctl_get_ascii(req, "arg0"); 1174208777Smarius if (s == NULL) 1175208777Smarius abort(); 1176208777Smarius gp = find_geom(classp, s); 1177208777Smarius if (gp == NULL) 1178208777Smarius errx(EXIT_FAILURE, "No such geom: %s.", s); 1179208777Smarius s = find_geomcfg(gp, "scheme"); 1180208777Smarius vtoc8 = 0; 1181208777Smarius if (strcmp(s, "VTOC8") == 0) 1182208777Smarius vtoc8 = 1; 1183208777Smarius 1184212554Spjd if (gctl_has_param(req, GPART_PARAM_PARTCODE)) { 1185212554Spjd s = gctl_get_ascii(req, GPART_PARAM_PARTCODE); 1186208777Smarius partsize = vtoc8 != 0 ? VTOC_BOOTSIZE : bootsize * 1024; 1187179629Smarcel partcode = gpart_bootfile_read(s, &partsize); 1188212554Spjd error = gctl_delete_param(req, GPART_PARAM_PARTCODE); 1189179629Smarcel if (error) 1190179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 1191179629Smarcel } else { 1192179629Smarcel partcode = NULL; 1193179629Smarcel partsize = 0; 1194179629Smarcel } 1195179629Smarcel 1196212554Spjd if (gctl_has_param(req, GPART_PARAM_INDEX)) { 1197179629Smarcel if (partcode == NULL) 1198179629Smarcel errx(EXIT_FAILURE, "-i is only valid with -p"); 1199212708Spjd idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 1200212708Spjd if (idx < 1) 1201179629Smarcel errx(EXIT_FAILURE, "invalid partition index"); 1202212554Spjd error = gctl_delete_param(req, GPART_PARAM_INDEX); 1203179629Smarcel if (error) 1204179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 1205179629Smarcel } else 1206179629Smarcel idx = 0; 1207179629Smarcel 1208179629Smarcel if (partcode != NULL) { 1209208777Smarius if (vtoc8 == 0) { 1210208777Smarius if (idx == 0) 1211208777Smarius errx(EXIT_FAILURE, "missing -i option"); 1212208777Smarius gpart_write_partcode(gp, idx, partcode, partsize); 1213223364Sae } else { 1214223364Sae if (partsize != VTOC_BOOTSIZE) 1215223364Sae errx(EXIT_FAILURE, "invalid bootcode"); 1216208777Smarius gpart_write_partcode_vtoc8(gp, idx, partcode); 1217223364Sae } 1218208777Smarius } else 1219179629Smarcel if (bootcode == NULL) 1220179629Smarcel errx(EXIT_FAILURE, "no -b nor -p"); 1221179629Smarcel 1222185454Smarcel if (bootcode != NULL) 1223185454Smarcel gpart_issue(req, fl); 1224208777Smarius 1225208777Smarius geom_deletetree(&mesh); 1226185454Smarcel} 1227185454Smarcel 1228185454Smarcelstatic void 1229213097Saegpart_print_error(const char *errstr) 1230213097Sae{ 1231213097Sae char *errmsg; 1232213097Sae int error; 1233213097Sae 1234213097Sae error = strtol(errstr, &errmsg, 0); 1235213097Sae if (errmsg != errstr) { 1236213097Sae while (errmsg[0] == ' ') 1237213097Sae errmsg++; 1238213097Sae if (errmsg[0] != '\0') 1239213097Sae warnc(error, "%s", errmsg); 1240213097Sae else 1241213097Sae warnc(error, NULL); 1242213097Sae } else 1243213097Sae warnx("%s", errmsg); 1244213097Sae} 1245213097Sae 1246213097Saestatic void 1247185454Smarcelgpart_issue(struct gctl_req *req, unsigned int fl __unused) 1248185454Smarcel{ 1249185454Smarcel char buf[4096]; 1250185454Smarcel const char *errstr; 1251185495Smarcel int error, status; 1252185454Smarcel 1253212554Spjd if (gctl_get_int(req, "nargs") != 1) 1254212554Spjd errx(EXIT_FAILURE, "Invalid number of arguments."); 1255212554Spjd (void)gctl_delete_param(req, "nargs"); 1256212554Spjd 1257193673Smarcel /* autofill parameters (if applicable). */ 1258193673Smarcel error = gpart_autofill(req); 1259193673Smarcel if (error) { 1260193673Smarcel warnc(error, "autofill"); 1261193673Smarcel status = EXIT_FAILURE; 1262193673Smarcel goto done; 1263193673Smarcel } 1264193673Smarcel 1265185454Smarcel bzero(buf, sizeof(buf)); 1266185454Smarcel gctl_rw_param(req, "output", sizeof(buf), buf); 1267185454Smarcel errstr = gctl_issue(req); 1268185454Smarcel if (errstr == NULL || errstr[0] == '\0') { 1269185454Smarcel if (buf[0] != '\0') 1270185454Smarcel printf("%s", buf); 1271185495Smarcel status = EXIT_SUCCESS; 1272185495Smarcel goto done; 1273179629Smarcel } 1274185454Smarcel 1275213097Sae gpart_print_error(errstr); 1276185495Smarcel status = EXIT_FAILURE; 1277185495Smarcel 1278185495Smarcel done: 1279185495Smarcel gctl_free(req); 1280185495Smarcel exit(status); 1281179629Smarcel} 1282