1253923Smarcel/*- 2263409Smarcel * Copyright (c) 2013,2014 Juniper Networks, Inc. 3253923Smarcel * All rights reserved. 4253923Smarcel * 5253923Smarcel * Redistribution and use in source and binary forms, with or without 6253923Smarcel * modification, are permitted provided that the following conditions 7253923Smarcel * are met: 8253923Smarcel * 1. Redistributions of source code must retain the above copyright 9253923Smarcel * notice, this list of conditions and the following disclaimer. 10253923Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11253923Smarcel * notice, this list of conditions and the following disclaimer in the 12253923Smarcel * documentation and/or other materials provided with the distribution. 13253923Smarcel * 14253923Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15253923Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16253923Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17253923Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18253923Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19253923Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20253923Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21253923Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22253923Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23253923Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24253923Smarcel * SUCH DAMAGE. 25253923Smarcel */ 26253923Smarcel 27253923Smarcel#include <sys/cdefs.h> 28253923Smarcel__FBSDID("$FreeBSD: releng/11.0/usr.bin/mkimg/mkimg.c 279139 2015-02-22 04:50:47Z marcel $"); 29253923Smarcel 30263409Smarcel#include <sys/linker_set.h> 31253923Smarcel#include <sys/queue.h> 32253923Smarcel#include <sys/stat.h> 33253923Smarcel#include <sys/types.h> 34268236Smarcel#include <sys/uuid.h> 35253923Smarcel#include <errno.h> 36253923Smarcel#include <err.h> 37253923Smarcel#include <fcntl.h> 38272198Smarcel#include <getopt.h> 39253923Smarcel#include <libutil.h> 40263709Smarcel#include <limits.h> 41253923Smarcel#include <stdio.h> 42253923Smarcel#include <stdlib.h> 43253923Smarcel#include <string.h> 44253923Smarcel#include <sysexits.h> 45253923Smarcel#include <unistd.h> 46253923Smarcel 47266176Smarcel#include "image.h" 48266176Smarcel#include "format.h" 49263382Smarcel#include "mkimg.h" 50253923Smarcel#include "scheme.h" 51253923Smarcel 52272198Smarcel#define LONGOPT_FORMATS 0x01000001 53272198Smarcel#define LONGOPT_SCHEMES 0x01000002 54272198Smarcel#define LONGOPT_VERSION 0x01000003 55272198Smarcel 56272198Smarcelstatic struct option longopts[] = { 57272198Smarcel { "formats", no_argument, NULL, LONGOPT_FORMATS }, 58272198Smarcel { "schemes", no_argument, NULL, LONGOPT_SCHEMES }, 59272198Smarcel { "version", no_argument, NULL, LONGOPT_VERSION }, 60272198Smarcel { NULL, 0, NULL, 0 } 61272198Smarcel}; 62272198Smarcel 63279139Smarcelstatic uint64_t capacity; 64279139Smarcel 65263382Smarcelstruct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist); 66263382Smarcelu_int nparts = 0; 67253923Smarcel 68268236Smarcelu_int unit_testing; 69263831Smarcelu_int verbose; 70263831Smarcel 71263709Smarcelu_int ncyls = 0; 72263709Smarcelu_int nheads = 1; 73263709Smarcelu_int nsecs = 1; 74263653Smarcelu_int secsz = 512; 75263831Smarcelu_int blksz = 0; 76263653Smarcel 77253923Smarcelstatic void 78272198Smarcelprint_formats(int usage) 79253923Smarcel{ 80266176Smarcel struct mkimg_format *f, **f_iter; 81272198Smarcel const char *sep; 82272198Smarcel 83272198Smarcel if (usage) { 84272217Smarcel fprintf(stderr, " formats:\n"); 85272198Smarcel SET_FOREACH(f_iter, formats) { 86272198Smarcel f = *f_iter; 87272198Smarcel fprintf(stderr, "\t%s\t- %s\n", f->name, 88272198Smarcel f->description); 89272198Smarcel } 90272198Smarcel } else { 91272198Smarcel sep = ""; 92272198Smarcel SET_FOREACH(f_iter, formats) { 93272198Smarcel f = *f_iter; 94272198Smarcel printf("%s%s", sep, f->name); 95272198Smarcel sep = " "; 96272198Smarcel } 97272198Smarcel putchar('\n'); 98272198Smarcel } 99272198Smarcel} 100272198Smarcel 101272198Smarcelstatic void 102272198Smarcelprint_schemes(int usage) 103272198Smarcel{ 104266176Smarcel struct mkimg_scheme *s, **s_iter; 105272198Smarcel const char *sep; 106263409Smarcel 107272198Smarcel if (usage) { 108272217Smarcel fprintf(stderr, " schemes:\n"); 109272198Smarcel SET_FOREACH(s_iter, schemes) { 110272198Smarcel s = *s_iter; 111272198Smarcel fprintf(stderr, "\t%s\t- %s\n", s->name, 112272198Smarcel s->description); 113272198Smarcel } 114272198Smarcel } else { 115272198Smarcel sep = ""; 116272198Smarcel SET_FOREACH(s_iter, schemes) { 117272198Smarcel s = *s_iter; 118272198Smarcel printf("%s%s", sep, s->name); 119272198Smarcel sep = " "; 120272198Smarcel } 121272198Smarcel putchar('\n'); 122272198Smarcel } 123272198Smarcel} 124272198Smarcel 125272198Smarcelstatic void 126272198Smarcelprint_version(void) 127272198Smarcel{ 128272198Smarcel u_int width; 129272198Smarcel 130272198Smarcel#ifdef __LP64__ 131272198Smarcel width = 64; 132272198Smarcel#else 133272198Smarcel width = 32; 134272198Smarcel#endif 135272198Smarcel printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width); 136272198Smarcel} 137272198Smarcel 138272198Smarcelstatic void 139272198Smarcelusage(const char *why) 140272198Smarcel{ 141272198Smarcel 142253923Smarcel warnx("error: %s", why); 143272217Smarcel fputc('\n', stderr); 144272217Smarcel fprintf(stderr, "usage: %s <options>\n", getprogname()); 145263383Smarcel 146253923Smarcel fprintf(stderr, " options:\n"); 147272217Smarcel fprintf(stderr, "\t--formats\t- list image formats\n"); 148272217Smarcel fprintf(stderr, "\t--schemes\t- list partition schemes\n"); 149272217Smarcel fprintf(stderr, "\t--version\t- show version information\n"); 150272217Smarcel fputc('\n', stderr); 151263383Smarcel fprintf(stderr, "\t-b <file>\t- file containing boot code\n"); 152279139Smarcel fprintf(stderr, "\t-c <num>\t- capacity (in bytes) of the disk\n"); 153266176Smarcel fprintf(stderr, "\t-f <format>\n"); 154263383Smarcel fprintf(stderr, "\t-o <file>\t- file to write image into\n"); 155253923Smarcel fprintf(stderr, "\t-p <partition>\n"); 156253923Smarcel fprintf(stderr, "\t-s <scheme>\n"); 157268264Smarcel fprintf(stderr, "\t-v\t\t- increase verbosity\n"); 158268264Smarcel fprintf(stderr, "\t-y\t\t- [developers] enable unit test\n"); 159263709Smarcel fprintf(stderr, "\t-H <num>\t- number of heads to simulate\n"); 160263709Smarcel fprintf(stderr, "\t-P <num>\t- physical sector size\n"); 161263709Smarcel fprintf(stderr, "\t-S <num>\t- logical sector size\n"); 162263709Smarcel fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n"); 163272217Smarcel fputc('\n', stderr); 164272198Smarcel print_formats(1); 165272217Smarcel fputc('\n', stderr); 166272198Smarcel print_schemes(1); 167272217Smarcel fputc('\n', stderr); 168272217Smarcel fprintf(stderr, " partition specification:\n"); 169263467Smarcel fprintf(stderr, "\t<t>[/<l>]::<size>\t- empty partition of given " 170263467Smarcel "size\n"); 171263467Smarcel fprintf(stderr, "\t<t>[/<l>]:=<file>\t- partition content and size " 172263467Smarcel "are determined\n\t\t\t\t by the named file\n"); 173263864Smarcel fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t- partition content and size " 174263467Smarcel "are taken from\n\t\t\t\t the output of the command to run\n"); 175271482Smarcel fprintf(stderr, "\t-\t\t\t- unused partition entry\n"); 176263383Smarcel fprintf(stderr, "\t where:\n"); 177263467Smarcel fprintf(stderr, "\t\t<t>\t- scheme neutral partition type\n"); 178263467Smarcel fprintf(stderr, "\t\t<l>\t- optional scheme-dependent partition " 179263467Smarcel "label\n"); 180263383Smarcel 181253923Smarcel exit(EX_USAGE); 182253923Smarcel} 183253923Smarcel 184263709Smarcelstatic int 185279139Smarcelparse_uint32(uint32_t *valp, uint32_t min, uint32_t max, const char *arg) 186263709Smarcel{ 187263709Smarcel uint64_t val; 188263709Smarcel 189263709Smarcel if (expand_number(arg, &val) == -1) 190263709Smarcel return (errno); 191263709Smarcel if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max) 192263709Smarcel return (EINVAL); 193279139Smarcel *valp = (uint32_t)val; 194263709Smarcel return (0); 195263709Smarcel} 196263709Smarcel 197263709Smarcelstatic int 198279139Smarcelparse_uint64(uint64_t *valp, uint64_t min, uint64_t max, const char *arg) 199279139Smarcel{ 200279139Smarcel uint64_t val; 201279139Smarcel 202279139Smarcel if (expand_number(arg, &val) == -1) 203279139Smarcel return (errno); 204279139Smarcel if (val < min || val > max) 205279139Smarcel return (EINVAL); 206279139Smarcel *valp = val; 207279139Smarcel return (0); 208279139Smarcel} 209279139Smarcel 210279139Smarcelstatic int 211263709Smarcelpwr_of_two(u_int nr) 212263709Smarcel{ 213263709Smarcel 214263709Smarcel return (((nr & (nr - 1)) == 0) ? 1 : 0); 215263709Smarcel} 216263709Smarcel 217253923Smarcel/* 218253923Smarcel * A partition specification has the following format: 219253923Smarcel * <type> ':' <kind> <contents> 220253923Smarcel * where: 221253923Smarcel * type the partition type alias 222253923Smarcel * kind the interpretation of the contents specification 223253923Smarcel * ':' contents holds the size of an empty partition 224253923Smarcel * '=' contents holds the name of a file to read 225263864Smarcel * '-' contents holds a command to run; the output of 226253923Smarcel * which is the contents of the partition. 227253923Smarcel * contents the specification of a partition's contents 228271482Smarcel * 229271482Smarcel * A specification that is a single dash indicates an unused partition 230271482Smarcel * entry. 231253923Smarcel */ 232253923Smarcelstatic int 233253923Smarcelparse_part(const char *spec) 234253923Smarcel{ 235253923Smarcel struct part *part; 236253923Smarcel char *sep; 237253923Smarcel size_t len; 238253923Smarcel int error; 239253923Smarcel 240271482Smarcel if (strcmp(spec, "-") == 0) { 241271482Smarcel nparts++; 242271482Smarcel return (0); 243271482Smarcel } 244271482Smarcel 245253923Smarcel part = calloc(1, sizeof(struct part)); 246253923Smarcel if (part == NULL) 247253923Smarcel return (ENOMEM); 248253923Smarcel 249253923Smarcel sep = strchr(spec, ':'); 250253923Smarcel if (sep == NULL) { 251253923Smarcel error = EINVAL; 252253923Smarcel goto errout; 253253923Smarcel } 254253923Smarcel len = sep - spec + 1; 255253923Smarcel if (len < 2) { 256253923Smarcel error = EINVAL; 257253923Smarcel goto errout; 258253923Smarcel } 259263414Smarcel part->alias = malloc(len); 260263414Smarcel if (part->alias == NULL) { 261253923Smarcel error = ENOMEM; 262253923Smarcel goto errout; 263253923Smarcel } 264263414Smarcel strlcpy(part->alias, spec, len); 265253923Smarcel spec = sep + 1; 266253923Smarcel 267253923Smarcel switch (*spec) { 268253923Smarcel case ':': 269253923Smarcel part->kind = PART_KIND_SIZE; 270253923Smarcel break; 271253923Smarcel case '=': 272253923Smarcel part->kind = PART_KIND_FILE; 273253923Smarcel break; 274263864Smarcel case '-': 275253923Smarcel part->kind = PART_KIND_PIPE; 276253923Smarcel break; 277253923Smarcel default: 278253923Smarcel error = EINVAL; 279253923Smarcel goto errout; 280253923Smarcel } 281253923Smarcel spec++; 282253923Smarcel 283253923Smarcel part->contents = strdup(spec); 284253923Smarcel if (part->contents == NULL) { 285253923Smarcel error = ENOMEM; 286253923Smarcel goto errout; 287253923Smarcel } 288253923Smarcel 289263466Smarcel spec = part->alias; 290263466Smarcel sep = strchr(spec, '/'); 291263466Smarcel if (sep != NULL) { 292263466Smarcel *sep++ = '\0'; 293263466Smarcel if (strlen(part->alias) == 0 || strlen(sep) == 0) { 294263466Smarcel error = EINVAL; 295263466Smarcel goto errout; 296263466Smarcel } 297263466Smarcel part->label = strdup(sep); 298263466Smarcel if (part->label == NULL) { 299263466Smarcel error = ENOMEM; 300263466Smarcel goto errout; 301263466Smarcel } 302263466Smarcel } 303263466Smarcel 304253923Smarcel part->index = nparts; 305263382Smarcel STAILQ_INSERT_TAIL(&partlist, part, link); 306253923Smarcel nparts++; 307253923Smarcel return (0); 308253923Smarcel 309253923Smarcel errout: 310263414Smarcel if (part->alias != NULL) 311263414Smarcel free(part->alias); 312253923Smarcel free(part); 313253923Smarcel return (error); 314253923Smarcel} 315253923Smarcel 316263857Smarcel#if defined(SPARSE_WRITE) 317266176Smarcelssize_t 318266176Smarcelsparse_write(int fd, const void *ptr, size_t sz) 319263857Smarcel{ 320266176Smarcel const char *buf, *p; 321263857Smarcel off_t ofs; 322263857Smarcel size_t len; 323263857Smarcel ssize_t wr, wrsz; 324263857Smarcel 325266176Smarcel buf = ptr; 326263857Smarcel wrsz = 0; 327263857Smarcel p = memchr(buf, 0, sz); 328263857Smarcel while (sz > 0) { 329263897Smarcel len = (p != NULL) ? (size_t)(p - buf) : sz; 330263857Smarcel if (len > 0) { 331263857Smarcel len = (len + secsz - 1) & ~(secsz - 1); 332263857Smarcel if (len > sz) 333263857Smarcel len = sz; 334263857Smarcel wr = write(fd, buf, len); 335263857Smarcel if (wr < 0) 336263857Smarcel return (-1); 337263857Smarcel } else { 338263857Smarcel while (len < sz && *p++ == '\0') 339263857Smarcel len++; 340263857Smarcel if (len < sz) 341263857Smarcel len &= ~(secsz - 1); 342263857Smarcel if (len == 0) 343263857Smarcel continue; 344263857Smarcel ofs = lseek(fd, len, SEEK_CUR); 345263857Smarcel if (ofs < 0) 346263857Smarcel return (-1); 347263857Smarcel wr = len; 348263857Smarcel } 349263857Smarcel buf += wr; 350263857Smarcel sz -= wr; 351263857Smarcel wrsz += wr; 352263857Smarcel p = memchr(buf, 0, sz); 353263857Smarcel } 354263857Smarcel return (wrsz); 355263857Smarcel} 356263857Smarcel#endif /* SPARSE_WRITE */ 357263857Smarcel 358268236Smarcelvoid 359272485Smarcelmkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp) 360272485Smarcel{ 361272485Smarcel u_int hd, sec; 362272485Smarcel 363272485Smarcel *cylp = *hdp = *secp = ~0U; 364272485Smarcel if (nsecs == 1 || nheads == 1) 365272485Smarcel return; 366272485Smarcel 367272485Smarcel sec = lba % nsecs + 1; 368272485Smarcel lba /= nsecs; 369272485Smarcel hd = lba % nheads; 370272485Smarcel lba /= nheads; 371272485Smarcel if (lba > maxcyl) 372272485Smarcel return; 373272485Smarcel 374272485Smarcel *cylp = lba; 375272485Smarcel *hdp = hd; 376272485Smarcel *secp = sec; 377272485Smarcel} 378272485Smarcel 379272485Smarcelvoid 380268236Smarcelmkimg_uuid(struct uuid *uuid) 381268236Smarcel{ 382268236Smarcel static uint8_t gen[sizeof(struct uuid)]; 383268236Smarcel u_int i; 384268236Smarcel 385268236Smarcel if (!unit_testing) { 386268236Smarcel uuidgen(uuid, 1); 387268236Smarcel return; 388268236Smarcel } 389268236Smarcel 390268236Smarcel for (i = 0; i < sizeof(gen); i++) 391268236Smarcel gen[i]++; 392268236Smarcel memcpy(uuid, gen, sizeof(uuid_t)); 393268236Smarcel} 394268236Smarcel 395279139Smarcelstatic int 396279139Smarcelcapacity_resize(lba_t end) 397279139Smarcel{ 398279139Smarcel lba_t capsz; 399279139Smarcel 400279139Smarcel capsz = (capacity + secsz - 1) / secsz; 401279139Smarcel if (end >= capsz) 402279139Smarcel return (0); 403279139Smarcel return (image_set_size(capsz)); 404279139Smarcel} 405279139Smarcel 406253923Smarcelstatic void 407266176Smarcelmkimg(void) 408253923Smarcel{ 409253923Smarcel FILE *fp; 410253923Smarcel struct part *part; 411263653Smarcel lba_t block; 412263653Smarcel off_t bytesize; 413253923Smarcel int error, fd; 414253923Smarcel 415263442Smarcel /* First check partition information */ 416263442Smarcel STAILQ_FOREACH(part, &partlist, link) { 417263442Smarcel error = scheme_check_part(part); 418263442Smarcel if (error) 419263442Smarcel errc(EX_DATAERR, error, "partition %d", part->index+1); 420263442Smarcel } 421263442Smarcel 422263844Smarcel block = scheme_metadata(SCHEME_META_IMG_START, 0); 423263382Smarcel STAILQ_FOREACH(part, &partlist, link) { 424263844Smarcel block = scheme_metadata(SCHEME_META_PART_BEFORE, block); 425263844Smarcel if (verbose) 426263862Smarcel fprintf(stderr, "partition %d: starting block %llu " 427263862Smarcel "... ", part->index + 1, (long long)block); 428263653Smarcel part->block = block; 429253923Smarcel switch (part->kind) { 430253923Smarcel case PART_KIND_SIZE: 431263653Smarcel if (expand_number(part->contents, &bytesize) == -1) 432253923Smarcel error = errno; 433253923Smarcel break; 434253923Smarcel case PART_KIND_FILE: 435253923Smarcel fd = open(part->contents, O_RDONLY, 0); 436253923Smarcel if (fd != -1) { 437266176Smarcel error = image_copyin(block, fd, &bytesize); 438253923Smarcel close(fd); 439253923Smarcel } else 440253923Smarcel error = errno; 441253923Smarcel break; 442253923Smarcel case PART_KIND_PIPE: 443253923Smarcel fp = popen(part->contents, "r"); 444253923Smarcel if (fp != NULL) { 445266176Smarcel fd = fileno(fp); 446266176Smarcel error = image_copyin(block, fd, &bytesize); 447253923Smarcel pclose(fp); 448253923Smarcel } else 449253923Smarcel error = errno; 450253923Smarcel break; 451253923Smarcel } 452263442Smarcel if (error) 453263844Smarcel errc(EX_IOERR, error, "partition %d", part->index + 1); 454263653Smarcel part->size = (bytesize + secsz - 1) / secsz; 455263844Smarcel if (verbose) { 456263844Smarcel bytesize = part->size * secsz; 457263862Smarcel fprintf(stderr, "size %llu bytes (%llu blocks)\n", 458263844Smarcel (long long)bytesize, (long long)part->size); 459263844Smarcel } 460263844Smarcel block = scheme_metadata(SCHEME_META_PART_AFTER, 461263844Smarcel part->block + part->size); 462253923Smarcel } 463253923Smarcel 464263844Smarcel block = scheme_metadata(SCHEME_META_IMG_END, block); 465266176Smarcel error = image_set_size(block); 466266176Smarcel if (!error) 467279139Smarcel error = capacity_resize(block); 468279139Smarcel if (!error) 469266176Smarcel error = format_resize(block); 470266176Smarcel if (error) 471266176Smarcel errc(EX_IOERR, error, "image sizing"); 472266176Smarcel block = image_get_size(); 473266176Smarcel ncyls = block / (nsecs * nheads); 474279125Smarcel error = scheme_write(block); 475266176Smarcel if (error) 476266176Smarcel errc(EX_IOERR, error, "writing metadata"); 477253923Smarcel} 478253923Smarcel 479253923Smarcelint 480253923Smarcelmain(int argc, char *argv[]) 481253923Smarcel{ 482266176Smarcel int bcfd, outfd; 483253923Smarcel int c, error; 484253923Smarcel 485266176Smarcel bcfd = -1; 486266176Smarcel outfd = 1; /* Write to stdout by default */ 487279139Smarcel while ((c = getopt_long(argc, argv, "b:c:f:o:p:s:vyH:P:S:T:", 488272198Smarcel longopts, NULL)) != -1) { 489253923Smarcel switch (c) { 490253923Smarcel case 'b': /* BOOT CODE */ 491263537Smarcel if (bcfd != -1) 492253923Smarcel usage("multiple bootcode given"); 493253923Smarcel bcfd = open(optarg, O_RDONLY, 0); 494253923Smarcel if (bcfd == -1) 495253923Smarcel err(EX_UNAVAILABLE, "%s", optarg); 496253923Smarcel break; 497279139Smarcel case 'c': /* CAPACITY */ 498279139Smarcel error = parse_uint64(&capacity, 1, OFF_MAX, optarg); 499279139Smarcel if (error) 500279139Smarcel errc(EX_DATAERR, error, "capacity in bytes"); 501279139Smarcel break; 502266176Smarcel case 'f': /* OUTPUT FORMAT */ 503266176Smarcel if (format_selected() != NULL) 504266176Smarcel usage("multiple formats given"); 505266176Smarcel error = format_select(optarg); 506266176Smarcel if (error) 507266176Smarcel errc(EX_DATAERR, error, "format"); 508266176Smarcel break; 509253923Smarcel case 'o': /* OUTPUT FILE */ 510266176Smarcel if (outfd != 1) 511253923Smarcel usage("multiple output files given"); 512253923Smarcel outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 513253923Smarcel S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 514253923Smarcel if (outfd == -1) 515253923Smarcel err(EX_CANTCREAT, "%s", optarg); 516253923Smarcel break; 517253923Smarcel case 'p': /* PARTITION */ 518253923Smarcel error = parse_part(optarg); 519253923Smarcel if (error) 520253923Smarcel errc(EX_DATAERR, error, "partition"); 521253923Smarcel break; 522253923Smarcel case 's': /* SCHEME */ 523263409Smarcel if (scheme_selected() != NULL) 524253923Smarcel usage("multiple schemes given"); 525253923Smarcel error = scheme_select(optarg); 526253923Smarcel if (error) 527253923Smarcel errc(EX_DATAERR, error, "scheme"); 528253923Smarcel break; 529268236Smarcel case 'y': 530268236Smarcel unit_testing++; 531268236Smarcel break; 532263831Smarcel case 'v': 533263831Smarcel verbose++; 534263831Smarcel break; 535263709Smarcel case 'H': /* GEOMETRY: HEADS */ 536279139Smarcel error = parse_uint32(&nheads, 1, 255, optarg); 537263709Smarcel if (error) 538263709Smarcel errc(EX_DATAERR, error, "number of heads"); 539263709Smarcel break; 540263709Smarcel case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */ 541279139Smarcel error = parse_uint32(&blksz, 512, INT_MAX+1U, optarg); 542263709Smarcel if (error == 0 && !pwr_of_two(blksz)) 543263709Smarcel error = EINVAL; 544263709Smarcel if (error) 545263709Smarcel errc(EX_DATAERR, error, "physical sector size"); 546263709Smarcel break; 547263709Smarcel case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */ 548279139Smarcel error = parse_uint32(&secsz, 512, INT_MAX+1U, optarg); 549263831Smarcel if (error == 0 && !pwr_of_two(secsz)) 550263709Smarcel error = EINVAL; 551263709Smarcel if (error) 552263709Smarcel errc(EX_DATAERR, error, "logical sector size"); 553263709Smarcel break; 554263709Smarcel case 'T': /* GEOMETRY: TRACK SIZE */ 555279139Smarcel error = parse_uint32(&nsecs, 1, 63, optarg); 556263709Smarcel if (error) 557263709Smarcel errc(EX_DATAERR, error, "track size"); 558263709Smarcel break; 559272198Smarcel case LONGOPT_FORMATS: 560272198Smarcel print_formats(0); 561272198Smarcel exit(EX_OK); 562272198Smarcel /*NOTREACHED*/ 563272198Smarcel case LONGOPT_SCHEMES: 564272198Smarcel print_schemes(0); 565272198Smarcel exit(EX_OK); 566272198Smarcel /*NOTREACHED*/ 567272198Smarcel case LONGOPT_VERSION: 568272198Smarcel print_version(); 569272198Smarcel exit(EX_OK); 570272198Smarcel /*NOTREACHED*/ 571253923Smarcel default: 572253923Smarcel usage("unknown option"); 573253923Smarcel } 574253923Smarcel } 575263831Smarcel 576253923Smarcel if (argc > optind) 577253923Smarcel usage("trailing arguments"); 578279128Smarcel if (scheme_selected() == NULL && nparts > 0) 579253923Smarcel usage("no scheme"); 580279139Smarcel if (nparts == 0 && capacity == 0) 581253923Smarcel usage("no partitions"); 582253923Smarcel 583263831Smarcel if (secsz > blksz) { 584263831Smarcel if (blksz != 0) 585263831Smarcel errx(EX_DATAERR, "the physical block size cannot " 586263831Smarcel "be smaller than the sector size"); 587263831Smarcel blksz = secsz; 588263831Smarcel } 589263831Smarcel 590263831Smarcel if (secsz > scheme_max_secsz()) 591263831Smarcel errx(EX_DATAERR, "maximum sector size supported is %u; " 592263831Smarcel "size specified is %u", scheme_max_secsz(), secsz); 593263831Smarcel 594263831Smarcel if (nparts > scheme_max_parts()) 595263831Smarcel errx(EX_DATAERR, "%d partitions supported; %d given", 596263831Smarcel scheme_max_parts(), nparts); 597263831Smarcel 598266176Smarcel if (format_selected() == NULL) 599266176Smarcel format_select("raw"); 600253923Smarcel 601266176Smarcel if (bcfd != -1) { 602266176Smarcel error = scheme_bootcode(bcfd); 603266176Smarcel close(bcfd); 604266176Smarcel if (error) 605266176Smarcel errc(EX_DATAERR, error, "boot code"); 606266176Smarcel } 607266176Smarcel 608263831Smarcel if (verbose) { 609263862Smarcel fprintf(stderr, "Logical sector size: %u\n", secsz); 610263862Smarcel fprintf(stderr, "Physical block size: %u\n", blksz); 611263862Smarcel fprintf(stderr, "Sectors per track: %u\n", nsecs); 612263862Smarcel fprintf(stderr, "Number of heads: %u\n", nheads); 613266176Smarcel fputc('\n', stderr); 614279128Smarcel if (scheme_selected()) 615279128Smarcel fprintf(stderr, "Partitioning scheme: %s\n", 616279128Smarcel scheme_selected()->name); 617266176Smarcel fprintf(stderr, "Output file format: %s\n", 618266176Smarcel format_selected()->name); 619266176Smarcel fputc('\n', stderr); 620263831Smarcel } 621263831Smarcel 622266176Smarcel error = image_init(); 623266176Smarcel if (error) 624266176Smarcel errc(EX_OSERR, error, "cannot initialize"); 625253923Smarcel 626266176Smarcel mkimg(); 627266176Smarcel 628266176Smarcel if (verbose) { 629266176Smarcel fputc('\n', stderr); 630263862Smarcel fprintf(stderr, "Number of cylinders: %u\n", ncyls); 631253923Smarcel } 632253923Smarcel 633266176Smarcel error = format_write(outfd); 634266176Smarcel if (error) 635266176Smarcel errc(EX_IOERR, error, "writing image"); 636266176Smarcel 637253923Smarcel return (0); 638253923Smarcel} 639