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: stable/10/sbin/geom/class/part/geom_part.c 319258 2017-05-30 22:33:24Z asomers $"); 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 *); 84319258Sasomersstatic _Noreturn 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{ 210281303Smav struct ggeom *gp, *wgp; 211172837Smarcel 212213662Sae if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 213213662Sae name += sizeof(_PATH_DEV) - 1; 214281303Smav wgp = NULL; 215172837Smarcel LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 216281303Smav if (strcmp(gp->lg_name, name) != 0) 217281303Smav continue; 218281303Smav if (find_geomcfg(gp, "wither") == NULL) 219172837Smarcel return (gp); 220281303Smav else 221281303Smav wgp = gp; 222172837Smarcel } 223281303Smav return (wgp); 224172837Smarcel} 225172837Smarcel 226172837Smarcelstatic const char * 227172837Smarcelfind_geomcfg(struct ggeom *gp, const char *cfg) 228172837Smarcel{ 229172837Smarcel struct gconfig *gc; 230172837Smarcel 231172837Smarcel LIST_FOREACH(gc, &gp->lg_config, lg_config) { 232172837Smarcel if (!strcmp(gc->lg_name, cfg)) 233172837Smarcel return (gc->lg_val); 234172837Smarcel } 235172837Smarcel return (NULL); 236172837Smarcel} 237172837Smarcel 238172837Smarcelstatic const char * 239172837Smarcelfind_provcfg(struct gprovider *pp, const char *cfg) 240172837Smarcel{ 241172837Smarcel struct gconfig *gc; 242172837Smarcel 243172837Smarcel LIST_FOREACH(gc, &pp->lg_config, lg_config) { 244172837Smarcel if (!strcmp(gc->lg_name, cfg)) 245172837Smarcel return (gc->lg_val); 246172837Smarcel } 247172837Smarcel return (NULL); 248172837Smarcel} 249172837Smarcel 250172837Smarcelstatic struct gprovider * 251209388Saefind_provider(struct ggeom *gp, off_t minsector) 252172837Smarcel{ 253172837Smarcel struct gprovider *pp, *bestpp; 254188330Smarcel const char *s; 255209388Sae off_t sector, bestsector; 256172837Smarcel 257172837Smarcel bestpp = NULL; 258198478Slulf bestsector = 0; 259172837Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 260188330Smarcel s = find_provcfg(pp, "start"); 261221952Sae sector = (off_t)strtoimax(s, NULL, 0); 262172837Smarcel if (sector < minsector) 263172837Smarcel continue; 264172837Smarcel if (bestpp != NULL && sector >= bestsector) 265172837Smarcel continue; 266188330Smarcel 267172837Smarcel bestpp = pp; 268172837Smarcel bestsector = sector; 269172837Smarcel } 270172837Smarcel return (bestpp); 271172837Smarcel} 272172837Smarcel 273172837Smarcelstatic const char * 274185046Smarcelfmtsize(int64_t rawsz) 275172837Smarcel{ 276185046Smarcel static char buf[5]; 277172837Smarcel 278185046Smarcel humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, 279185046Smarcel HN_B | HN_NOSPACE | HN_DECIMAL); 280172837Smarcel return (buf); 281172837Smarcel} 282172837Smarcel 283179854Smarcelstatic const char * 284179854Smarcelfmtattrib(struct gprovider *pp) 285179854Smarcel{ 286184070Smarcel static char buf[128]; 287184070Smarcel struct gconfig *gc; 288184070Smarcel u_int idx; 289179854Smarcel 290184070Smarcel buf[0] = '\0'; 291184070Smarcel idx = 0; 292184070Smarcel LIST_FOREACH(gc, &pp->lg_config, lg_config) { 293184070Smarcel if (strcmp(gc->lg_name, "attrib") != 0) 294184070Smarcel continue; 295184070Smarcel idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", 296184070Smarcel (idx == 0) ? " [" : ",", gc->lg_val); 297184070Smarcel } 298184070Smarcel if (idx > 0) 299184070Smarcel snprintf(buf + idx, sizeof(buf) - idx, "] "); 300179854Smarcel return (buf); 301179854Smarcel} 302179854Smarcel 303222264Sae#define ALIGNDOWN(d, a) ((d) - (d) % (a)) 304222263Sae#define ALIGNUP(d, a) ((d) % (a) ? (d) - (d) % (a) + (a): (d)) 305221363Sae 306193673Smarcelstatic int 307207095Smarcelgpart_autofill_resize(struct gctl_req *req) 308207095Smarcel{ 309207095Smarcel struct gmesh mesh; 310207095Smarcel struct gclass *cp; 311207095Smarcel struct ggeom *gp; 312207095Smarcel struct gprovider *pp; 313209388Sae off_t last, size, start, new_size; 314222630Sae off_t lba, new_lba, alignment, offset; 315207095Smarcel const char *s; 316225445Sae int error, idx, has_alignment; 317207095Smarcel 318212708Spjd idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 319212708Spjd if (idx < 1) 320207095Smarcel errx(EXIT_FAILURE, "invalid partition index"); 321207095Smarcel 322207095Smarcel error = geom_gettree(&mesh); 323207095Smarcel if (error) 324207095Smarcel return (error); 325207095Smarcel s = gctl_get_ascii(req, "class"); 326207095Smarcel if (s == NULL) 327207095Smarcel abort(); 328207095Smarcel cp = find_class(&mesh, s); 329207095Smarcel if (cp == NULL) 330207095Smarcel errx(EXIT_FAILURE, "Class %s not found.", s); 331212613Spjd s = gctl_get_ascii(req, "arg0"); 332207095Smarcel if (s == NULL) 333207095Smarcel abort(); 334207095Smarcel gp = find_geom(cp, s); 335207095Smarcel if (gp == NULL) 336207095Smarcel errx(EXIT_FAILURE, "No such geom: %s.", s); 337209388Sae pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 338209388Sae if (pp == NULL) 339209388Sae errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 340207095Smarcel 341221363Sae s = gctl_get_ascii(req, "alignment"); 342225445Sae has_alignment = (*s == '*') ? 0 : 1; 343221363Sae alignment = 1; 344225445Sae if (has_alignment) { 345221363Sae error = g_parse_lba(s, pp->lg_sectorsize, &alignment); 346221363Sae if (error) 347221363Sae errc(EXIT_FAILURE, error, "Invalid alignment param"); 348221363Sae if (alignment == 0) 349221363Sae errx(EXIT_FAILURE, "Invalid alignment param"); 350222819Sae } else { 351222630Sae lba = pp->lg_stripesize / pp->lg_sectorsize; 352222631Sae if (lba > 0) 353222819Sae alignment = lba; 354221363Sae } 355221363Sae error = gctl_delete_param(req, "alignment"); 356221363Sae if (error) 357221363Sae errc(EXIT_FAILURE, error, "internal error"); 358221363Sae 359209388Sae s = gctl_get_ascii(req, "size"); 360209388Sae if (*s == '*') 361209388Sae new_size = 0; 362209388Sae else { 363209388Sae error = g_parse_lba(s, pp->lg_sectorsize, &new_size); 364209388Sae if (error) 365209388Sae errc(EXIT_FAILURE, error, "Invalid size param"); 366209388Sae /* no autofill necessary. */ 367225445Sae if (has_alignment == 0) 368221363Sae goto done; 369209388Sae } 370209388Sae 371223356Sdelphij offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; 372259311Sasomers s = find_geomcfg(gp, "last"); 373259311Sasomers if (s == NULL) 374259311Sasomers errx(EXIT_FAILURE, "Final block not found for geom %s", 375259311Sasomers gp->lg_name); 376259311Sasomers last = (off_t)strtoimax(s, NULL, 0); 377207095Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 378207095Smarcel s = find_provcfg(pp, "index"); 379207095Smarcel if (s == NULL) 380207095Smarcel continue; 381207095Smarcel if (atoi(s) == idx) 382207095Smarcel break; 383207095Smarcel } 384207095Smarcel if (pp == NULL) 385207095Smarcel errx(EXIT_FAILURE, "invalid partition index"); 386207095Smarcel 387207095Smarcel s = find_provcfg(pp, "start"); 388221952Sae start = (off_t)strtoimax(s, NULL, 0); 389207095Smarcel s = find_provcfg(pp, "end"); 390222630Sae lba = (off_t)strtoimax(s, NULL, 0); 391222630Sae size = lba - start + 1; 392207095Smarcel 393225445Sae pp = find_provider(gp, lba + 1); 394225445Sae if (new_size > 0 && (new_size <= size || pp == NULL)) { 395222630Sae /* The start offset may be not aligned, so we align the end 396222630Sae * offset and then calculate the size. 397222630Sae */ 398222630Sae new_size = ALIGNDOWN(start + offset + new_size, 399222630Sae alignment) - start - offset; 400222630Sae goto done; 401209388Sae } 402222630Sae if (pp == NULL) { 403222630Sae new_size = ALIGNDOWN(last + offset + 1, alignment) - 404222630Sae start - offset; 405222630Sae if (new_size < size) 406222630Sae return (ENOSPC); 407222630Sae } else { 408207095Smarcel s = find_provcfg(pp, "start"); 409221952Sae new_lba = (off_t)strtoimax(s, NULL, 0); 410209388Sae /* 411209388Sae * Is there any free space between current and 412207095Smarcel * next providers? 413207095Smarcel */ 414222630Sae new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset; 415207095Smarcel if (new_lba > lba) 416207095Smarcel new_size = new_lba - start; 417209388Sae else { 418209388Sae geom_deletetree(&mesh); 419207095Smarcel return (ENOSPC); 420209388Sae } 421207095Smarcel } 422209388Saedone: 423209388Sae snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size); 424209388Sae gctl_change_param(req, "size", -1, ssize); 425209388Sae geom_deletetree(&mesh); 426207095Smarcel return (0); 427207095Smarcel} 428207095Smarcel 429207095Smarcelstatic int 430193673Smarcelgpart_autofill(struct gctl_req *req) 431193673Smarcel{ 432193673Smarcel struct gmesh mesh; 433193673Smarcel struct gclass *cp; 434193673Smarcel struct ggeom *gp; 435193673Smarcel struct gprovider *pp; 436221363Sae off_t first, last, a_first; 437221363Sae off_t size, start, a_lba; 438221967Sae off_t lba, len, alignment, offset; 439209388Sae uintmax_t grade; 440193673Smarcel const char *s; 441221363Sae int error, has_size, has_start, has_alignment; 442193673Smarcel 443193673Smarcel s = gctl_get_ascii(req, "verb"); 444207095Smarcel if (strcmp(s, "resize") == 0) 445207095Smarcel return gpart_autofill_resize(req); 446193673Smarcel if (strcmp(s, "add") != 0) 447193673Smarcel return (0); 448193673Smarcel 449193673Smarcel error = geom_gettree(&mesh); 450193673Smarcel if (error) 451193673Smarcel return (error); 452196278Smarcel s = gctl_get_ascii(req, "class"); 453196278Smarcel if (s == NULL) 454196278Smarcel abort(); 455196278Smarcel cp = find_class(&mesh, s); 456196278Smarcel if (cp == NULL) 457196278Smarcel errx(EXIT_FAILURE, "Class %s not found.", s); 458212613Spjd s = gctl_get_ascii(req, "arg0"); 459196278Smarcel if (s == NULL) 460196278Smarcel abort(); 461196278Smarcel gp = find_geom(cp, s); 462196278Smarcel if (gp == NULL) 463196278Smarcel errx(EXIT_FAILURE, "No such geom: %s.", s); 464209388Sae pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 465209388Sae if (pp == NULL) 466209388Sae errx(EXIT_FAILURE, "Provider for geom %s not found.", s); 467209388Sae 468221363Sae s = gctl_get_ascii(req, "alignment"); 469221363Sae has_alignment = (*s == '*') ? 0 : 1; 470221363Sae alignment = 1; 471221363Sae if (has_alignment) { 472221363Sae error = g_parse_lba(s, pp->lg_sectorsize, &alignment); 473221363Sae if (error) 474221363Sae errc(EXIT_FAILURE, error, "Invalid alignment param"); 475221363Sae if (alignment == 0) 476221363Sae errx(EXIT_FAILURE, "Invalid alignment param"); 477221363Sae } 478221363Sae error = gctl_delete_param(req, "alignment"); 479221363Sae if (error) 480221363Sae errc(EXIT_FAILURE, error, "internal error"); 481221363Sae 482209388Sae s = gctl_get_ascii(req, "size"); 483209388Sae has_size = (*s == '*') ? 0 : 1; 484209388Sae size = 0; 485209388Sae if (has_size) { 486209388Sae error = g_parse_lba(s, pp->lg_sectorsize, &size); 487209388Sae if (error) 488209388Sae errc(EXIT_FAILURE, error, "Invalid size param"); 489209388Sae } 490209388Sae 491209388Sae s = gctl_get_ascii(req, "start"); 492209388Sae has_start = (*s == '*') ? 0 : 1; 493209388Sae start = 0ULL; 494209388Sae if (has_start) { 495209388Sae error = g_parse_lba(s, pp->lg_sectorsize, &start); 496209388Sae if (error) 497209388Sae errc(EXIT_FAILURE, error, "Invalid start param"); 498209388Sae } 499209388Sae 500209388Sae /* No autofill necessary. */ 501221363Sae if (has_size && has_start && !has_alignment) 502209388Sae goto done; 503209388Sae 504222630Sae len = pp->lg_stripesize / pp->lg_sectorsize; 505222819Sae if (len > 0 && !has_alignment) 506222819Sae alignment = len; 507222630Sae 508222630Sae /* Adjust parameters to stripeoffset */ 509223356Sdelphij offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; 510221967Sae start = ALIGNUP(start + offset, alignment); 511223355Sae if (size > alignment) 512223355Sae size = ALIGNDOWN(size, alignment); 513221967Sae 514259311Sasomers s = find_geomcfg(gp, "first"); 515259311Sasomers if (s == NULL) 516259311Sasomers errx(EXIT_FAILURE, "Starting block not found for geom %s", 517259311Sasomers gp->lg_name); 518259311Sasomers first = (off_t)strtoimax(s, NULL, 0); 519259311Sasomers s = find_geomcfg(gp, "last"); 520259311Sasomers if (s == NULL) 521259311Sasomers errx(EXIT_FAILURE, "Final block not found for geom %s", 522259311Sasomers gp->lg_name); 523259311Sasomers last = (off_t)strtoimax(s, NULL, 0); 524193673Smarcel grade = ~0ULL; 525221967Sae a_first = ALIGNUP(first + offset, alignment); 526221967Sae last = ALIGNDOWN(last + offset, alignment); 527235033Sae if (a_first < start) 528235033Sae a_first = start; 529193673Smarcel while ((pp = find_provider(gp, first)) != NULL) { 530193673Smarcel s = find_provcfg(pp, "start"); 531221952Sae lba = (off_t)strtoimax(s, NULL, 0); 532221967Sae a_lba = ALIGNDOWN(lba + offset, alignment); 533221363Sae if (first < a_lba && a_first < a_lba) { 534193673Smarcel /* Free space [first, lba> */ 535221363Sae len = a_lba - a_first; 536193673Smarcel if (has_size) { 537209388Sae if (len >= size && 538209388Sae (uintmax_t)(len - size) < grade) { 539221363Sae start = a_first; 540193673Smarcel grade = len - size; 541193673Smarcel } 542193673Smarcel } else if (has_start) { 543221363Sae if (start >= a_first && start < a_lba) { 544221363Sae size = a_lba - start; 545221363Sae grade = start - a_first; 546193673Smarcel } 547193673Smarcel } else { 548193673Smarcel if (grade == ~0ULL || len > size) { 549221363Sae start = a_first; 550193673Smarcel size = len; 551193673Smarcel grade = 0; 552193673Smarcel } 553193673Smarcel } 554193673Smarcel } 555193673Smarcel 556193673Smarcel s = find_provcfg(pp, "end"); 557221952Sae first = (off_t)strtoimax(s, NULL, 0) + 1; 558279646Sae if (first + offset > a_first) 559235033Sae a_first = ALIGNUP(first + offset, alignment); 560193673Smarcel } 561221363Sae if (a_first <= last) { 562193673Smarcel /* Free space [first-last] */ 563221363Sae len = ALIGNDOWN(last - a_first + 1, alignment); 564193673Smarcel if (has_size) { 565209388Sae if (len >= size && 566209388Sae (uintmax_t)(len - size) < grade) { 567221363Sae start = a_first; 568193673Smarcel grade = len - size; 569193673Smarcel } 570193673Smarcel } else if (has_start) { 571221363Sae if (start >= a_first && start <= last) { 572221363Sae size = ALIGNDOWN(last - start + 1, alignment); 573221363Sae grade = start - a_first; 574193673Smarcel } 575193673Smarcel } else { 576193673Smarcel if (grade == ~0ULL || len > size) { 577221363Sae start = a_first; 578193673Smarcel size = len; 579193673Smarcel grade = 0; 580193673Smarcel } 581193673Smarcel } 582193673Smarcel } 583209388Sae if (grade == ~0ULL) { 584209388Sae geom_deletetree(&mesh); 585193673Smarcel return (ENOSPC); 586209388Sae } 587221967Sae start -= offset; /* Return back to real offset */ 588209388Saedone: 589209388Sae snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size); 590209388Sae gctl_change_param(req, "size", -1, ssize); 591209388Sae snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start); 592209388Sae gctl_change_param(req, "start", -1, sstart); 593209388Sae geom_deletetree(&mesh); 594193673Smarcel return (0); 595193673Smarcel} 596193673Smarcel 597172837Smarcelstatic void 598219415Saegpart_show_geom(struct ggeom *gp, const char *element, int show_providers) 599172837Smarcel{ 600172837Smarcel struct gprovider *pp; 601172837Smarcel const char *s, *scheme; 602209388Sae off_t first, last, sector, end; 603209388Sae off_t length, secsz; 604219415Sae int idx, wblocks, wname, wmax; 605172837Smarcel 606281303Smav if (find_geomcfg(gp, "wither")) 607281303Smav return; 608172837Smarcel scheme = find_geomcfg(gp, "scheme"); 609259311Sasomers if (scheme == NULL) 610259311Sasomers errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); 611172837Smarcel s = find_geomcfg(gp, "first"); 612259311Sasomers if (s == NULL) 613259311Sasomers errx(EXIT_FAILURE, "Starting block not found for geom %s", 614259311Sasomers gp->lg_name); 615209388Sae first = (off_t)strtoimax(s, NULL, 0); 616172837Smarcel s = find_geomcfg(gp, "last"); 617259311Sasomers if (s == NULL) 618259311Sasomers errx(EXIT_FAILURE, "Final block not found for geom %s", 619259311Sasomers gp->lg_name); 620209388Sae last = (off_t)strtoimax(s, NULL, 0); 621172837Smarcel wblocks = strlen(s); 622214352Sae s = find_geomcfg(gp, "state"); 623259311Sasomers if (s == NULL) 624259311Sasomers errx(EXIT_FAILURE, "State not found for geom %s", gp->lg_name); 625214352Sae if (s != NULL && *s != 'C') 626214352Sae s = NULL; 627219415Sae wmax = strlen(gp->lg_name); 628219415Sae if (show_providers) { 629219415Sae LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 630219415Sae wname = strlen(pp->lg_name); 631219415Sae if (wname > wmax) 632219415Sae wmax = wname; 633219415Sae } 634219415Sae } 635219415Sae wname = wmax; 636172837Smarcel pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 637172837Smarcel secsz = pp->lg_sectorsize; 638214352Sae printf("=>%*jd %*jd %*s %s (%s)%s\n", 639209388Sae wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1), 640172837Smarcel wname, gp->lg_name, 641214352Sae scheme, fmtsize(pp->lg_mediasize), 642214352Sae s ? " [CORRUPT]": ""); 643172837Smarcel 644172837Smarcel while ((pp = find_provider(gp, first)) != NULL) { 645188330Smarcel s = find_provcfg(pp, "start"); 646221952Sae sector = (off_t)strtoimax(s, NULL, 0); 647188330Smarcel 648188330Smarcel s = find_provcfg(pp, "end"); 649221952Sae end = (off_t)strtoimax(s, NULL, 0); 650221952Sae length = end - sector + 1; 651221952Sae 652172837Smarcel s = find_provcfg(pp, "index"); 653172837Smarcel idx = atoi(s); 654172837Smarcel if (first < sector) { 655209388Sae printf(" %*jd %*jd %*s - free - (%s)\n", 656209388Sae wblocks, (intmax_t)first, wblocks, 657209388Sae (intmax_t)(sector - first), wname, "", 658172837Smarcel fmtsize((sector - first) * secsz)); 659172837Smarcel } 660219415Sae if (show_providers) { 661219415Sae printf(" %*jd %*jd %*s %s %s (%s)\n", 662219415Sae wblocks, (intmax_t)sector, wblocks, 663219415Sae (intmax_t)length, wname, pp->lg_name, 664219415Sae find_provcfg(pp, element), fmtattrib(pp), 665219415Sae fmtsize(pp->lg_mediasize)); 666219415Sae } else 667219415Sae printf(" %*jd %*jd %*d %s %s (%s)\n", 668219415Sae wblocks, (intmax_t)sector, wblocks, 669219415Sae (intmax_t)length, wname, idx, 670219415Sae find_provcfg(pp, element), fmtattrib(pp), 671219415Sae fmtsize(pp->lg_mediasize)); 672188330Smarcel first = end + 1; 673172837Smarcel } 674172837Smarcel if (first <= last) { 675188330Smarcel length = last - first + 1; 676209388Sae printf(" %*jd %*jd %*s - free - (%s)\n", 677209388Sae wblocks, (intmax_t)first, wblocks, (intmax_t)length, 678172837Smarcel wname, "", 679188330Smarcel fmtsize(length * secsz)); 680172837Smarcel } 681172837Smarcel printf("\n"); 682172837Smarcel} 683172837Smarcel 684179769Smarcelstatic int 685179769Smarcelgpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 686179769Smarcel{ 687179769Smarcel 688215704Sbrucec if (!gctl_get_int(req, "%s", opt)) 689179769Smarcel return (0); 690179769Smarcel 691179769Smarcel if (elt != NULL) 692179769Smarcel errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 693179769Smarcel 694179769Smarcel return (1); 695179769Smarcel} 696179769Smarcel 697172837Smarcelstatic void 698178180Smarcelgpart_show(struct gctl_req *req, unsigned int fl __unused) 699172837Smarcel{ 700172837Smarcel struct gmesh mesh; 701172837Smarcel struct gclass *classp; 702172837Smarcel struct ggeom *gp; 703179769Smarcel const char *element, *name; 704219415Sae int error, i, nargs, show_providers; 705172837Smarcel 706179769Smarcel element = NULL; 707179769Smarcel if (gpart_show_hasopt(req, "show_label", element)) 708179769Smarcel element = "label"; 709179769Smarcel if (gpart_show_hasopt(req, "show_rawtype", element)) 710179769Smarcel element = "rawtype"; 711179769Smarcel if (element == NULL) 712179769Smarcel element = "type"; 713179769Smarcel 714172837Smarcel name = gctl_get_ascii(req, "class"); 715172837Smarcel if (name == NULL) 716172837Smarcel abort(); 717172837Smarcel error = geom_gettree(&mesh); 718172837Smarcel if (error != 0) 719172837Smarcel errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 720172837Smarcel classp = find_class(&mesh, name); 721172837Smarcel if (classp == NULL) { 722172837Smarcel geom_deletetree(&mesh); 723172837Smarcel errx(EXIT_FAILURE, "Class %s not found.", name); 724172837Smarcel } 725219415Sae show_providers = gctl_get_int(req, "show_providers"); 726172837Smarcel nargs = gctl_get_int(req, "nargs"); 727172837Smarcel if (nargs > 0) { 728172837Smarcel for (i = 0; i < nargs; i++) { 729172837Smarcel name = gctl_get_ascii(req, "arg%d", i); 730172837Smarcel gp = find_geom(classp, name); 731172837Smarcel if (gp != NULL) 732219415Sae gpart_show_geom(gp, element, show_providers); 733172837Smarcel else 734172837Smarcel errx(EXIT_FAILURE, "No such geom: %s.", name); 735172837Smarcel } 736172837Smarcel } else { 737172837Smarcel LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 738219415Sae gpart_show_geom(gp, element, show_providers); 739172837Smarcel } 740172837Smarcel } 741172837Smarcel geom_deletetree(&mesh); 742172837Smarcel} 743178180Smarcel 744215570Saestatic void 745215570Saegpart_backup(struct gctl_req *req, unsigned int fl __unused) 746215570Sae{ 747215570Sae struct gmesh mesh; 748215570Sae struct gclass *classp; 749215570Sae struct gprovider *pp; 750215570Sae struct ggeom *gp; 751215570Sae const char *s, *scheme; 752215570Sae off_t sector, end; 753229916Seadler off_t length; 754215671Sae int error, i, windex, wblocks, wtype; 755215570Sae 756215570Sae if (gctl_get_int(req, "nargs") != 1) 757215570Sae errx(EXIT_FAILURE, "Invalid number of arguments."); 758215570Sae error = geom_gettree(&mesh); 759215570Sae if (error != 0) 760215570Sae errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 761215570Sae s = gctl_get_ascii(req, "class"); 762215570Sae if (s == NULL) 763215570Sae abort(); 764215570Sae classp = find_class(&mesh, s); 765215570Sae if (classp == NULL) { 766215570Sae geom_deletetree(&mesh); 767215570Sae errx(EXIT_FAILURE, "Class %s not found.", s); 768215570Sae } 769215570Sae s = gctl_get_ascii(req, "arg0"); 770215570Sae if (s == NULL) 771215570Sae abort(); 772215570Sae gp = find_geom(classp, s); 773215570Sae if (gp == NULL) 774215570Sae errx(EXIT_FAILURE, "No such geom: %s.", s); 775215570Sae scheme = find_geomcfg(gp, "scheme"); 776215570Sae if (scheme == NULL) 777215570Sae abort(); 778215570Sae pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 779215570Sae s = find_geomcfg(gp, "last"); 780259311Sasomers if (s == NULL) 781259311Sasomers abort(); 782215570Sae wblocks = strlen(s); 783215570Sae wtype = 0; 784215570Sae LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 785215570Sae s = find_provcfg(pp, "type"); 786215570Sae i = strlen(s); 787215570Sae if (i > wtype) 788215570Sae wtype = i; 789215570Sae } 790215570Sae s = find_geomcfg(gp, "entries"); 791259311Sasomers if (s == NULL) 792259311Sasomers abort(); 793215570Sae windex = strlen(s); 794215570Sae printf("%s %s\n", scheme, s); 795215570Sae LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 796215570Sae s = find_provcfg(pp, "start"); 797221952Sae sector = (off_t)strtoimax(s, NULL, 0); 798215570Sae 799215570Sae s = find_provcfg(pp, "end"); 800221952Sae end = (off_t)strtoimax(s, NULL, 0); 801221952Sae length = end - sector + 1; 802221952Sae 803215570Sae s = find_provcfg(pp, "label"); 804215671Sae printf("%-*s %*s %*jd %*jd %s %s\n", 805215570Sae windex, find_provcfg(pp, "index"), 806215570Sae wtype, find_provcfg(pp, "type"), 807215570Sae wblocks, (intmax_t)sector, 808215671Sae wblocks, (intmax_t)length, 809215671Sae (s != NULL) ? s: "", fmtattrib(pp)); 810215570Sae } 811215570Sae geom_deletetree(&mesh); 812215570Sae} 813215570Sae 814215570Saestatic int 815215570Saeskip_line(const char *p) 816215570Sae{ 817215570Sae 818215570Sae while (*p != '\0') { 819215570Sae if (*p == '#') 820215570Sae return (1); 821215570Sae if (isspace(*p) == 0) 822215570Sae return (0); 823215570Sae p++; 824215570Sae } 825215570Sae return (1); 826215570Sae} 827215570Sae 828215570Saestatic void 829215672Saegpart_sighndl(int sig __unused) 830215672Sae{ 831215672Sae undo_restore = 1; 832215672Sae} 833215672Sae 834215672Saestatic void 835215570Saegpart_restore(struct gctl_req *req, unsigned int fl __unused) 836215570Sae{ 837215570Sae struct gmesh mesh; 838215570Sae struct gclass *classp; 839215570Sae struct gctl_req *r; 840215570Sae struct ggeom *gp; 841215672Sae struct sigaction si_sa; 842215570Sae const char *s, *flags, *errstr, *label; 843215570Sae char **ap, *argv[6], line[BUFSIZ], *pline; 844215671Sae int error, forced, i, l, nargs, created, rl; 845215570Sae intmax_t n; 846215570Sae 847215570Sae nargs = gctl_get_int(req, "nargs"); 848215570Sae if (nargs < 1) 849215570Sae errx(EXIT_FAILURE, "Invalid number of arguments."); 850215570Sae 851215570Sae forced = gctl_get_int(req, "force"); 852215570Sae flags = gctl_get_ascii(req, "flags"); 853215671Sae rl = gctl_get_int(req, "restore_labels"); 854215570Sae s = gctl_get_ascii(req, "class"); 855215570Sae if (s == NULL) 856215570Sae abort(); 857215570Sae error = geom_gettree(&mesh); 858215570Sae if (error != 0) 859215570Sae errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 860215570Sae classp = find_class(&mesh, s); 861215570Sae if (classp == NULL) { 862215570Sae geom_deletetree(&mesh); 863215570Sae errx(EXIT_FAILURE, "Class %s not found.", s); 864215570Sae } 865215672Sae 866215672Sae sigemptyset(&si_sa.sa_mask); 867215672Sae si_sa.sa_flags = 0; 868215672Sae si_sa.sa_handler = gpart_sighndl; 869215672Sae if (sigaction(SIGINT, &si_sa, 0) == -1) 870215672Sae err(EXIT_FAILURE, "sigaction SIGINT"); 871215672Sae 872215570Sae if (forced) { 873215570Sae /* destroy existent partition table before restore */ 874215570Sae for (i = 0; i < nargs; i++) { 875215570Sae s = gctl_get_ascii(req, "arg%d", i); 876215570Sae gp = find_geom(classp, s); 877215570Sae if (gp != NULL) { 878215570Sae r = gctl_get_handle(); 879215570Sae gctl_ro_param(r, "class", -1, 880215570Sae classp->lg_name); 881215570Sae gctl_ro_param(r, "verb", -1, "destroy"); 882215570Sae gctl_ro_param(r, "flags", -1, "restore"); 883215570Sae gctl_ro_param(r, "force", sizeof(forced), 884215570Sae &forced); 885215570Sae gctl_ro_param(r, "arg0", -1, s); 886215570Sae errstr = gctl_issue(r); 887215570Sae if (errstr != NULL && errstr[0] != '\0') { 888215570Sae gpart_print_error(errstr); 889215570Sae gctl_free(r); 890215570Sae goto backout; 891215570Sae } 892215570Sae gctl_free(r); 893215570Sae } 894215570Sae } 895215570Sae } 896215570Sae created = 0; 897215672Sae while (undo_restore == 0 && 898215672Sae fgets(line, sizeof(line) - 1, stdin) != NULL) { 899215570Sae /* Format of backup entries: 900215570Sae * <scheme name> <number of entries> 901215570Sae * <index> <type> <start> <size> [label] ['['attrib[,attrib]']'] 902215570Sae */ 903215570Sae pline = (char *)line; 904215570Sae pline[strlen(line) - 1] = 0; 905215570Sae if (skip_line(pline)) 906215570Sae continue; 907215570Sae for (ap = argv; 908215570Sae (*ap = strsep(&pline, " \t")) != NULL;) 909215570Sae if (**ap != '\0' && ++ap >= &argv[6]) 910215570Sae break; 911215570Sae l = ap - &argv[0]; 912215570Sae label = pline = NULL; 913215671Sae if (l == 1 || l == 2) { /* create table */ 914215570Sae if (created) 915215570Sae errx(EXIT_FAILURE, "Incorrect backup format."); 916215671Sae if (l == 2) 917215671Sae n = strtoimax(argv[1], NULL, 0); 918215570Sae for (i = 0; i < nargs; i++) { 919215570Sae s = gctl_get_ascii(req, "arg%d", i); 920215570Sae r = gctl_get_handle(); 921215570Sae gctl_ro_param(r, "class", -1, 922215570Sae classp->lg_name); 923215570Sae gctl_ro_param(r, "verb", -1, "create"); 924215570Sae gctl_ro_param(r, "scheme", -1, argv[0]); 925215671Sae if (l == 2) 926215671Sae gctl_ro_param(r, "entries", 927215671Sae sizeof(n), &n); 928215570Sae gctl_ro_param(r, "flags", -1, "restore"); 929215570Sae gctl_ro_param(r, "arg0", -1, s); 930215570Sae errstr = gctl_issue(r); 931215570Sae if (errstr != NULL && errstr[0] != '\0') { 932215570Sae gpart_print_error(errstr); 933215570Sae gctl_free(r); 934215570Sae goto backout; 935215570Sae } 936215570Sae gctl_free(r); 937215570Sae } 938215570Sae created = 1; 939215570Sae continue; 940215570Sae } else if (l < 4 || created == 0) 941215570Sae errx(EXIT_FAILURE, "Incorrect backup format."); 942215570Sae else if (l == 5) { 943215570Sae if (strchr(argv[4], '[') == NULL) 944215570Sae label = argv[4]; 945215570Sae else 946215570Sae pline = argv[4]; 947215570Sae } else if (l == 6) { 948215570Sae label = argv[4]; 949215570Sae pline = argv[5]; 950215570Sae } 951215570Sae /* Add partitions to each table */ 952215570Sae for (i = 0; i < nargs; i++) { 953215570Sae s = gctl_get_ascii(req, "arg%d", i); 954215570Sae r = gctl_get_handle(); 955215570Sae n = strtoimax(argv[0], NULL, 0); 956215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 957215570Sae gctl_ro_param(r, "verb", -1, "add"); 958215570Sae gctl_ro_param(r, "flags", -1, "restore"); 959215570Sae gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n); 960215570Sae gctl_ro_param(r, "type", -1, argv[1]); 961215570Sae gctl_ro_param(r, "start", -1, argv[2]); 962215570Sae gctl_ro_param(r, "size", -1, argv[3]); 963215671Sae if (rl != 0 && label != NULL) 964215570Sae gctl_ro_param(r, "label", -1, argv[4]); 965223158Sae gctl_ro_param(r, "alignment", -1, GPART_AUTOFILL); 966215570Sae gctl_ro_param(r, "arg0", -1, s); 967215570Sae error = gpart_autofill(r); 968215570Sae if (error != 0) 969215570Sae errc(EXIT_FAILURE, error, "autofill"); 970215570Sae errstr = gctl_issue(r); 971215570Sae if (errstr != NULL && errstr[0] != '\0') { 972215570Sae gpart_print_error(errstr); 973215570Sae gctl_free(r); 974215570Sae goto backout; 975215570Sae } 976215570Sae gctl_free(r); 977215570Sae } 978215570Sae if (pline == NULL || *pline != '[') 979215570Sae continue; 980215570Sae /* set attributes */ 981215570Sae pline++; 982215570Sae for (ap = argv; 983215570Sae (*ap = strsep(&pline, ",]")) != NULL;) 984215570Sae if (**ap != '\0' && ++ap >= &argv[6]) 985215570Sae break; 986215570Sae for (i = 0; i < nargs; i++) { 987215570Sae l = ap - &argv[0]; 988215570Sae s = gctl_get_ascii(req, "arg%d", i); 989215570Sae while (l > 0) { 990215570Sae r = gctl_get_handle(); 991215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 992215570Sae gctl_ro_param(r, "verb", -1, "set"); 993215570Sae gctl_ro_param(r, "flags", -1, "restore"); 994215570Sae gctl_ro_param(r, GPART_PARAM_INDEX, 995215570Sae sizeof(n), &n); 996215570Sae gctl_ro_param(r, "attrib", -1, argv[--l]); 997215570Sae gctl_ro_param(r, "arg0", -1, s); 998215570Sae errstr = gctl_issue(r); 999215570Sae if (errstr != NULL && errstr[0] != '\0') { 1000215570Sae gpart_print_error(errstr); 1001215570Sae gctl_free(r); 1002215570Sae goto backout; 1003215570Sae } 1004215570Sae gctl_free(r); 1005215570Sae } 1006215570Sae } 1007215570Sae } 1008215672Sae if (undo_restore) 1009215672Sae goto backout; 1010215570Sae /* commit changes if needed */ 1011215570Sae if (strchr(flags, 'C') != NULL) { 1012215570Sae for (i = 0; i < nargs; i++) { 1013215570Sae s = gctl_get_ascii(req, "arg%d", i); 1014215570Sae r = gctl_get_handle(); 1015215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 1016215570Sae gctl_ro_param(r, "verb", -1, "commit"); 1017215570Sae gctl_ro_param(r, "arg0", -1, s); 1018215570Sae errstr = gctl_issue(r); 1019215570Sae if (errstr != NULL && errstr[0] != '\0') { 1020215570Sae gpart_print_error(errstr); 1021215570Sae gctl_free(r); 1022215570Sae goto backout; 1023215570Sae } 1024215570Sae gctl_free(r); 1025215570Sae } 1026215570Sae } 1027215570Sae gctl_free(req); 1028215570Sae geom_deletetree(&mesh); 1029215570Sae exit(EXIT_SUCCESS); 1030215570Sae 1031215570Saebackout: 1032215570Sae for (i = 0; i < nargs; i++) { 1033215570Sae s = gctl_get_ascii(req, "arg%d", i); 1034215570Sae r = gctl_get_handle(); 1035215570Sae gctl_ro_param(r, "class", -1, classp->lg_name); 1036215570Sae gctl_ro_param(r, "verb", -1, "undo"); 1037215570Sae gctl_ro_param(r, "arg0", -1, s); 1038215570Sae gctl_issue(r); 1039215570Sae gctl_free(r); 1040215570Sae } 1041215570Sae gctl_free(req); 1042215570Sae geom_deletetree(&mesh); 1043215570Sae exit(EXIT_FAILURE); 1044215570Sae} 1045215570Sae 1046179629Smarcelstatic void * 1047179629Smarcelgpart_bootfile_read(const char *bootfile, ssize_t *size) 1048178180Smarcel{ 1049178180Smarcel struct stat sb; 1050178180Smarcel void *code; 1051179629Smarcel int fd; 1052178180Smarcel 1053179629Smarcel if (stat(bootfile, &sb) == -1) 1054179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 1055178180Smarcel if (!S_ISREG(sb.st_mode)) 1056178180Smarcel errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 1057179629Smarcel if (sb.st_size == 0) 1058179629Smarcel errx(EXIT_FAILURE, "%s: empty file", bootfile); 1059208777Smarius if (*size > 0 && sb.st_size > *size) 1060179629Smarcel errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 1061179629Smarcel *size); 1062178180Smarcel 1063179629Smarcel *size = sb.st_size; 1064178180Smarcel 1065178180Smarcel fd = open(bootfile, O_RDONLY); 1066178180Smarcel if (fd == -1) 1067179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 1068179629Smarcel code = malloc(*size); 1069178180Smarcel if (code == NULL) 1070179629Smarcel err(EXIT_FAILURE, NULL); 1071179629Smarcel if (read(fd, code, *size) != *size) 1072179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 1073178180Smarcel close(fd); 1074178180Smarcel 1075179629Smarcel return (code); 1076178180Smarcel} 1077179629Smarcel 1078179629Smarcelstatic void 1079208777Smariusgpart_write_partcode(struct ggeom *gp, int idx, void *code, ssize_t size) 1080179629Smarcel{ 1081179629Smarcel char dsf[128]; 1082179629Smarcel struct gprovider *pp; 1083179629Smarcel const char *s; 1084185038Smarcel char *buf; 1085185038Smarcel off_t bsize; 1086208777Smarius int fd; 1087179629Smarcel 1088179629Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1089179629Smarcel s = find_provcfg(pp, "index"); 1090179629Smarcel if (s == NULL) 1091179629Smarcel continue; 1092179629Smarcel if (atoi(s) == idx) 1093179629Smarcel break; 1094179629Smarcel } 1095179629Smarcel 1096179629Smarcel if (pp != NULL) { 1097179629Smarcel snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1098285936Sae if (pp->lg_mediasize < size) 1099285936Sae errx(EXIT_FAILURE, "%s: not enough space", dsf); 1100179629Smarcel fd = open(dsf, O_WRONLY); 1101179629Smarcel if (fd == -1) 1102179629Smarcel err(EXIT_FAILURE, "%s", dsf); 1103185038Smarcel /* 1104185038Smarcel * When writing to a disk device, the write must be 1105185038Smarcel * sector aligned and not write to any partial sectors, 1106185038Smarcel * so round up the buffer size to the next sector and zero it. 1107185038Smarcel */ 1108185038Smarcel bsize = (size + pp->lg_sectorsize - 1) / 1109185038Smarcel pp->lg_sectorsize * pp->lg_sectorsize; 1110185038Smarcel buf = calloc(1, bsize); 1111185038Smarcel if (buf == NULL) 1112179629Smarcel err(EXIT_FAILURE, "%s", dsf); 1113185038Smarcel bcopy(code, buf, size); 1114185038Smarcel if (write(fd, buf, bsize) != bsize) 1115185038Smarcel err(EXIT_FAILURE, "%s", dsf); 1116185038Smarcel free(buf); 1117179629Smarcel close(fd); 1118298628Sae printf("partcode written to %s\n", pp->lg_name); 1119179629Smarcel } else 1120179629Smarcel errx(EXIT_FAILURE, "invalid partition index"); 1121208777Smarius} 1122179629Smarcel 1123208777Smariusstatic void 1124208777Smariusgpart_write_partcode_vtoc8(struct ggeom *gp, int idx, void *code) 1125208777Smarius{ 1126208777Smarius char dsf[128]; 1127208777Smarius struct gprovider *pp; 1128208777Smarius const char *s; 1129208777Smarius int installed, fd; 1130208777Smarius 1131208777Smarius installed = 0; 1132208777Smarius LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1133208777Smarius s = find_provcfg(pp, "index"); 1134208777Smarius if (s == NULL) 1135208777Smarius continue; 1136208777Smarius if (idx != 0 && atoi(s) != idx) 1137208777Smarius continue; 1138208777Smarius snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 1139208777Smarius if (pp->lg_sectorsize != sizeof(struct vtoc8)) 1140208777Smarius errx(EXIT_FAILURE, "%s: unexpected sector " 1141208777Smarius "size (%d)\n", dsf, pp->lg_sectorsize); 1142285936Sae if (pp->lg_mediasize < VTOC_BOOTSIZE) 1143285936Sae continue; 1144208777Smarius fd = open(dsf, O_WRONLY); 1145208777Smarius if (fd == -1) 1146208777Smarius err(EXIT_FAILURE, "%s", dsf); 1147208777Smarius /* 1148208777Smarius * We ignore the first VTOC_BOOTSIZE bytes of boot code in 1149208777Smarius * order to avoid overwriting the label. 1150208777Smarius */ 1151208777Smarius if (lseek(fd, sizeof(struct vtoc8), SEEK_SET) != 1152208777Smarius sizeof(struct vtoc8)) 1153208777Smarius err(EXIT_FAILURE, "%s", dsf); 1154208777Smarius if (write(fd, (caddr_t)code + sizeof(struct vtoc8), 1155208777Smarius VTOC_BOOTSIZE - sizeof(struct vtoc8)) != VTOC_BOOTSIZE - 1156208777Smarius sizeof(struct vtoc8)) 1157208777Smarius err(EXIT_FAILURE, "%s", dsf); 1158208777Smarius installed++; 1159208777Smarius close(fd); 1160208777Smarius if (idx != 0 && atoi(s) == idx) 1161208777Smarius break; 1162208777Smarius } 1163208777Smarius if (installed == 0) 1164208777Smarius errx(EXIT_FAILURE, "%s: no partitions", gp->lg_name); 1165298628Sae else 1166298628Sae printf("partcode written to %s\n", 1167298628Sae idx != 0 ? pp->lg_name: gp->lg_name); 1168179629Smarcel} 1169179629Smarcel 1170179629Smarcelstatic void 1171185454Smarcelgpart_bootcode(struct gctl_req *req, unsigned int fl) 1172179629Smarcel{ 1173208777Smarius struct gmesh mesh; 1174208777Smarius struct gclass *classp; 1175208777Smarius struct ggeom *gp; 1176179629Smarcel const char *s; 1177179629Smarcel void *bootcode, *partcode; 1178179629Smarcel size_t bootsize, partsize; 1179208777Smarius int error, idx, vtoc8; 1180179629Smarcel 1181212554Spjd if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) { 1182212554Spjd s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE); 1183208173Snwhitehorn bootsize = 800 * 1024; /* Arbitrary limit. */ 1184179629Smarcel bootcode = gpart_bootfile_read(s, &bootsize); 1185212554Spjd error = gctl_change_param(req, GPART_PARAM_BOOTCODE, bootsize, 1186179629Smarcel bootcode); 1187179629Smarcel if (error) 1188179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 1189298628Sae } else 1190179629Smarcel bootcode = NULL; 1191179629Smarcel 1192208777Smarius s = gctl_get_ascii(req, "class"); 1193208777Smarius if (s == NULL) 1194208777Smarius abort(); 1195208777Smarius error = geom_gettree(&mesh); 1196208777Smarius if (error != 0) 1197208777Smarius errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 1198208777Smarius classp = find_class(&mesh, s); 1199208777Smarius if (classp == NULL) { 1200208777Smarius geom_deletetree(&mesh); 1201208777Smarius errx(EXIT_FAILURE, "Class %s not found.", s); 1202208777Smarius } 1203216619Sae if (gctl_get_int(req, "nargs") != 1) 1204216619Sae errx(EXIT_FAILURE, "Invalid number of arguments."); 1205212554Spjd s = gctl_get_ascii(req, "arg0"); 1206208777Smarius if (s == NULL) 1207208777Smarius abort(); 1208208777Smarius gp = find_geom(classp, s); 1209208777Smarius if (gp == NULL) 1210208777Smarius errx(EXIT_FAILURE, "No such geom: %s.", s); 1211208777Smarius s = find_geomcfg(gp, "scheme"); 1212259311Sasomers if (s == NULL) 1213259311Sasomers errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); 1214208777Smarius if (strcmp(s, "VTOC8") == 0) 1215208777Smarius vtoc8 = 1; 1216298628Sae else 1217298628Sae vtoc8 = 0; 1218208777Smarius 1219212554Spjd if (gctl_has_param(req, GPART_PARAM_PARTCODE)) { 1220212554Spjd s = gctl_get_ascii(req, GPART_PARAM_PARTCODE); 1221298628Sae if (vtoc8 != 0) 1222298628Sae partsize = VTOC_BOOTSIZE; 1223298628Sae else 1224298628Sae partsize = 1024 * 1024; /* Arbitrary limit. */ 1225179629Smarcel partcode = gpart_bootfile_read(s, &partsize); 1226212554Spjd error = gctl_delete_param(req, GPART_PARAM_PARTCODE); 1227179629Smarcel if (error) 1228179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 1229298628Sae } else 1230179629Smarcel partcode = NULL; 1231179629Smarcel 1232212554Spjd if (gctl_has_param(req, GPART_PARAM_INDEX)) { 1233179629Smarcel if (partcode == NULL) 1234179629Smarcel errx(EXIT_FAILURE, "-i is only valid with -p"); 1235212708Spjd idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); 1236212708Spjd if (idx < 1) 1237179629Smarcel errx(EXIT_FAILURE, "invalid partition index"); 1238212554Spjd error = gctl_delete_param(req, GPART_PARAM_INDEX); 1239179629Smarcel if (error) 1240179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 1241179629Smarcel } else 1242179629Smarcel idx = 0; 1243179629Smarcel 1244179629Smarcel if (partcode != NULL) { 1245208777Smarius if (vtoc8 == 0) { 1246208777Smarius if (idx == 0) 1247208777Smarius errx(EXIT_FAILURE, "missing -i option"); 1248208777Smarius gpart_write_partcode(gp, idx, partcode, partsize); 1249223364Sae } else { 1250223364Sae if (partsize != VTOC_BOOTSIZE) 1251223364Sae errx(EXIT_FAILURE, "invalid bootcode"); 1252208777Smarius gpart_write_partcode_vtoc8(gp, idx, partcode); 1253223364Sae } 1254208777Smarius } else 1255179629Smarcel if (bootcode == NULL) 1256179629Smarcel errx(EXIT_FAILURE, "no -b nor -p"); 1257179629Smarcel 1258185454Smarcel if (bootcode != NULL) 1259185454Smarcel gpart_issue(req, fl); 1260208777Smarius 1261208777Smarius geom_deletetree(&mesh); 1262319258Sasomers free(partcode); 1263185454Smarcel} 1264185454Smarcel 1265185454Smarcelstatic void 1266213097Saegpart_print_error(const char *errstr) 1267213097Sae{ 1268213097Sae char *errmsg; 1269213097Sae int error; 1270213097Sae 1271213097Sae error = strtol(errstr, &errmsg, 0); 1272213097Sae if (errmsg != errstr) { 1273213097Sae while (errmsg[0] == ' ') 1274213097Sae errmsg++; 1275213097Sae if (errmsg[0] != '\0') 1276213097Sae warnc(error, "%s", errmsg); 1277213097Sae else 1278213097Sae warnc(error, NULL); 1279213097Sae } else 1280213097Sae warnx("%s", errmsg); 1281213097Sae} 1282213097Sae 1283319258Sasomersstatic _Noreturn void 1284185454Smarcelgpart_issue(struct gctl_req *req, unsigned int fl __unused) 1285185454Smarcel{ 1286185454Smarcel char buf[4096]; 1287185454Smarcel const char *errstr; 1288185495Smarcel int error, status; 1289185454Smarcel 1290212554Spjd if (gctl_get_int(req, "nargs") != 1) 1291212554Spjd errx(EXIT_FAILURE, "Invalid number of arguments."); 1292212554Spjd (void)gctl_delete_param(req, "nargs"); 1293212554Spjd 1294193673Smarcel /* autofill parameters (if applicable). */ 1295193673Smarcel error = gpart_autofill(req); 1296193673Smarcel if (error) { 1297193673Smarcel warnc(error, "autofill"); 1298193673Smarcel status = EXIT_FAILURE; 1299193673Smarcel goto done; 1300193673Smarcel } 1301193673Smarcel 1302185454Smarcel bzero(buf, sizeof(buf)); 1303185454Smarcel gctl_rw_param(req, "output", sizeof(buf), buf); 1304185454Smarcel errstr = gctl_issue(req); 1305185454Smarcel if (errstr == NULL || errstr[0] == '\0') { 1306185454Smarcel if (buf[0] != '\0') 1307185454Smarcel printf("%s", buf); 1308185495Smarcel status = EXIT_SUCCESS; 1309185495Smarcel goto done; 1310179629Smarcel } 1311185454Smarcel 1312213097Sae gpart_print_error(errstr); 1313185495Smarcel status = EXIT_FAILURE; 1314185495Smarcel 1315185495Smarcel done: 1316185495Smarcel gctl_free(req); 1317185495Smarcel exit(status); 1318179629Smarcel} 1319