2 * Copyright (c) 2013,2014 Juniper Networks, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
50 #define LONGOPT_FORMATS 0x01000001
51 #define LONGOPT_SCHEMES 0x01000002
52 #define LONGOPT_VERSION 0x01000003
53 #define LONGOPT_CAPACITY 0x01000004
55 static struct option longopts[] = {
56 { "formats", no_argument, NULL, LONGOPT_FORMATS },
57 { "schemes", no_argument, NULL, LONGOPT_SCHEMES },
58 { "version", no_argument, NULL, LONGOPT_VERSION },
59 { "capacity", required_argument, NULL, LONGOPT_CAPACITY },
63 static uint64_t min_capacity = 0;
64 static uint64_t max_capacity = 0;
66 struct partlisthead partlist = TAILQ_HEAD_INITIALIZER(partlist);
77 uint32_t active_partition = 0;
80 print_formats(int usage)
82 struct mkimg_format *f;
86 fprintf(stderr, " formats:\n");
88 while ((f = format_iterate(f)) != NULL) {
89 fprintf(stderr, "\t%s\t- %s\n", f->name,
95 while ((f = format_iterate(f)) != NULL) {
96 printf("%s%s", sep, f->name);
104 print_schemes(int usage)
106 struct mkimg_scheme *s;
110 fprintf(stderr, " schemes:\n");
112 while ((s = scheme_iterate(s)) != NULL) {
113 fprintf(stderr, "\t%s\t- %s\n", s->name,
119 while ((s = scheme_iterate(s)) != NULL) {
120 printf("%s%s", sep, s->name);
137 printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width);
141 usage(const char *why)
144 warnx("error: %s", why);
146 fprintf(stderr, "usage: %s <options>\n", getprogname());
148 fprintf(stderr, " options:\n");
149 fprintf(stderr, "\t--formats\t- list image formats\n");
150 fprintf(stderr, "\t--schemes\t- list partition schemes\n");
151 fprintf(stderr, "\t--version\t- show version information\n");
153 fprintf(stderr, "\t-a <num>\t- mark num'th partion as active\n");
154 fprintf(stderr, "\t-b <file>\t- file containing boot code\n");
155 fprintf(stderr, "\t-c <num>\t- minimum capacity (in bytes) of the disk\n");
156 fprintf(stderr, "\t-C <num>\t- maximum capacity (in bytes) of the disk\n");
157 fprintf(stderr, "\t-f <format>\n");
158 fprintf(stderr, "\t-o <file>\t- file to write image into\n");
159 fprintf(stderr, "\t-p <partition>\n");
160 fprintf(stderr, "\t-s <scheme>\n");
161 fprintf(stderr, "\t-v\t\t- increase verbosity\n");
162 fprintf(stderr, "\t-y\t\t- [developers] enable unit test\n");
163 fprintf(stderr, "\t-H <num>\t- number of heads to simulate\n");
164 fprintf(stderr, "\t-P <num>\t- physical sector size\n");
165 fprintf(stderr, "\t-S <num>\t- logical sector size\n");
166 fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n");
172 fprintf(stderr, " partition specification:\n");
173 fprintf(stderr, "\t<t>[/<l>]::<size>\t- empty partition of given "
175 fprintf(stderr, "\t<t>[/<l>]:=<file>\t- partition content and size "
176 "are determined\n\t\t\t\t by the named file\n");
177 fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t- partition content and size "
178 "are taken from\n\t\t\t\t the output of the command to run\n");
179 fprintf(stderr, "\t-\t\t\t- unused partition entry\n");
180 fprintf(stderr, "\t where:\n");
181 fprintf(stderr, "\t\t<t>\t- scheme neutral partition type\n");
182 fprintf(stderr, "\t\t<l>\t- optional scheme-dependent partition "
189 parse_uint32(uint32_t *valp, uint32_t min, uint32_t max, const char *arg)
193 if (expand_number(arg, &val) == -1)
195 if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max)
197 *valp = (uint32_t)val;
202 parse_uint64(uint64_t *valp, uint64_t min, uint64_t max, const char *arg)
206 if (expand_number(arg, &val) == -1)
208 if (val < min || val > max)
218 return (((nr & (nr - 1)) == 0) ? 1 : 0);
222 * A partition specification has the following format:
223 * <type> ':' <kind> <contents>
225 * type the partition type alias
226 * kind the interpretation of the contents specification
227 * ':' contents holds the size of an empty partition
228 * '=' contents holds the name of a file to read
229 * '-' contents holds a command to run; the output of
230 * which is the contents of the partition.
231 * contents the specification of a partition's contents
233 * A specification that is a single dash indicates an unused partition
237 parse_part(const char *spec)
244 if (strcmp(spec, "-") == 0) {
249 part = calloc(1, sizeof(struct part));
253 sep = strchr(spec, ':');
258 len = sep - spec + 1;
263 part->alias = malloc(len);
264 if (part->alias == NULL) {
268 strlcpy(part->alias, spec, len);
273 part->kind = PART_KIND_SIZE;
276 part->kind = PART_KIND_FILE;
279 part->kind = PART_KIND_PIPE;
287 part->contents = strdup(spec);
288 if (part->contents == NULL) {
294 sep = strchr(spec, '/');
297 if (strlen(part->alias) == 0 || strlen(sep) == 0) {
301 part->label = strdup(sep);
302 if (part->label == NULL) {
308 part->index = nparts;
309 TAILQ_INSERT_TAIL(&partlist, part, link);
314 if (part->alias != NULL)
320 #if defined(SPARSE_WRITE)
322 sparse_write(int fd, const void *ptr, size_t sz)
331 p = memchr(buf, 0, sz);
333 len = (p != NULL) ? (size_t)(p - buf) : sz;
335 len = (len + secsz - 1) & ~(secsz - 1);
338 wr = write(fd, buf, len);
342 while (len < sz && *p++ == '\0')
348 ofs = lseek(fd, len, SEEK_CUR);
356 p = memchr(buf, 0, sz);
360 #endif /* SPARSE_WRITE */
363 mkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp)
367 *cylp = *hdp = *secp = ~0U;
368 if (nsecs == 1 || nheads == 1)
371 sec = lba % nsecs + 1;
384 capacity_resize(lba_t end)
386 lba_t min_capsz, max_capsz;
388 min_capsz = (min_capacity + secsz - 1) / secsz;
389 max_capsz = (max_capacity + secsz - 1) / secsz;
391 if (max_capsz != 0 && end > max_capsz)
393 if (end >= min_capsz)
396 return (image_set_size(min_capsz));
408 /* First check partition information */
409 TAILQ_FOREACH(part, &partlist, link) {
410 error = scheme_check_part(part);
412 errc(EX_DATAERR, error, "partition %d", part->index+1);
415 block = scheme_metadata(SCHEME_META_IMG_START, 0);
416 TAILQ_FOREACH(part, &partlist, link) {
417 block = scheme_metadata(SCHEME_META_PART_BEFORE, block);
419 fprintf(stderr, "partition %d: starting block %llu "
420 "... ", part->index + 1, (long long)block);
422 switch (part->kind) {
424 if (expand_number(part->contents, &bytesize) == -1)
428 fd = open(part->contents, O_RDONLY, 0);
430 error = image_copyin(block, fd, &bytesize);
436 fp = popen(part->contents, "r");
439 error = image_copyin(block, fd, &bytesize);
446 errc(EX_IOERR, error, "partition %d", part->index + 1);
447 part->size = (bytesize + secsz - 1) / secsz;
449 bytesize = part->size * secsz;
450 fprintf(stderr, "size %llu bytes (%llu blocks)\n",
451 (long long)bytesize, (long long)part->size);
453 block = scheme_metadata(SCHEME_META_PART_AFTER,
454 part->block + part->size);
457 block = scheme_metadata(SCHEME_META_IMG_END, block);
458 error = image_set_size(block);
460 error = capacity_resize(block);
461 block = image_get_size();
464 error = format_resize(block);
465 block = image_get_size();
468 errc(EX_IOERR, error, "image sizing");
469 ncyls = block / (nsecs * nheads);
470 error = scheme_write(block);
472 errc(EX_IOERR, error, "writing metadata");
476 main(int argc, char *argv[])
482 outfd = 1; /* Write to stdout by default */
483 while ((c = getopt_long(argc, argv, "a:b:c:C:f:o:p:s:vyH:P:S:T:",
484 longopts, NULL)) != -1) {
486 case 'a': /* ACTIVE PARTITION, if supported */
487 error = parse_uint32(&active_partition, 1, 100, optarg);
489 errc(EX_DATAERR, error, "Partition ordinal");
491 case 'b': /* BOOT CODE */
493 usage("multiple bootcode given");
494 bcfd = open(optarg, O_RDONLY, 0);
496 err(EX_UNAVAILABLE, "%s", optarg);
498 case 'c': /* MINIMUM CAPACITY */
499 error = parse_uint64(&min_capacity, 1, INT64_MAX, optarg);
501 errc(EX_DATAERR, error, "minimum capacity in bytes");
503 case 'C': /* MAXIMUM CAPACITY */
504 error = parse_uint64(&max_capacity, 1, INT64_MAX, optarg);
506 errc(EX_DATAERR, error, "maximum capacity in bytes");
508 case 'f': /* OUTPUT FORMAT */
509 if (format_selected() != NULL)
510 usage("multiple formats given");
511 error = format_select(optarg);
513 errc(EX_DATAERR, error, "format");
515 case 'o': /* OUTPUT FILE */
517 usage("multiple output files given");
518 outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC,
519 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
521 err(EX_CANTCREAT, "%s", optarg);
523 case 'p': /* PARTITION */
524 error = parse_part(optarg);
526 errc(EX_DATAERR, error, "partition");
528 case 's': /* SCHEME */
529 if (scheme_selected() != NULL)
530 usage("multiple schemes given");
531 error = scheme_select(optarg);
533 errc(EX_DATAERR, error, "scheme");
541 case 'H': /* GEOMETRY: HEADS */
542 error = parse_uint32(&nheads, 1, 255, optarg);
544 errc(EX_DATAERR, error, "number of heads");
546 case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */
547 error = parse_uint32(&blksz, 512, INT_MAX+1U, optarg);
548 if (error == 0 && !pwr_of_two(blksz))
551 errc(EX_DATAERR, error, "physical sector size");
553 case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */
554 error = parse_uint32(&secsz, 512, INT_MAX+1U, optarg);
555 if (error == 0 && !pwr_of_two(secsz))
558 errc(EX_DATAERR, error, "logical sector size");
560 case 'T': /* GEOMETRY: TRACK SIZE */
561 error = parse_uint32(&nsecs, 1, 63, optarg);
563 errc(EX_DATAERR, error, "track size");
565 case LONGOPT_FORMATS:
569 case LONGOPT_SCHEMES:
573 case LONGOPT_VERSION:
577 case LONGOPT_CAPACITY:
578 error = parse_uint64(&min_capacity, 1, INT64_MAX, optarg);
580 errc(EX_DATAERR, error, "capacity in bytes");
581 max_capacity = min_capacity;
584 usage("unknown option");
589 usage("trailing arguments");
590 if (scheme_selected() == NULL && nparts > 0)
592 if (nparts == 0 && min_capacity == 0)
593 usage("no partitions");
594 if (max_capacity != 0 && min_capacity > max_capacity)
595 usage("minimum capacity cannot be larger than the maximum one");
599 errx(EX_DATAERR, "the physical block size cannot "
600 "be smaller than the sector size");
604 if (secsz > scheme_max_secsz())
605 errx(EX_DATAERR, "maximum sector size supported is %u; "
606 "size specified is %u", scheme_max_secsz(), secsz);
608 if (nparts > scheme_max_parts())
609 errx(EX_DATAERR, "%d partitions supported; %d given",
610 scheme_max_parts(), nparts);
612 if (format_selected() == NULL)
613 format_select("raw");
616 error = scheme_bootcode(bcfd);
619 errc(EX_DATAERR, error, "boot code");
623 fprintf(stderr, "Logical sector size: %u\n", secsz);
624 fprintf(stderr, "Physical block size: %u\n", blksz);
625 fprintf(stderr, "Sectors per track: %u\n", nsecs);
626 fprintf(stderr, "Number of heads: %u\n", nheads);
628 if (scheme_selected())
629 fprintf(stderr, "Partitioning scheme: %s\n",
630 scheme_selected()->name);
631 fprintf(stderr, "Output file format: %s\n",
632 format_selected()->name);
636 error = image_init();
638 errc(EX_OSERR, error, "cannot initialize");
644 fprintf(stderr, "Number of cylinders: %u\n", ncyls);
647 error = format_write(outfd);
649 errc(EX_IOERR, error, "writing image");