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