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