Index: head/usr.bin/mkimg/format.c =================================================================== --- head/usr.bin/mkimg/format.c (revision 306324) +++ head/usr.bin/mkimg/format.c (revision 306325) @@ -1,87 +1,101 @@ /*- * Copyright (c) 2014 Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include -#include -#include #include #include #include #include #include #include #include #include "image.h" #include "format.h" #include "mkimg.h" +static struct mkimg_format *first; static struct mkimg_format *format; +struct mkimg_format * +format_iterate(struct mkimg_format *f) +{ + + return ((f == NULL) ? first : f->next); +} + +void +format_register(struct mkimg_format *f) +{ + + f->next = first; + first = f; +} + int format_resize(lba_t end) { if (format == NULL) return (ENOSYS); return (format->resize(end)); } int format_select(const char *spec) { - struct mkimg_format *f, **iter; + struct mkimg_format *f; - SET_FOREACH(iter, formats) { - f = *iter; + f = NULL; + while ((f = format_iterate(f)) != NULL) { if (strcasecmp(spec, f->name) == 0) { format = f; return (0); } } return (EINVAL); } struct mkimg_format * format_selected(void) { return (format); } int format_write(int fd) { int error; if (format == NULL) return (ENOSYS); error = format->write(fd); return (error); } Index: head/usr.bin/mkimg/format.h =================================================================== --- head/usr.bin/mkimg/format.h (revision 306324) +++ head/usr.bin/mkimg/format.h (revision 306325) @@ -1,49 +1,52 @@ /*- * Copyright (c) 2014 Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MKIMG_FORMAT_H_ #define _MKIMG_FORMAT_H_ -#include - struct mkimg_format { + struct mkimg_format *next; const char *name; const char *description; int (*resize)(lba_t); int (*write)(int); }; -SET_DECLARE(formats, struct mkimg_format); -#define FORMAT_DEFINE(nm) DATA_SET(formats, nm) +#define FORMAT_DEFINE(nm) \ +static void format_register_##nm(void) __attribute__((constructor)); \ +static void format_register_##nm(void) { format_register(&nm); } -int format_resize(lba_t); +struct mkimg_format *format_iterate(struct mkimg_format *); +void format_register(struct mkimg_format *); int format_select(const char *); struct mkimg_format *format_selected(void); + +int format_resize(lba_t); int format_write(int); #endif /* _MKIMG_FORMAT_H_ */ Index: head/usr.bin/mkimg/mkimg.c =================================================================== --- head/usr.bin/mkimg/mkimg.c (revision 306324) +++ head/usr.bin/mkimg/mkimg.c (revision 306325) @@ -1,641 +1,640 @@ /*- * Copyright (c) 2013,2014 Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "image.h" #include "format.h" #include "mkimg.h" #include "scheme.h" #define LONGOPT_FORMATS 0x01000001 #define LONGOPT_SCHEMES 0x01000002 #define LONGOPT_VERSION 0x01000003 static struct option longopts[] = { { "formats", no_argument, NULL, LONGOPT_FORMATS }, { "schemes", no_argument, NULL, LONGOPT_SCHEMES }, { "version", no_argument, NULL, LONGOPT_VERSION }, { NULL, 0, NULL, 0 } }; static uint64_t capacity; struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist); u_int nparts = 0; u_int unit_testing; u_int verbose; u_int ncyls = 0; u_int nheads = 1; u_int nsecs = 1; u_int secsz = 512; u_int blksz = 0; static void print_formats(int usage) { - struct mkimg_format *f, **f_iter; + struct mkimg_format *f; const char *sep; if (usage) { fprintf(stderr, " formats:\n"); - SET_FOREACH(f_iter, formats) { - f = *f_iter; + f = NULL; + while ((f = format_iterate(f)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", f->name, f->description); } } else { sep = ""; - SET_FOREACH(f_iter, formats) { - f = *f_iter; + f = NULL; + while ((f = format_iterate(f)) != NULL) { printf("%s%s", sep, f->name); sep = " "; } putchar('\n'); } } static void print_schemes(int usage) { - struct mkimg_scheme *s, **s_iter; + struct mkimg_scheme *s; const char *sep; if (usage) { fprintf(stderr, " schemes:\n"); - SET_FOREACH(s_iter, schemes) { - s = *s_iter; + s = NULL; + while ((s = scheme_iterate(s)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", s->name, s->description); } } else { sep = ""; - SET_FOREACH(s_iter, schemes) { - s = *s_iter; + s = NULL; + while ((s = scheme_iterate(s)) != NULL) { printf("%s%s", sep, s->name); sep = " "; } putchar('\n'); } } static void print_version(void) { u_int width; #ifdef __LP64__ width = 64; #else width = 32; #endif printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width); } static void usage(const char *why) { warnx("error: %s", why); fputc('\n', stderr); fprintf(stderr, "usage: %s \n", getprogname()); fprintf(stderr, " options:\n"); fprintf(stderr, "\t--formats\t- list image formats\n"); fprintf(stderr, "\t--schemes\t- list partition schemes\n"); fprintf(stderr, "\t--version\t- show version information\n"); fputc('\n', stderr); fprintf(stderr, "\t-b \t- file containing boot code\n"); fprintf(stderr, "\t-c \t- capacity (in bytes) of the disk\n"); fprintf(stderr, "\t-f \n"); fprintf(stderr, "\t-o \t- file to write image into\n"); fprintf(stderr, "\t-p \n"); fprintf(stderr, "\t-s \n"); fprintf(stderr, "\t-v\t\t- increase verbosity\n"); fprintf(stderr, "\t-y\t\t- [developers] enable unit test\n"); fprintf(stderr, "\t-H \t- number of heads to simulate\n"); fprintf(stderr, "\t-P \t- physical sector size\n"); fprintf(stderr, "\t-S \t- logical sector size\n"); fprintf(stderr, "\t-T \t- number of tracks to simulate\n"); fputc('\n', stderr); print_formats(1); fputc('\n', stderr); print_schemes(1); fputc('\n', stderr); fprintf(stderr, " partition specification:\n"); fprintf(stderr, "\t[/]::\t- empty partition of given " "size\n"); fprintf(stderr, "\t[/]:=\t- partition content and size " "are determined\n\t\t\t\t by the named file\n"); fprintf(stderr, "\t[/]:-\t- partition content and size " "are taken from\n\t\t\t\t the output of the command to run\n"); fprintf(stderr, "\t-\t\t\t- unused partition entry\n"); fprintf(stderr, "\t where:\n"); fprintf(stderr, "\t\t\t- scheme neutral partition type\n"); fprintf(stderr, "\t\t\t- optional scheme-dependent partition " "label\n"); exit(EX_USAGE); } static int parse_uint32(uint32_t *valp, uint32_t min, uint32_t max, const char *arg) { uint64_t val; if (expand_number(arg, &val) == -1) return (errno); if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max) return (EINVAL); *valp = (uint32_t)val; return (0); } static int parse_uint64(uint64_t *valp, uint64_t min, uint64_t max, const char *arg) { uint64_t val; if (expand_number(arg, &val) == -1) return (errno); if (val < min || val > max) return (EINVAL); *valp = val; return (0); } static int pwr_of_two(u_int nr) { return (((nr & (nr - 1)) == 0) ? 1 : 0); } /* * A partition specification has the following format: * ':' * where: * type the partition type alias * kind the interpretation of the contents specification * ':' contents holds the size of an empty partition * '=' contents holds the name of a file to read * '-' contents holds a command to run; the output of * which is the contents of the partition. * contents the specification of a partition's contents * * A specification that is a single dash indicates an unused partition * entry. */ static int parse_part(const char *spec) { struct part *part; char *sep; size_t len; int error; if (strcmp(spec, "-") == 0) { nparts++; return (0); } part = calloc(1, sizeof(struct part)); if (part == NULL) return (ENOMEM); sep = strchr(spec, ':'); if (sep == NULL) { error = EINVAL; goto errout; } len = sep - spec + 1; if (len < 2) { error = EINVAL; goto errout; } part->alias = malloc(len); if (part->alias == NULL) { error = ENOMEM; goto errout; } strlcpy(part->alias, spec, len); spec = sep + 1; switch (*spec) { case ':': part->kind = PART_KIND_SIZE; break; case '=': part->kind = PART_KIND_FILE; break; case '-': part->kind = PART_KIND_PIPE; break; default: error = EINVAL; goto errout; } spec++; part->contents = strdup(spec); if (part->contents == NULL) { error = ENOMEM; goto errout; } spec = part->alias; sep = strchr(spec, '/'); if (sep != NULL) { *sep++ = '\0'; if (strlen(part->alias) == 0 || strlen(sep) == 0) { error = EINVAL; goto errout; } part->label = strdup(sep); if (part->label == NULL) { error = ENOMEM; goto errout; } } part->index = nparts; STAILQ_INSERT_TAIL(&partlist, part, link); nparts++; return (0); errout: if (part->alias != NULL) free(part->alias); free(part); return (error); } #if defined(SPARSE_WRITE) ssize_t sparse_write(int fd, const void *ptr, size_t sz) { const char *buf, *p; off_t ofs; size_t len; ssize_t wr, wrsz; buf = ptr; wrsz = 0; p = memchr(buf, 0, sz); while (sz > 0) { len = (p != NULL) ? (size_t)(p - buf) : sz; if (len > 0) { len = (len + secsz - 1) & ~(secsz - 1); if (len > sz) len = sz; wr = write(fd, buf, len); if (wr < 0) return (-1); } else { while (len < sz && *p++ == '\0') len++; if (len < sz) len &= ~(secsz - 1); if (len == 0) continue; ofs = lseek(fd, len, SEEK_CUR); if (ofs < 0) return (-1); wr = len; } buf += wr; sz -= wr; wrsz += wr; p = memchr(buf, 0, sz); } return (wrsz); } #endif /* SPARSE_WRITE */ void mkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp) { u_int hd, sec; *cylp = *hdp = *secp = ~0U; if (nsecs == 1 || nheads == 1) return; sec = lba % nsecs + 1; lba /= nsecs; hd = lba % nheads; lba /= nheads; if (lba > maxcyl) return; *cylp = lba; *hdp = hd; *secp = sec; } void mkimg_uuid(struct uuid *uuid) { static uint8_t gen[sizeof(struct uuid)]; u_int i; if (!unit_testing) { uuidgen(uuid, 1); return; } for (i = 0; i < sizeof(gen); i++) gen[i]++; memcpy(uuid, gen, sizeof(uuid_t)); } static int capacity_resize(lba_t end) { lba_t capsz; capsz = (capacity + secsz - 1) / secsz; if (end >= capsz) return (0); return (image_set_size(capsz)); } static void mkimg(void) { FILE *fp; struct part *part; lba_t block; off_t bytesize; int error, fd; /* First check partition information */ STAILQ_FOREACH(part, &partlist, link) { error = scheme_check_part(part); if (error) errc(EX_DATAERR, error, "partition %d", part->index+1); } block = scheme_metadata(SCHEME_META_IMG_START, 0); STAILQ_FOREACH(part, &partlist, link) { block = scheme_metadata(SCHEME_META_PART_BEFORE, block); if (verbose) fprintf(stderr, "partition %d: starting block %llu " "... ", part->index + 1, (long long)block); part->block = block; switch (part->kind) { case PART_KIND_SIZE: if (expand_number(part->contents, &bytesize) == -1) error = errno; break; case PART_KIND_FILE: fd = open(part->contents, O_RDONLY, 0); if (fd != -1) { error = image_copyin(block, fd, &bytesize); close(fd); } else error = errno; break; case PART_KIND_PIPE: fp = popen(part->contents, "r"); if (fp != NULL) { fd = fileno(fp); error = image_copyin(block, fd, &bytesize); pclose(fp); } else error = errno; break; } if (error) errc(EX_IOERR, error, "partition %d", part->index + 1); part->size = (bytesize + secsz - 1) / secsz; if (verbose) { bytesize = part->size * secsz; fprintf(stderr, "size %llu bytes (%llu blocks)\n", (long long)bytesize, (long long)part->size); } block = scheme_metadata(SCHEME_META_PART_AFTER, part->block + part->size); } block = scheme_metadata(SCHEME_META_IMG_END, block); error = image_set_size(block); if (!error) { error = capacity_resize(block); block = image_get_size(); } if (!error) { error = format_resize(block); block = image_get_size(); } if (error) errc(EX_IOERR, error, "image sizing"); ncyls = block / (nsecs * nheads); error = scheme_write(block); if (error) errc(EX_IOERR, error, "writing metadata"); } int main(int argc, char *argv[]) { int bcfd, outfd; int c, error; bcfd = -1; outfd = 1; /* Write to stdout by default */ while ((c = getopt_long(argc, argv, "b:c:f:o:p:s:vyH:P:S:T:", longopts, NULL)) != -1) { switch (c) { case 'b': /* BOOT CODE */ if (bcfd != -1) usage("multiple bootcode given"); bcfd = open(optarg, O_RDONLY, 0); if (bcfd == -1) err(EX_UNAVAILABLE, "%s", optarg); break; case 'c': /* CAPACITY */ error = parse_uint64(&capacity, 1, OFF_MAX, optarg); if (error) errc(EX_DATAERR, error, "capacity in bytes"); break; case 'f': /* OUTPUT FORMAT */ if (format_selected() != NULL) usage("multiple formats given"); error = format_select(optarg); if (error) errc(EX_DATAERR, error, "format"); break; case 'o': /* OUTPUT FILE */ if (outfd != 1) usage("multiple output files given"); outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); if (outfd == -1) err(EX_CANTCREAT, "%s", optarg); break; case 'p': /* PARTITION */ error = parse_part(optarg); if (error) errc(EX_DATAERR, error, "partition"); break; case 's': /* SCHEME */ if (scheme_selected() != NULL) usage("multiple schemes given"); error = scheme_select(optarg); if (error) errc(EX_DATAERR, error, "scheme"); break; case 'y': unit_testing++; break; case 'v': verbose++; break; case 'H': /* GEOMETRY: HEADS */ error = parse_uint32(&nheads, 1, 255, optarg); if (error) errc(EX_DATAERR, error, "number of heads"); break; case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */ error = parse_uint32(&blksz, 512, INT_MAX+1U, optarg); if (error == 0 && !pwr_of_two(blksz)) error = EINVAL; if (error) errc(EX_DATAERR, error, "physical sector size"); break; case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */ error = parse_uint32(&secsz, 512, INT_MAX+1U, optarg); if (error == 0 && !pwr_of_two(secsz)) error = EINVAL; if (error) errc(EX_DATAERR, error, "logical sector size"); break; case 'T': /* GEOMETRY: TRACK SIZE */ error = parse_uint32(&nsecs, 1, 63, optarg); if (error) errc(EX_DATAERR, error, "track size"); break; case LONGOPT_FORMATS: print_formats(0); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_SCHEMES: print_schemes(0); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_VERSION: print_version(); exit(EX_OK); /*NOTREACHED*/ default: usage("unknown option"); } } if (argc > optind) usage("trailing arguments"); if (scheme_selected() == NULL && nparts > 0) usage("no scheme"); if (nparts == 0 && capacity == 0) usage("no partitions"); if (secsz > blksz) { if (blksz != 0) errx(EX_DATAERR, "the physical block size cannot " "be smaller than the sector size"); blksz = secsz; } if (secsz > scheme_max_secsz()) errx(EX_DATAERR, "maximum sector size supported is %u; " "size specified is %u", scheme_max_secsz(), secsz); if (nparts > scheme_max_parts()) errx(EX_DATAERR, "%d partitions supported; %d given", scheme_max_parts(), nparts); if (format_selected() == NULL) format_select("raw"); if (bcfd != -1) { error = scheme_bootcode(bcfd); close(bcfd); if (error) errc(EX_DATAERR, error, "boot code"); } if (verbose) { fprintf(stderr, "Logical sector size: %u\n", secsz); fprintf(stderr, "Physical block size: %u\n", blksz); fprintf(stderr, "Sectors per track: %u\n", nsecs); fprintf(stderr, "Number of heads: %u\n", nheads); fputc('\n', stderr); if (scheme_selected()) fprintf(stderr, "Partitioning scheme: %s\n", scheme_selected()->name); fprintf(stderr, "Output file format: %s\n", format_selected()->name); fputc('\n', stderr); } error = image_init(); if (error) errc(EX_OSERR, error, "cannot initialize"); mkimg(); if (verbose) { fputc('\n', stderr); fprintf(stderr, "Number of cylinders: %u\n", ncyls); } error = format_write(outfd); if (error) errc(EX_IOERR, error, "writing image"); return (0); } Index: head/usr.bin/mkimg/scheme.c =================================================================== --- head/usr.bin/mkimg/scheme.c (revision 306324) +++ head/usr.bin/mkimg/scheme.c (revision 306325) @@ -1,190 +1,203 @@ /*- * Copyright (c) 2013,2014 Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include -#include -#include #include #include #include #include #include #include #include #include #include #include "image.h" #include "mkimg.h" #include "scheme.h" static struct { const char *name; enum alias alias; } scheme_alias[] = { { "ebr", ALIAS_EBR }, { "efi", ALIAS_EFI }, { "fat16b", ALIAS_FAT16B }, { "fat32", ALIAS_FAT32 }, { "freebsd", ALIAS_FREEBSD }, { "freebsd-boot", ALIAS_FREEBSD_BOOT }, { "freebsd-nandfs", ALIAS_FREEBSD_NANDFS }, { "freebsd-swap", ALIAS_FREEBSD_SWAP }, { "freebsd-ufs", ALIAS_FREEBSD_UFS }, { "freebsd-vinum", ALIAS_FREEBSD_VINUM }, { "freebsd-zfs", ALIAS_FREEBSD_ZFS }, { "mbr", ALIAS_MBR }, { "ntfs", ALIAS_NTFS }, { "prepboot", ALIAS_PPCBOOT }, { NULL, ALIAS_NONE } /* Keep last! */ }; +static struct mkimg_scheme *first; static struct mkimg_scheme *scheme; static void *bootcode; static enum alias scheme_parse_alias(const char *name) { u_int idx; idx = 0; while (scheme_alias[idx].name != NULL) { if (strcasecmp(scheme_alias[idx].name, name) == 0) return (scheme_alias[idx].alias); idx++; } return (ALIAS_NONE); } +struct mkimg_scheme * +scheme_iterate(struct mkimg_scheme *s) +{ + + return ((s == NULL) ? first : s->next); +} + +void +scheme_register(struct mkimg_scheme *s) +{ + s->next = first; + first = s; +} + int scheme_select(const char *spec) { - struct mkimg_scheme *s, **iter; + struct mkimg_scheme *s; - SET_FOREACH(iter, schemes) { - s = *iter; + s = NULL; + while ((s = scheme_iterate(s)) != NULL) { if (strcasecmp(spec, s->name) == 0) { scheme = s; return (0); } } return (EINVAL); } struct mkimg_scheme * scheme_selected(void) { return (scheme); } int scheme_bootcode(int fd) { struct stat sb; if (scheme == NULL || scheme->bootcode == 0) return (ENXIO); if (fstat(fd, &sb) == -1) return (errno); if (sb.st_size > scheme->bootcode) return (EFBIG); bootcode = malloc(scheme->bootcode); if (bootcode == NULL) return (ENOMEM); memset(bootcode, 0, scheme->bootcode); if (read(fd, bootcode, sb.st_size) != sb.st_size) { free(bootcode); bootcode = NULL; return (errno); } return (0); } int scheme_check_part(struct part *p) { struct mkimg_alias *iter; enum alias alias; assert(scheme != NULL); /* Check the partition type alias */ alias = scheme_parse_alias(p->alias); if (alias == ALIAS_NONE) return (EINVAL); iter = scheme->aliases; while (iter->alias != ALIAS_NONE) { if (alias == iter->alias) break; iter++; } if (iter->alias == ALIAS_NONE) return (EINVAL); p->type = iter->type; /* Validate the optional label. */ if (p->label != NULL) { if (strlen(p->label) > scheme->labellen) return (EINVAL); } return (0); } u_int scheme_max_parts(void) { return ((scheme == NULL) ? 0 : scheme->nparts); } u_int scheme_max_secsz(void) { return ((scheme == NULL) ? INT_MAX+1U : scheme->maxsecsz); } lba_t scheme_metadata(u_int where, lba_t start) { return ((scheme == NULL) ? start : scheme->metadata(where, start)); } int scheme_write(lba_t end) { return ((scheme == NULL) ? 0 : scheme->write(end, bootcode)); } Index: head/usr.bin/mkimg/scheme.h =================================================================== --- head/usr.bin/mkimg/scheme.h (revision 306324) +++ head/usr.bin/mkimg/scheme.h (revision 306325) @@ -1,93 +1,95 @@ /*- * Copyright (c) 2013,2014 Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MKIMG_SCHEME_H_ #define _MKIMG_SCHEME_H_ -#include - enum alias { ALIAS_NONE, /* Keep first! */ /* start */ ALIAS_EBR, ALIAS_EFI, ALIAS_FAT16B, ALIAS_FAT32, ALIAS_FREEBSD, ALIAS_FREEBSD_BOOT, ALIAS_FREEBSD_NANDFS, ALIAS_FREEBSD_SWAP, ALIAS_FREEBSD_UFS, ALIAS_FREEBSD_VINUM, ALIAS_FREEBSD_ZFS, ALIAS_MBR, ALIAS_NTFS, ALIAS_PPCBOOT, /* end */ ALIAS_COUNT /* Keep last! */ }; struct mkimg_alias { u_int alias; uintptr_t type; #define ALIAS_PTR2TYPE(p) (uintptr_t)(p) #define ALIAS_INT2TYPE(i) (i) #define ALIAS_TYPE2PTR(p) (void *)(p) #define ALIAS_TYPE2INT(i) (i) }; struct mkimg_scheme { + struct mkimg_scheme *next; const char *name; const char *description; struct mkimg_alias *aliases; lba_t (*metadata)(u_int, lba_t); #define SCHEME_META_IMG_START 1 #define SCHEME_META_IMG_END 2 #define SCHEME_META_PART_BEFORE 3 #define SCHEME_META_PART_AFTER 4 int (*write)(lba_t, void *); u_int nparts; u_int labellen; u_int bootcode; u_int maxsecsz; }; -SET_DECLARE(schemes, struct mkimg_scheme); -#define SCHEME_DEFINE(nm) DATA_SET(schemes, nm) +#define SCHEME_DEFINE(nm) \ +static void scheme_register_##nm(void) __attribute__((constructor)); \ +static void scheme_register_##nm(void) { scheme_register(&nm); } +struct mkimg_scheme *scheme_iterate(struct mkimg_scheme *); +void scheme_register(struct mkimg_scheme *); int scheme_select(const char *); struct mkimg_scheme *scheme_selected(void); int scheme_bootcode(int fd); int scheme_check_part(struct part *); u_int scheme_max_parts(void); u_int scheme_max_secsz(void); lba_t scheme_metadata(u_int, lba_t); int scheme_write(lba_t); #endif /* _MKIMG_SCHEME_H_ */