1/*- 2 * Copyright (c) 2007, 2008 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h>
|
28__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 188330 2009-02-08 20:19:19Z marcel $");
|
28__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 193648 2009-06-07 20:12:14Z marcel $"); |
29 30#include <sys/stat.h> 31 32#include <assert.h> 33#include <err.h> 34#include <errno.h> 35#include <fcntl.h> 36#include <libgeom.h> 37#include <libutil.h> 38#include <paths.h> 39#include <stdint.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <strings.h> 44#include <unistd.h> 45 46#include "core/geom.h" 47#include "misc/subr.h" 48 49#ifdef STATIC_GEOM_CLASSES 50#define PUBSYM(x) gpart_##x 51#else 52#define PUBSYM(x) x 53#endif 54 55uint32_t PUBSYM(lib_version) = G_LIB_VERSION; 56uint32_t PUBSYM(version) = 0; 57 58static char optional[] = ""; 59static char flags[] = "C"; 60 61static char bootcode_param[] = "bootcode"; 62static char index_param[] = "index"; 63static char partcode_param[] = "partcode"; 64 65static void gpart_bootcode(struct gctl_req *, unsigned int); 66static void gpart_issue(struct gctl_req *, unsigned int); 67static void gpart_show(struct gctl_req *, unsigned int); 68 69struct g_command PUBSYM(class_commands)[] = { 70 { "add", 0, gpart_issue, {
|
71 { 'b', "start", NULL, G_TYPE_STRING },
72 { 's', "size", NULL, G_TYPE_STRING },
|
71 { 'b', "start", NULL, G_TYPE_ASCLBA }, 72 { 's', "size", NULL, G_TYPE_ASCLBA }, |
73 { 't', "type", NULL, G_TYPE_STRING },
|
74 { 'i', index_param, optional, G_TYPE_STRING },
|
74 { 'i', index_param, optional, G_TYPE_ASCNUM }, |
75 { 'l', "label", optional, G_TYPE_STRING }, 76 { 'f', "flags", flags, G_TYPE_STRING }, 77 G_OPT_SENTINEL }, 78 "geom", NULL 79 }, 80 { "bootcode", 0, gpart_bootcode, { 81 { 'b', bootcode_param, optional, G_TYPE_STRING }, 82 { 'p', partcode_param, optional, G_TYPE_STRING },
|
83 { 'i', index_param, optional, G_TYPE_STRING },
|
83 { 'i', index_param, optional, G_TYPE_ASCNUM }, |
84 { 'f', "flags", flags, G_TYPE_STRING }, 85 G_OPT_SENTINEL }, 86 "geom", NULL 87 }, 88 { "commit", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, 89 { "create", 0, gpart_issue, { 90 { 's', "scheme", NULL, G_TYPE_STRING },
|
91 { 'n', "entries", optional, G_TYPE_STRING },
|
91 { 'n', "entries", optional, G_TYPE_ASCNUM }, |
92 { 'f', "flags", flags, G_TYPE_STRING }, 93 G_OPT_SENTINEL }, 94 "provider", NULL 95 }, 96 { "delete", 0, gpart_issue, {
|
97 { 'i', index_param, NULL, G_TYPE_STRING },
|
97 { 'i', index_param, NULL, G_TYPE_ASCNUM }, |
98 { 'f', "flags", flags, G_TYPE_STRING }, 99 G_OPT_SENTINEL }, 100 "geom", NULL 101 }, 102 { "destroy", 0, gpart_issue, { 103 { 'f', "flags", flags, G_TYPE_STRING }, 104 G_OPT_SENTINEL }, 105 "geom", NULL }, 106 { "modify", 0, gpart_issue, {
|
107 { 'i', index_param, NULL, G_TYPE_STRING },
|
107 { 'i', index_param, NULL, G_TYPE_ASCNUM }, |
108 { 'l', "label", optional, G_TYPE_STRING }, 109 { 't', "type", optional, G_TYPE_STRING }, 110 { 'f', "flags", flags, G_TYPE_STRING }, 111 G_OPT_SENTINEL }, 112 "geom", NULL 113 }, 114 { "set", 0, gpart_issue, { 115 { 'a', "attrib", NULL, G_TYPE_STRING },
|
116 { 'i', index_param, NULL, G_TYPE_STRING },
|
116 { 'i', index_param, NULL, G_TYPE_ASCNUM }, |
117 { 'f', "flags", flags, G_TYPE_STRING }, 118 G_OPT_SENTINEL }, 119 "geom", NULL 120 }, 121 { "show", 0, gpart_show, { 122 { 'l', "show_label", NULL, G_TYPE_BOOL }, 123 { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, 124 G_OPT_SENTINEL }, 125 NULL, "[-lr] [geom ...]" 126 }, 127 { "undo", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, 128 { "unset", 0, gpart_issue, { 129 { 'a', "attrib", NULL, G_TYPE_STRING },
|
130 { 'i', index_param, NULL, G_TYPE_STRING },
|
130 { 'i', index_param, NULL, G_TYPE_ASCNUM }, |
131 { 'f', "flags", flags, G_TYPE_STRING }, 132 G_OPT_SENTINEL }, 133 "geom", NULL 134 }, 135 G_CMD_SENTINEL 136}; 137 138static struct gclass * 139find_class(struct gmesh *mesh, const char *name) 140{ 141 struct gclass *classp; 142 143 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 144 if (strcmp(classp->lg_name, name) == 0) 145 return (classp); 146 } 147 return (NULL); 148} 149 150static struct ggeom * 151find_geom(struct gclass *classp, const char *name) 152{ 153 struct ggeom *gp; 154 155 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 156 if (strcmp(gp->lg_name, name) == 0) 157 return (gp); 158 } 159 return (NULL); 160} 161 162static const char * 163find_geomcfg(struct ggeom *gp, const char *cfg) 164{ 165 struct gconfig *gc; 166 167 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 168 if (!strcmp(gc->lg_name, cfg)) 169 return (gc->lg_val); 170 } 171 return (NULL); 172} 173 174static const char * 175find_provcfg(struct gprovider *pp, const char *cfg) 176{ 177 struct gconfig *gc; 178 179 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 180 if (!strcmp(gc->lg_name, cfg)) 181 return (gc->lg_val); 182 } 183 return (NULL); 184} 185 186static struct gprovider * 187find_provider(struct ggeom *gp, unsigned long long minsector) 188{ 189 struct gprovider *pp, *bestpp; 190 const char *s; 191 unsigned long long sector, bestsector; 192 193 bestpp = NULL; 194 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 195 s = find_provcfg(pp, "start"); 196 if (s == NULL) { 197 s = find_provcfg(pp, "offset"); 198 sector = atoll(s) / pp->lg_sectorsize; 199 } else 200 sector = atoll(s); 201 202 if (sector < minsector) 203 continue; 204 if (bestpp != NULL && sector >= bestsector) 205 continue; 206 207 bestpp = pp; 208 bestsector = sector; 209 } 210 return (bestpp); 211} 212 213static const char * 214fmtsize(int64_t rawsz) 215{ 216 static char buf[5]; 217 218 humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, 219 HN_B | HN_NOSPACE | HN_DECIMAL); 220 return (buf); 221} 222 223static const char * 224fmtattrib(struct gprovider *pp) 225{ 226 static char buf[128]; 227 struct gconfig *gc; 228 u_int idx; 229 230 buf[0] = '\0'; 231 idx = 0; 232 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 233 if (strcmp(gc->lg_name, "attrib") != 0) 234 continue; 235 idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", 236 (idx == 0) ? " [" : ",", gc->lg_val); 237 } 238 if (idx > 0) 239 snprintf(buf + idx, sizeof(buf) - idx, "] "); 240 return (buf); 241} 242 243static void 244gpart_show_geom(struct ggeom *gp, const char *element) 245{ 246 struct gprovider *pp; 247 const char *s, *scheme; 248 unsigned long long first, last, sector, end; 249 unsigned long long length, secsz; 250 int idx, wblocks, wname; 251 252 scheme = find_geomcfg(gp, "scheme"); 253 s = find_geomcfg(gp, "first"); 254 first = atoll(s); 255 s = find_geomcfg(gp, "last"); 256 last = atoll(s); 257 wblocks = strlen(s); 258 wname = strlen(gp->lg_name); 259 pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; 260 secsz = pp->lg_sectorsize; 261 printf("=>%*llu %*llu %*s %s (%s)\n", 262 wblocks, first, wblocks, (last - first + 1), 263 wname, gp->lg_name, 264 scheme, fmtsize(pp->lg_mediasize)); 265 266 while ((pp = find_provider(gp, first)) != NULL) { 267 s = find_provcfg(pp, "start"); 268 if (s == NULL) { 269 s = find_provcfg(pp, "offset"); 270 sector = atoll(s) / secsz; 271 } else 272 sector = atoll(s); 273 274 s = find_provcfg(pp, "end"); 275 if (s == NULL) { 276 s = find_provcfg(pp, "length"); 277 length = atoll(s) / secsz; 278 end = sector + length - 1; 279 } else { 280 end = atoll(s); 281 length = end - sector + 1; 282 } 283 s = find_provcfg(pp, "index"); 284 idx = atoi(s); 285 if (first < sector) { 286 printf(" %*llu %*llu %*s - free - (%s)\n", 287 wblocks, first, wblocks, sector - first, 288 wname, "", 289 fmtsize((sector - first) * secsz)); 290 } 291 printf(" %*llu %*llu %*d %s %s (%s)\n", 292 wblocks, sector, wblocks, length, 293 wname, idx, find_provcfg(pp, element), 294 fmtattrib(pp), fmtsize(pp->lg_mediasize)); 295 first = end + 1; 296 } 297 if (first <= last) { 298 length = last - first + 1; 299 printf(" %*llu %*llu %*s - free - (%s)\n", 300 wblocks, first, wblocks, length, 301 wname, "", 302 fmtsize(length * secsz)); 303 } 304 printf("\n"); 305} 306 307static int 308gpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) 309{ 310 311 if (!gctl_get_int(req, opt)) 312 return (0); 313 314 if (elt != NULL) 315 errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); 316 317 return (1); 318} 319 320static void 321gpart_show(struct gctl_req *req, unsigned int fl __unused) 322{ 323 struct gmesh mesh; 324 struct gclass *classp; 325 struct ggeom *gp; 326 const char *element, *name; 327 int error, i, nargs; 328 329 element = NULL; 330 if (gpart_show_hasopt(req, "show_label", element)) 331 element = "label"; 332 if (gpart_show_hasopt(req, "show_rawtype", element)) 333 element = "rawtype"; 334 if (element == NULL) 335 element = "type"; 336 337 name = gctl_get_ascii(req, "class"); 338 if (name == NULL) 339 abort(); 340 error = geom_gettree(&mesh); 341 if (error != 0) 342 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 343 classp = find_class(&mesh, name); 344 if (classp == NULL) { 345 geom_deletetree(&mesh); 346 errx(EXIT_FAILURE, "Class %s not found.", name); 347 } 348 nargs = gctl_get_int(req, "nargs"); 349 if (nargs > 0) { 350 for (i = 0; i < nargs; i++) { 351 name = gctl_get_ascii(req, "arg%d", i); 352 gp = find_geom(classp, name); 353 if (gp != NULL) 354 gpart_show_geom(gp, element); 355 else 356 errx(EXIT_FAILURE, "No such geom: %s.", name); 357 } 358 } else { 359 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 360 gpart_show_geom(gp, element); 361 } 362 } 363 geom_deletetree(&mesh); 364} 365 366static void * 367gpart_bootfile_read(const char *bootfile, ssize_t *size) 368{ 369 struct stat sb; 370 void *code; 371 int fd; 372 373 if (stat(bootfile, &sb) == -1) 374 err(EXIT_FAILURE, "%s", bootfile); 375 if (!S_ISREG(sb.st_mode)) 376 errx(EXIT_FAILURE, "%s: not a regular file", bootfile); 377 if (sb.st_size == 0) 378 errx(EXIT_FAILURE, "%s: empty file", bootfile); 379 if (*size > 0 && sb.st_size >= *size) 380 errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, 381 *size); 382 383 *size = sb.st_size; 384 385 fd = open(bootfile, O_RDONLY); 386 if (fd == -1) 387 err(EXIT_FAILURE, "%s", bootfile); 388 code = malloc(*size); 389 if (code == NULL) 390 err(EXIT_FAILURE, NULL); 391 if (read(fd, code, *size) != *size) 392 err(EXIT_FAILURE, "%s", bootfile); 393 close(fd); 394 395 return (code); 396} 397 398static void 399gpart_write_partcode(struct gctl_req *req, int idx, void *code, ssize_t size) 400{ 401 char dsf[128]; 402 struct gmesh mesh; 403 struct gclass *classp; 404 struct ggeom *gp; 405 struct gprovider *pp; 406 const char *s; 407 char *buf; 408 off_t bsize; 409 int error, fd; 410 411 s = gctl_get_ascii(req, "class"); 412 if (s == NULL) 413 abort(); 414 error = geom_gettree(&mesh); 415 if (error != 0) 416 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 417 classp = find_class(&mesh, s); 418 if (classp == NULL) { 419 geom_deletetree(&mesh); 420 errx(EXIT_FAILURE, "Class %s not found.", s); 421 } 422 s = gctl_get_ascii(req, "geom"); 423 gp = find_geom(classp, s); 424 if (gp == NULL) 425 errx(EXIT_FAILURE, "No such geom: %s.", s); 426 427 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 428 s = find_provcfg(pp, "index"); 429 if (s == NULL) 430 continue; 431 if (atoi(s) == idx) 432 break; 433 } 434 435 if (pp != NULL) { 436 snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); 437 fd = open(dsf, O_WRONLY); 438 if (fd == -1) 439 err(EXIT_FAILURE, "%s", dsf); 440 if (lseek(fd, size, SEEK_SET) != size) 441 errx(EXIT_FAILURE, "%s: not enough space", dsf); 442 if (lseek(fd, 0, SEEK_SET) != 0) 443 err(EXIT_FAILURE, "%s", dsf); 444 445 /* 446 * When writing to a disk device, the write must be 447 * sector aligned and not write to any partial sectors, 448 * so round up the buffer size to the next sector and zero it. 449 */ 450 bsize = (size + pp->lg_sectorsize - 1) / 451 pp->lg_sectorsize * pp->lg_sectorsize; 452 buf = calloc(1, bsize); 453 if (buf == NULL) 454 err(EXIT_FAILURE, "%s", dsf); 455 bcopy(code, buf, size); 456 if (write(fd, buf, bsize) != bsize) 457 err(EXIT_FAILURE, "%s", dsf); 458 free(buf); 459 close(fd); 460 } else 461 errx(EXIT_FAILURE, "invalid partition index"); 462 463 geom_deletetree(&mesh); 464} 465 466static void 467gpart_bootcode(struct gctl_req *req, unsigned int fl) 468{ 469 const char *s; 470 char *sp; 471 void *bootcode, *partcode; 472 size_t bootsize, partsize; 473 int error, idx; 474 475 if (gctl_has_param(req, bootcode_param)) { 476 s = gctl_get_ascii(req, bootcode_param); 477 bootsize = 64 * 1024; /* Arbitrary limit. */ 478 bootcode = gpart_bootfile_read(s, &bootsize); 479 error = gctl_change_param(req, bootcode_param, bootsize, 480 bootcode); 481 if (error) 482 errc(EXIT_FAILURE, error, "internal error"); 483 } else { 484 bootcode = NULL; 485 bootsize = 0; 486 } 487 488 if (gctl_has_param(req, partcode_param)) { 489 s = gctl_get_ascii(req, partcode_param); 490 partsize = bootsize * 1024; 491 partcode = gpart_bootfile_read(s, &partsize); 492 error = gctl_delete_param(req, partcode_param); 493 if (error) 494 errc(EXIT_FAILURE, error, "internal error"); 495 } else { 496 partcode = NULL; 497 partsize = 0; 498 } 499 500 if (gctl_has_param(req, index_param)) { 501 if (partcode == NULL) 502 errx(EXIT_FAILURE, "-i is only valid with -p"); 503 s = gctl_get_ascii(req, index_param); 504 idx = strtol(s, &sp, 10); 505 if (idx < 1 || *s == '\0' || *sp != '\0') 506 errx(EXIT_FAILURE, "invalid partition index"); 507 error = gctl_delete_param(req, index_param); 508 if (error) 509 errc(EXIT_FAILURE, error, "internal error"); 510 } else 511 idx = 0; 512 513 if (partcode != NULL) { 514 if (idx == 0) 515 errx(EXIT_FAILURE, "missing -i option"); 516 gpart_write_partcode(req, idx, partcode, partsize); 517 } else { 518 if (bootcode == NULL) 519 errx(EXIT_FAILURE, "no -b nor -p"); 520 } 521 522 if (bootcode != NULL) 523 gpart_issue(req, fl); 524} 525 526static void 527gpart_issue(struct gctl_req *req, unsigned int fl __unused) 528{ 529 char buf[4096]; 530 char *errmsg; 531 const char *errstr; 532 int error, status; 533 534 bzero(buf, sizeof(buf)); 535 gctl_rw_param(req, "output", sizeof(buf), buf); 536 errstr = gctl_issue(req); 537 if (errstr == NULL || errstr[0] == '\0') { 538 if (buf[0] != '\0') 539 printf("%s", buf); 540 status = EXIT_SUCCESS; 541 goto done; 542 } 543 544 error = strtol(errstr, &errmsg, 0); 545 if (errmsg != errstr) { 546 while (errmsg[0] == ' ') 547 errmsg++; 548 if (errmsg[0] != '\0') 549 warnc(error, "%s", errmsg); 550 else 551 warnc(error, NULL); 552 } else 553 warnx("%s", errmsg); 554 555 status = EXIT_FAILURE; 556 557 done: 558 gctl_free(req); 559 exit(status); 560}
|