geom_part.c revision 198478
1169586Smarcel/*- 2179854Smarcel * Copyright (c) 2007, 2008 Marcel Moolenaar 3169586Smarcel * All rights reserved. 4169586Smarcel * 5169586Smarcel * Redistribution and use in source and binary forms, with or without 6169586Smarcel * modification, are permitted provided that the following conditions 7169586Smarcel * are met: 8169586Smarcel * 1. Redistributions of source code must retain the above copyright 9169586Smarcel * notice, this list of conditions and the following disclaimer. 10169586Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11169586Smarcel * notice, this list of conditions and the following disclaimer in the 12169586Smarcel * documentation and/or other materials provided with the distribution. 13169586Smarcel * 14169586Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15169586Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169586Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169586Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18169586Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169586Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169586Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169586Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169586Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169586Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169586Smarcel * SUCH DAMAGE. 25169586Smarcel */ 26169586Smarcel 27169586Smarcel#include <sys/cdefs.h> 28169586Smarcel__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 198478 2009-10-26 07:43:41Z lulf $"); 29169586Smarcel 30185044Smarcel#include <sys/stat.h> 31185044Smarcel 32185044Smarcel#include <assert.h> 33185044Smarcel#include <err.h> 34185044Smarcel#include <errno.h> 35185044Smarcel#include <fcntl.h> 36185044Smarcel#include <libgeom.h> 37185046Smarcel#include <libutil.h> 38185044Smarcel#include <paths.h> 39185044Smarcel#include <stdint.h> 40169586Smarcel#include <stdio.h> 41169586Smarcel#include <stdlib.h> 42169586Smarcel#include <string.h> 43169586Smarcel#include <strings.h> 44185044Smarcel#include <unistd.h> 45169586Smarcel 46169586Smarcel#include "core/geom.h" 47169586Smarcel#include "misc/subr.h" 48169586Smarcel 49179550Smarcel#ifdef STATIC_GEOM_CLASSES 50173313Smarcel#define PUBSYM(x) gpart_##x 51173313Smarcel#else 52173313Smarcel#define PUBSYM(x) x 53173313Smarcel#endif 54169586Smarcel 55173313Smarceluint32_t PUBSYM(lib_version) = G_LIB_VERSION; 56173313Smarceluint32_t PUBSYM(version) = 0; 57173313Smarcel 58193673Smarcelstatic char autofill[] = "*"; 59169586Smarcelstatic char optional[] = ""; 60169586Smarcelstatic char flags[] = "C"; 61169586Smarcel 62179629Smarcelstatic char bootcode_param[] = "bootcode"; 63179629Smarcelstatic char index_param[] = "index"; 64179629Smarcelstatic char partcode_param[] = "partcode"; 65179629Smarcel 66178180Smarcelstatic void gpart_bootcode(struct gctl_req *, unsigned int); 67185454Smarcelstatic void gpart_issue(struct gctl_req *, unsigned int); 68178180Smarcelstatic void gpart_show(struct gctl_req *, unsigned int); 69172837Smarcel 70173313Smarcelstruct g_command PUBSYM(class_commands)[] = { 71185454Smarcel { "add", 0, gpart_issue, { 72193673Smarcel { 'b', "start", autofill, G_TYPE_ASCLBA }, 73193673Smarcel { 's', "size", autofill, G_TYPE_ASCLBA }, 74169586Smarcel { 't', "type", NULL, G_TYPE_STRING }, 75193648Smarcel { 'i', index_param, optional, G_TYPE_ASCNUM }, 76169586Smarcel { 'l', "label", optional, G_TYPE_STRING }, 77169586Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 78169586Smarcel G_OPT_SENTINEL }, 79178180Smarcel "geom", NULL 80169586Smarcel }, 81178180Smarcel { "bootcode", 0, gpart_bootcode, { 82179629Smarcel { 'b', bootcode_param, optional, G_TYPE_STRING }, 83179629Smarcel { 'p', partcode_param, optional, G_TYPE_STRING }, 84193648Smarcel { 'i', index_param, optional, G_TYPE_ASCNUM }, 85178180Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 86178180Smarcel G_OPT_SENTINEL }, 87178180Smarcel "geom", NULL 88178180Smarcel }, 89185454Smarcel { "commit", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, 90185454Smarcel { "create", 0, gpart_issue, { 91169586Smarcel { 's', "scheme", NULL, G_TYPE_STRING }, 92193648Smarcel { 'n', "entries", optional, G_TYPE_ASCNUM }, 93169586Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 94169586Smarcel G_OPT_SENTINEL }, 95169586Smarcel "provider", NULL 96169586Smarcel }, 97185454Smarcel { "delete", 0, gpart_issue, { 98193648Smarcel { 'i', index_param, NULL, G_TYPE_ASCNUM }, 99169586Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 100169586Smarcel G_OPT_SENTINEL }, 101169586Smarcel "geom", NULL 102169586Smarcel }, 103185454Smarcel { "destroy", 0, gpart_issue, { 104169586Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 105169586Smarcel G_OPT_SENTINEL }, 106169586Smarcel "geom", NULL }, 107185454Smarcel { "modify", 0, gpart_issue, { 108193648Smarcel { 'i', index_param, NULL, G_TYPE_ASCNUM }, 109169586Smarcel { 'l', "label", optional, G_TYPE_STRING }, 110169586Smarcel { 't', "type", optional, G_TYPE_STRING }, 111169586Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 112169586Smarcel G_OPT_SENTINEL }, 113169586Smarcel "geom", NULL 114169586Smarcel }, 115185454Smarcel { "set", 0, gpart_issue, { 116179854Smarcel { 'a', "attrib", NULL, G_TYPE_STRING }, 117193648Smarcel { 'i', index_param, NULL, G_TYPE_ASCNUM }, 118179854Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 119179854Smarcel G_OPT_SENTINEL }, 120179854Smarcel "geom", NULL 121179854Smarcel }, 122179769Smarcel { "show", 0, gpart_show, { 123179769Smarcel { 'l', "show_label", NULL, G_TYPE_BOOL }, 124179769Smarcel { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, 125179769Smarcel G_OPT_SENTINEL }, 126179769Smarcel NULL, "[-lr] [geom ...]" 127179769Smarcel }, 128185454Smarcel { "undo", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, 129185454Smarcel { "unset", 0, gpart_issue, { 130179854Smarcel { 'a', "attrib", NULL, G_TYPE_STRING }, 131193648Smarcel { 'i', index_param, NULL, G_TYPE_ASCNUM }, 132179854Smarcel { 'f', "flags", flags, G_TYPE_STRING }, 133179854Smarcel G_OPT_SENTINEL }, 134179854Smarcel "geom", NULL 135179854Smarcel }, 136169586Smarcel G_CMD_SENTINEL 137169586Smarcel}; 138172837Smarcel 139172837Smarcelstatic struct gclass * 140172837Smarcelfind_class(struct gmesh *mesh, const char *name) 141172837Smarcel{ 142172837Smarcel struct gclass *classp; 143172837Smarcel 144172837Smarcel LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 145172837Smarcel if (strcmp(classp->lg_name, name) == 0) 146172837Smarcel return (classp); 147172837Smarcel } 148172837Smarcel return (NULL); 149172837Smarcel} 150172837Smarcel 151172837Smarcelstatic struct ggeom * 152172837Smarcelfind_geom(struct gclass *classp, const char *name) 153172837Smarcel{ 154172837Smarcel struct ggeom *gp; 155172837Smarcel 156172837Smarcel LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 157172837Smarcel if (strcmp(gp->lg_name, name) == 0) 158172837Smarcel return (gp); 159172837Smarcel } 160172837Smarcel return (NULL); 161172837Smarcel} 162172837Smarcel 163172837Smarcelstatic const char * 164172837Smarcelfind_geomcfg(struct ggeom *gp, const char *cfg) 165172837Smarcel{ 166172837Smarcel struct gconfig *gc; 167172837Smarcel 168172837Smarcel LIST_FOREACH(gc, &gp->lg_config, lg_config) { 169172837Smarcel if (!strcmp(gc->lg_name, cfg)) 170172837Smarcel return (gc->lg_val); 171172837Smarcel } 172172837Smarcel return (NULL); 173172837Smarcel} 174172837Smarcel 175172837Smarcelstatic const char * 176172837Smarcelfind_provcfg(struct gprovider *pp, const char *cfg) 177172837Smarcel{ 178172837Smarcel struct gconfig *gc; 179172837Smarcel 180172837Smarcel LIST_FOREACH(gc, &pp->lg_config, lg_config) { 181172837Smarcel if (!strcmp(gc->lg_name, cfg)) 182172837Smarcel return (gc->lg_val); 183172837Smarcel } 184172837Smarcel return (NULL); 185172837Smarcel} 186172837Smarcel 187172837Smarcelstatic struct gprovider * 188172837Smarcelfind_provider(struct ggeom *gp, unsigned long long minsector) 189172837Smarcel{ 190172837Smarcel struct gprovider *pp, *bestpp; 191188330Smarcel const char *s; 192172837Smarcel unsigned long long sector, bestsector; 193172837Smarcel 194172837Smarcel bestpp = NULL; 195198478Slulf bestsector = 0; 196172837Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 197188330Smarcel s = find_provcfg(pp, "start"); 198188330Smarcel if (s == NULL) { 199188330Smarcel s = find_provcfg(pp, "offset"); 200188330Smarcel sector = atoll(s) / pp->lg_sectorsize; 201188330Smarcel } else 202188330Smarcel sector = atoll(s); 203188330Smarcel 204172837Smarcel if (sector < minsector) 205172837Smarcel continue; 206172837Smarcel if (bestpp != NULL && sector >= bestsector) 207172837Smarcel continue; 208188330Smarcel 209172837Smarcel bestpp = pp; 210172837Smarcel bestsector = sector; 211172837Smarcel } 212172837Smarcel return (bestpp); 213172837Smarcel} 214172837Smarcel 215172837Smarcelstatic const char * 216185046Smarcelfmtsize(int64_t rawsz) 217172837Smarcel{ 218185046Smarcel static char buf[5]; 219172837Smarcel 220185046Smarcel humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, 221185046Smarcel HN_B | HN_NOSPACE | HN_DECIMAL); 222172837Smarcel return (buf); 223172837Smarcel} 224172837Smarcel 225179854Smarcelstatic const char * 226179854Smarcelfmtattrib(struct gprovider *pp) 227179854Smarcel{ 228184070Smarcel static char buf[128]; 229184070Smarcel struct gconfig *gc; 230184070Smarcel u_int idx; 231179854Smarcel 232184070Smarcel buf[0] = '\0'; 233184070Smarcel idx = 0; 234184070Smarcel LIST_FOREACH(gc, &pp->lg_config, lg_config) { 235184070Smarcel if (strcmp(gc->lg_name, "attrib") != 0) 236184070Smarcel continue; 237184070Smarcel idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", 238184070Smarcel (idx == 0) ? " [" : ",", gc->lg_val); 239184070Smarcel } 240184070Smarcel if (idx > 0) 241184070Smarcel snprintf(buf + idx, sizeof(buf) - idx, "] "); 242179854Smarcel return (buf); 243179854Smarcel} 244179854Smarcel 245193673Smarcelstatic int 246193673Smarcelgpart_autofill(struct gctl_req *req) 247193673Smarcel{ 248193673Smarcel struct gmesh mesh; 249193673Smarcel struct gclass *cp; 250193673Smarcel struct ggeom *gp; 251193673Smarcel struct gprovider *pp; 252193673Smarcel unsigned long long first, last; 253193673Smarcel unsigned long long size, start; 254193673Smarcel unsigned long long lba, len, grade; 255193673Smarcel const char *s; 256193673Smarcel char *val; 257193673Smarcel int error, has_size, has_start; 258193673Smarcel 259193673Smarcel s = gctl_get_ascii(req, "verb"); 260193673Smarcel if (strcmp(s, "add") != 0) 261193673Smarcel return (0); 262193673Smarcel 263193673Smarcel s = gctl_get_ascii(req, "size"); 264193673Smarcel has_size = (*s == '*') ? 0 : 1; 265193673Smarcel size = (has_size) ? (unsigned long long)atoll(s) : 0ULL; 266193673Smarcel 267193673Smarcel s = gctl_get_ascii(req, "start"); 268193673Smarcel has_start = (*s == '*') ? 0 : 1; 269193673Smarcel start = (has_start) ? (unsigned long long)atoll(s) : ~0ULL; 270193673Smarcel 271193673Smarcel /* No autofill necessary. */ 272193673Smarcel if (has_size && has_start) 273193673Smarcel return (0); 274193673Smarcel 275193673Smarcel error = geom_gettree(&mesh); 276193673Smarcel if (error) 277193673Smarcel return (error); 278196278Smarcel s = gctl_get_ascii(req, "class"); 279196278Smarcel if (s == NULL) 280196278Smarcel abort(); 281196278Smarcel cp = find_class(&mesh, s); 282196278Smarcel if (cp == NULL) 283196278Smarcel errx(EXIT_FAILURE, "Class %s not found.", s); 284196278Smarcel s = gctl_get_ascii(req, "geom"); 285196278Smarcel if (s == NULL) 286196278Smarcel abort(); 287196278Smarcel gp = find_geom(cp, s); 288196278Smarcel if (gp == NULL) 289196278Smarcel errx(EXIT_FAILURE, "No such geom: %s.", s); 290193673Smarcel first = atoll(find_geomcfg(gp, "first")); 291193673Smarcel last = atoll(find_geomcfg(gp, "last")); 292193673Smarcel grade = ~0ULL; 293193673Smarcel while ((pp = find_provider(gp, first)) != NULL) { 294193673Smarcel s = find_provcfg(pp, "start"); 295193673Smarcel if (s == NULL) { 296193673Smarcel s = find_provcfg(pp, "offset"); 297193673Smarcel lba = atoll(s) / pp->lg_sectorsize; 298193673Smarcel } else 299193673Smarcel lba = atoll(s); 300193673Smarcel 301193673Smarcel if (first < lba) { 302193673Smarcel /* Free space [first, lba> */ 303193673Smarcel len = lba - first; 304193673Smarcel if (has_size) { 305193673Smarcel if (len >= size && len - size < grade) { 306193673Smarcel start = first; 307193673Smarcel grade = len - size; 308193673Smarcel } 309193673Smarcel } else if (has_start) { 310193673Smarcel if (start >= first && start < lba) { 311193673Smarcel size = lba - start; 312193673Smarcel grade = start - first; 313193673Smarcel } 314193673Smarcel } else { 315193673Smarcel if (grade == ~0ULL || len > size) { 316193673Smarcel start = first; 317193673Smarcel size = len; 318193673Smarcel grade = 0; 319193673Smarcel } 320193673Smarcel } 321193673Smarcel } 322193673Smarcel 323193673Smarcel s = find_provcfg(pp, "end"); 324193673Smarcel if (s == NULL) { 325193673Smarcel s = find_provcfg(pp, "length"); 326193673Smarcel first = lba + atoll(s) / pp->lg_sectorsize; 327193673Smarcel } else 328193673Smarcel first = atoll(s) + 1; 329193673Smarcel } 330193673Smarcel if (first <= last) { 331193673Smarcel /* Free space [first-last] */ 332193673Smarcel len = last - first + 1; 333193673Smarcel if (has_size) { 334193673Smarcel if (len >= size && len - size < grade) { 335193673Smarcel start = first; 336193673Smarcel grade = len - size; 337193673Smarcel } 338193673Smarcel } else if (has_start) { 339193673Smarcel if (start >= first && start <= last) { 340193673Smarcel size = last - start + 1; 341193673Smarcel grade = start - first; 342193673Smarcel } 343193673Smarcel } else { 344193673Smarcel if (grade == ~0ULL || len > size) { 345193673Smarcel start = first; 346193673Smarcel size = len; 347193673Smarcel grade = 0; 348193673Smarcel } 349193673Smarcel } 350193673Smarcel } 351193673Smarcel 352193673Smarcel if (grade == ~0ULL) 353193673Smarcel return (ENOSPC); 354193673Smarcel 355193673Smarcel if (!has_size) { 356193728Sjhb asprintf(&val, "%llu", size); 357193673Smarcel if (val == NULL) 358193673Smarcel return (ENOMEM); 359193673Smarcel gctl_change_param(req, "size", -1, val); 360193673Smarcel } 361193673Smarcel if (!has_start) { 362193728Sjhb asprintf(&val, "%llu", start); 363193673Smarcel if (val == NULL) 364193673Smarcel return (ENOMEM); 365193673Smarcel gctl_change_param(req, "start", -1, val); 366193673Smarcel } 367193673Smarcel return (0); 368193673Smarcel} 369193673Smarcel 370172837Smarcelstatic void 371179769Smarcelgpart_show_geom(struct ggeom *gp, const char *element) 372172837Smarcel{ 373172837Smarcel struct gprovider *pp; 374172837Smarcel const char *s, *scheme; 375172837Smarcel unsigned long long first, last, sector, end; 376188330Smarcel unsigned long long length, secsz; 377172837Smarcel int idx, wblocks, wname; 378172837Smarcel 379172837Smarcel scheme = find_geomcfg(gp, "scheme"); 380172837Smarcel s = find_geomcfg(gp, "first"); 381172837Smarcel first = atoll(s); 382172837Smarcel s = find_geomcfg(gp, "last"); 383172837Smarcel last = atoll(s); 384172837Smarcel wblocks = strlen(s); 385172837Smarcel wname = strlen(gp->lg_name); 386172837Smarcel pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 387172837Smarcel secsz = pp->lg_sectorsize; 388172837Smarcel printf("=>%*llu %*llu %*s %s (%s)\n", 389172837Smarcel wblocks, first, wblocks, (last - first + 1), 390172837Smarcel wname, gp->lg_name, 391172837Smarcel scheme, fmtsize(pp->lg_mediasize)); 392172837Smarcel 393172837Smarcel while ((pp = find_provider(gp, first)) != NULL) { 394188330Smarcel s = find_provcfg(pp, "start"); 395188330Smarcel if (s == NULL) { 396188330Smarcel s = find_provcfg(pp, "offset"); 397188330Smarcel sector = atoll(s) / secsz; 398188330Smarcel } else 399188330Smarcel sector = atoll(s); 400188330Smarcel 401188330Smarcel s = find_provcfg(pp, "end"); 402188330Smarcel if (s == NULL) { 403188330Smarcel s = find_provcfg(pp, "length"); 404188330Smarcel length = atoll(s) / secsz; 405188330Smarcel end = sector + length - 1; 406188330Smarcel } else { 407188330Smarcel end = atoll(s); 408188330Smarcel length = end - sector + 1; 409188330Smarcel } 410172837Smarcel s = find_provcfg(pp, "index"); 411172837Smarcel idx = atoi(s); 412172837Smarcel if (first < sector) { 413172837Smarcel printf(" %*llu %*llu %*s - free - (%s)\n", 414172837Smarcel wblocks, first, wblocks, sector - first, 415172837Smarcel wname, "", 416172837Smarcel fmtsize((sector - first) * secsz)); 417172837Smarcel } 418179854Smarcel printf(" %*llu %*llu %*d %s %s (%s)\n", 419188330Smarcel wblocks, sector, wblocks, length, 420179854Smarcel wname, idx, find_provcfg(pp, element), 421179854Smarcel fmtattrib(pp), fmtsize(pp->lg_mediasize)); 422188330Smarcel first = end + 1; 423172837Smarcel } 424172837Smarcel if (first <= last) { 425188330Smarcel length = last - first + 1; 426172837Smarcel printf(" %*llu %*llu %*s - free - (%s)\n", 427188330Smarcel wblocks, first, wblocks, length, 428172837Smarcel wname, "", 429188330Smarcel fmtsize(length * secsz)); 430172837Smarcel } 431172837Smarcel printf("\n"); 432172837Smarcel} 433172837Smarcel 434179769Smarcelstatic int 435179769Smarcelgpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 436179769Smarcel{ 437179769Smarcel 438179769Smarcel if (!gctl_get_int(req, opt)) 439179769Smarcel return (0); 440179769Smarcel 441179769Smarcel if (elt != NULL) 442179769Smarcel errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 443179769Smarcel 444179769Smarcel return (1); 445179769Smarcel} 446179769Smarcel 447172837Smarcelstatic void 448178180Smarcelgpart_show(struct gctl_req *req, unsigned int fl __unused) 449172837Smarcel{ 450172837Smarcel struct gmesh mesh; 451172837Smarcel struct gclass *classp; 452172837Smarcel struct ggeom *gp; 453179769Smarcel const char *element, *name; 454172837Smarcel int error, i, nargs; 455172837Smarcel 456179769Smarcel element = NULL; 457179769Smarcel if (gpart_show_hasopt(req, "show_label", element)) 458179769Smarcel element = "label"; 459179769Smarcel if (gpart_show_hasopt(req, "show_rawtype", element)) 460179769Smarcel element = "rawtype"; 461179769Smarcel if (element == NULL) 462179769Smarcel element = "type"; 463179769Smarcel 464172837Smarcel name = gctl_get_ascii(req, "class"); 465172837Smarcel if (name == NULL) 466172837Smarcel abort(); 467172837Smarcel error = geom_gettree(&mesh); 468172837Smarcel if (error != 0) 469172837Smarcel errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 470172837Smarcel classp = find_class(&mesh, name); 471172837Smarcel if (classp == NULL) { 472172837Smarcel geom_deletetree(&mesh); 473172837Smarcel errx(EXIT_FAILURE, "Class %s not found.", name); 474172837Smarcel } 475172837Smarcel nargs = gctl_get_int(req, "nargs"); 476172837Smarcel if (nargs > 0) { 477172837Smarcel for (i = 0; i < nargs; i++) { 478172837Smarcel name = gctl_get_ascii(req, "arg%d", i); 479172837Smarcel gp = find_geom(classp, name); 480172837Smarcel if (gp != NULL) 481179769Smarcel gpart_show_geom(gp, element); 482172837Smarcel else 483172837Smarcel errx(EXIT_FAILURE, "No such geom: %s.", name); 484172837Smarcel } 485172837Smarcel } else { 486172837Smarcel LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 487179769Smarcel gpart_show_geom(gp, element); 488172837Smarcel } 489172837Smarcel } 490172837Smarcel geom_deletetree(&mesh); 491172837Smarcel} 492178180Smarcel 493179629Smarcelstatic void * 494179629Smarcelgpart_bootfile_read(const char *bootfile, ssize_t *size) 495178180Smarcel{ 496178180Smarcel struct stat sb; 497178180Smarcel void *code; 498179629Smarcel int fd; 499178180Smarcel 500179629Smarcel if (stat(bootfile, &sb) == -1) 501179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 502178180Smarcel if (!S_ISREG(sb.st_mode)) 503178180Smarcel errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 504179629Smarcel if (sb.st_size == 0) 505179629Smarcel errx(EXIT_FAILURE, "%s: empty file", bootfile); 506179629Smarcel if (*size > 0 && sb.st_size >= *size) 507179629Smarcel errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 508179629Smarcel *size); 509178180Smarcel 510179629Smarcel *size = sb.st_size; 511178180Smarcel 512178180Smarcel fd = open(bootfile, O_RDONLY); 513178180Smarcel if (fd == -1) 514179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 515179629Smarcel code = malloc(*size); 516178180Smarcel if (code == NULL) 517179629Smarcel err(EXIT_FAILURE, NULL); 518179629Smarcel if (read(fd, code, *size) != *size) 519179629Smarcel err(EXIT_FAILURE, "%s", bootfile); 520178180Smarcel close(fd); 521178180Smarcel 522179629Smarcel return (code); 523178180Smarcel} 524179629Smarcel 525179629Smarcelstatic void 526179629Smarcelgpart_write_partcode(struct gctl_req *req, int idx, void *code, ssize_t size) 527179629Smarcel{ 528179629Smarcel char dsf[128]; 529179629Smarcel struct gmesh mesh; 530179629Smarcel struct gclass *classp; 531179629Smarcel struct ggeom *gp; 532179629Smarcel struct gprovider *pp; 533179629Smarcel const char *s; 534185038Smarcel char *buf; 535185038Smarcel off_t bsize; 536179629Smarcel int error, fd; 537179629Smarcel 538179629Smarcel s = gctl_get_ascii(req, "class"); 539179629Smarcel if (s == NULL) 540179629Smarcel abort(); 541179629Smarcel error = geom_gettree(&mesh); 542179629Smarcel if (error != 0) 543179629Smarcel errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 544179629Smarcel classp = find_class(&mesh, s); 545179629Smarcel if (classp == NULL) { 546179629Smarcel geom_deletetree(&mesh); 547179629Smarcel errx(EXIT_FAILURE, "Class %s not found.", s); 548179629Smarcel } 549179629Smarcel s = gctl_get_ascii(req, "geom"); 550196278Smarcel if (s == NULL) 551196278Smarcel abort(); 552179629Smarcel gp = find_geom(classp, s); 553179629Smarcel if (gp == NULL) 554179629Smarcel errx(EXIT_FAILURE, "No such geom: %s.", s); 555179629Smarcel 556179629Smarcel LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 557179629Smarcel s = find_provcfg(pp, "index"); 558179629Smarcel if (s == NULL) 559179629Smarcel continue; 560179629Smarcel if (atoi(s) == idx) 561179629Smarcel break; 562179629Smarcel } 563179629Smarcel 564179629Smarcel if (pp != NULL) { 565179629Smarcel snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 566179629Smarcel fd = open(dsf, O_WRONLY); 567179629Smarcel if (fd == -1) 568179629Smarcel err(EXIT_FAILURE, "%s", dsf); 569179629Smarcel if (lseek(fd, size, SEEK_SET) != size) 570179629Smarcel errx(EXIT_FAILURE, "%s: not enough space", dsf); 571179629Smarcel if (lseek(fd, 0, SEEK_SET) != 0) 572179629Smarcel err(EXIT_FAILURE, "%s", dsf); 573185038Smarcel 574185038Smarcel /* 575185038Smarcel * When writing to a disk device, the write must be 576185038Smarcel * sector aligned and not write to any partial sectors, 577185038Smarcel * so round up the buffer size to the next sector and zero it. 578185038Smarcel */ 579185038Smarcel bsize = (size + pp->lg_sectorsize - 1) / 580185038Smarcel pp->lg_sectorsize * pp->lg_sectorsize; 581185038Smarcel buf = calloc(1, bsize); 582185038Smarcel if (buf == NULL) 583179629Smarcel err(EXIT_FAILURE, "%s", dsf); 584185038Smarcel bcopy(code, buf, size); 585185038Smarcel if (write(fd, buf, bsize) != bsize) 586185038Smarcel err(EXIT_FAILURE, "%s", dsf); 587185038Smarcel free(buf); 588179629Smarcel close(fd); 589179629Smarcel } else 590179629Smarcel errx(EXIT_FAILURE, "invalid partition index"); 591179629Smarcel 592179629Smarcel geom_deletetree(&mesh); 593179629Smarcel} 594179629Smarcel 595179629Smarcelstatic void 596185454Smarcelgpart_bootcode(struct gctl_req *req, unsigned int fl) 597179629Smarcel{ 598179629Smarcel const char *s; 599179629Smarcel char *sp; 600179629Smarcel void *bootcode, *partcode; 601179629Smarcel size_t bootsize, partsize; 602179629Smarcel int error, idx; 603179629Smarcel 604179629Smarcel if (gctl_has_param(req, bootcode_param)) { 605179629Smarcel s = gctl_get_ascii(req, bootcode_param); 606179629Smarcel bootsize = 64 * 1024; /* Arbitrary limit. */ 607179629Smarcel bootcode = gpart_bootfile_read(s, &bootsize); 608179629Smarcel error = gctl_change_param(req, bootcode_param, bootsize, 609179629Smarcel bootcode); 610179629Smarcel if (error) 611179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 612179629Smarcel } else { 613179629Smarcel bootcode = NULL; 614179629Smarcel bootsize = 0; 615179629Smarcel } 616179629Smarcel 617179629Smarcel if (gctl_has_param(req, partcode_param)) { 618179629Smarcel s = gctl_get_ascii(req, partcode_param); 619179629Smarcel partsize = bootsize * 1024; 620179629Smarcel partcode = gpart_bootfile_read(s, &partsize); 621179629Smarcel error = gctl_delete_param(req, partcode_param); 622179629Smarcel if (error) 623179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 624179629Smarcel } else { 625179629Smarcel partcode = NULL; 626179629Smarcel partsize = 0; 627179629Smarcel } 628179629Smarcel 629179629Smarcel if (gctl_has_param(req, index_param)) { 630179629Smarcel if (partcode == NULL) 631179629Smarcel errx(EXIT_FAILURE, "-i is only valid with -p"); 632179629Smarcel s = gctl_get_ascii(req, index_param); 633179629Smarcel idx = strtol(s, &sp, 10); 634179629Smarcel if (idx < 1 || *s == '\0' || *sp != '\0') 635179629Smarcel errx(EXIT_FAILURE, "invalid partition index"); 636179629Smarcel error = gctl_delete_param(req, index_param); 637179629Smarcel if (error) 638179629Smarcel errc(EXIT_FAILURE, error, "internal error"); 639179629Smarcel } else 640179629Smarcel idx = 0; 641179629Smarcel 642179629Smarcel if (partcode != NULL) { 643179629Smarcel if (idx == 0) 644179629Smarcel errx(EXIT_FAILURE, "missing -i option"); 645179629Smarcel gpart_write_partcode(req, idx, partcode, partsize); 646179629Smarcel } else { 647179629Smarcel if (bootcode == NULL) 648179629Smarcel errx(EXIT_FAILURE, "no -b nor -p"); 649179629Smarcel } 650179629Smarcel 651185454Smarcel if (bootcode != NULL) 652185454Smarcel gpart_issue(req, fl); 653185454Smarcel} 654185454Smarcel 655185454Smarcelstatic void 656185454Smarcelgpart_issue(struct gctl_req *req, unsigned int fl __unused) 657185454Smarcel{ 658185454Smarcel char buf[4096]; 659185454Smarcel char *errmsg; 660185454Smarcel const char *errstr; 661185495Smarcel int error, status; 662185454Smarcel 663193673Smarcel /* autofill parameters (if applicable). */ 664193673Smarcel error = gpart_autofill(req); 665193673Smarcel if (error) { 666193673Smarcel warnc(error, "autofill"); 667193673Smarcel status = EXIT_FAILURE; 668193673Smarcel goto done; 669193673Smarcel } 670193673Smarcel 671185454Smarcel bzero(buf, sizeof(buf)); 672185454Smarcel gctl_rw_param(req, "output", sizeof(buf), buf); 673185454Smarcel errstr = gctl_issue(req); 674185454Smarcel if (errstr == NULL || errstr[0] == '\0') { 675185454Smarcel if (buf[0] != '\0') 676185454Smarcel printf("%s", buf); 677185495Smarcel status = EXIT_SUCCESS; 678185495Smarcel goto done; 679179629Smarcel } 680185454Smarcel 681185454Smarcel error = strtol(errstr, &errmsg, 0); 682185496Smarcel if (errmsg != errstr) { 683185496Smarcel while (errmsg[0] == ' ') 684185496Smarcel errmsg++; 685185496Smarcel if (errmsg[0] != '\0') 686185496Smarcel warnc(error, "%s", errmsg); 687185496Smarcel else 688185496Smarcel warnc(error, NULL); 689185496Smarcel } else 690185496Smarcel warnx("%s", errmsg); 691185495Smarcel 692185495Smarcel status = EXIT_FAILURE; 693185495Smarcel 694185495Smarcel done: 695185495Smarcel gctl_free(req); 696185495Smarcel exit(status); 697179629Smarcel} 698