Index: user/marcel/mkimg/mkimg.c =================================================================== --- user/marcel/mkimg/mkimg.c (revision 263413) +++ user/marcel/mkimg/mkimg.c (revision 263414) @@ -1,328 +1,330 @@ /*- * 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 "mkimg.h" #include "scheme.h" #define BUFFER_SIZE (1024*1024) struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist); u_int nparts = 0; static int bcfd = 0; static int outfd = 0; static int tmpfd = -1; static char tmpfname[] = "/tmp/mkimg-XXXXXX"; static void cleanup(void) { if (tmpfd != -1) close(tmpfd); unlink(tmpfname); } static void usage(const char *why) { struct mkimg_scheme *s, **iter; warnx("error: %s", why); fprintf(stderr, "\nusage: %s \n", getprogname()); fprintf(stderr, " options:\n"); fprintf(stderr, "\t-b \t- file containing boot code\n"); fprintf(stderr, "\t-h \t- number of heads to simulate\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-t \t- number of tracks to simulate\n"); fprintf(stderr, "\t-z\t\t- write a sparse file\n"); fprintf(stderr, " schemes:\n"); SET_FOREACH(iter, schemes) { s = *iter; fprintf(stderr, "\t%s\t- %s\n", s->name, s->description); } fprintf(stderr, " partition specification:\n"); fprintf(stderr, "\t::\t- empty partition of given size\n"); fprintf(stderr, "\t:=\t- partition content and size\n" "\t\t\t determined by the named file\n"); fprintf(stderr, "\t:!\t- partition content and size\n" "\t\t\t taken from the output of the command to run\n"); fprintf(stderr, "\t where:\n"); fprintf(stderr, "\t\ttype\t- scheme neutral partition type\n"); exit(EX_USAGE); } /* * 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 */ static int parse_part(const char *spec) { struct part *part; char *sep; size_t len; int error; 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->type = malloc(len); - if (part->type == NULL) { + part->alias = malloc(len); + if (part->alias == NULL) { error = ENOMEM; goto errout; } - strlcpy(part->type, spec, len); + 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; } part->index = nparts; STAILQ_INSERT_TAIL(&partlist, part, link); nparts++; return (0); errout: - if (part->type != NULL) - free(part->type); + if (part->alias != NULL) + free(part->alias); free(part); return (error); } static int fdcopy(int src, int dst, uint64_t *count) { void *buffer; ssize_t rdsz, wrsz; if (count != 0) *count = 0; buffer = malloc(BUFFER_SIZE); if (buffer == NULL) return (errno); while (1) { rdsz = read(src, buffer, BUFFER_SIZE); if (rdsz <= 0) { free(buffer); return ((rdsz < 0) ? errno : 0); } if (count != NULL) *count += rdsz; wrsz = write(dst, buffer, rdsz); if (wrsz < 0) break; } free(buffer); return (errno); } static void mkimg(void) { FILE *fp; struct part *part; off_t offset; uint64_t size; int error, fd; if (nparts > scheme_max_parts()) errc(EX_DATAERR, ENOSPC, "only %d partitions are supported", scheme_max_parts()); offset = scheme_first_offset(nparts); STAILQ_FOREACH(part, &partlist, link) { part->offset = offset; lseek(tmpfd, offset, SEEK_SET); /* XXX check error */ error = 0; switch (part->kind) { case PART_KIND_SIZE: if (expand_number(part->contents, &size) == -1) error = errno; break; case PART_KIND_FILE: fd = open(part->contents, O_RDONLY, 0); if (fd != -1) { error = fdcopy(fd, tmpfd, &size); close(fd); } else error = errno; break; case PART_KIND_PIPE: fp = popen(part->contents, "r"); if (fp != NULL) { error = fdcopy(fileno(fp), tmpfd, &size); pclose(fp); } else error = errno; break; } part->size = size; - scheme_check_part(part); + error = scheme_check_part(part); + if (error) + errc(EX_DATAERR, error, "partition %d", part->index+1); offset = scheme_next_offset(offset, size); } scheme_write(tmpfd, offset); } int main(int argc, char *argv[]) { int c, error; while ((c = getopt(argc, argv, "b:h:o:p:s:t:z")) != -1) { switch (c) { case 'b': /* BOOT CODE */ if (bcfd != 0) usage("multiple bootcode given"); bcfd = open(optarg, O_RDONLY, 0); if (bcfd == -1) err(EX_UNAVAILABLE, "%s", optarg); break; case 'h': /* GEOMETRY: HEADS */ break; case 'o': /* OUTPUT FILE */ if (outfd != 0) 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 't': /* GEOMETRY: TRACK SIZE */ break; case 'z': /* SPARSE OUTPUT */ break; default: usage("unknown option"); } } if (argc > optind) usage("trailing arguments"); if (scheme_selected() == NULL) usage("no scheme"); if (nparts == 0) usage("no partitions"); if (outfd == 0) { if (atexit(cleanup) == -1) err(EX_OSERR, "cannot register cleanup function"); outfd = 1; tmpfd = mkstemp(tmpfname); if (tmpfd == -1) err(EX_OSERR, "cannot create temporary file"); } else tmpfd = outfd; mkimg(); if (tmpfd != outfd) { if (lseek(tmpfd, 0, SEEK_SET) == 0) error = fdcopy(tmpfd, outfd, NULL); else error = errno; /* XXX check error */ } return (0); } Index: user/marcel/mkimg/mkimg.h =================================================================== --- user/marcel/mkimg/mkimg.h (revision 263413) +++ user/marcel/mkimg/mkimg.h (revision 263414) @@ -1,49 +1,49 @@ /*- * 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_MKIMG_H_ #define _MKIMG_MKIMG_H_ struct part { STAILQ_ENTRY(part) link; - char *type; /* Partition type. */ + char *alias; /* Partition type alias. */ char *contents; /* Contents/size specification. */ u_int kind; /* Content kind. */ #define PART_UNDEF 0 #define PART_KIND_FILE 1 #define PART_KIND_PIPE 2 #define PART_KIND_SIZE 3 u_int index; /* Partition index (0-based). */ off_t offset; /* Byte-offset of partition in image. */ off_t size; /* Size in bytes of partition. */ }; extern STAILQ_HEAD(partlisthead, part) partlist; extern u_int nparts; #endif /* _MKIMG_MKIMG_H_ */ Index: user/marcel/mkimg/scheme.c =================================================================== --- user/marcel/mkimg/scheme.c (revision 263413) +++ user/marcel/mkimg/scheme.c (revision 263414) @@ -1,111 +1,125 @@ /*- * 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 "mkimg.h" #include "scheme.h" static struct mkimg_scheme *scheme; static u_int secsz = 512; int scheme_select(const char *spec) { struct mkimg_scheme *s, **iter; SET_FOREACH(iter, schemes) { s = *iter; if (strcasecmp(spec, s->name) == 0) { scheme = s; return (0); } } return (EINVAL); } struct mkimg_scheme * scheme_selected(void) { return (scheme); } int scheme_check_part(struct part *p) { + struct mkimg_alias *alias, *iter; warnx("part(%s): index=%u, type=`%s', offset=%ju, size=%ju", - scheme->name, p->index, p->type, (uintmax_t)p->offset, + scheme->name, p->index, p->alias, (uintmax_t)p->offset, (uintmax_t)p->size); + + /* Check the partition type alias */ + alias = NULL; + iter = scheme->aliases; + while (iter->name != NULL) { + if (strcasecmp(p->alias, iter->name) == 0) { + alias = iter; + break; + } + iter++; + } + if (alias == NULL) + return (EINVAL); return (0); } u_int scheme_max_parts(void) { return (scheme->nparts); } off_t scheme_first_offset(u_int parts) { off_t off; off = scheme->get_leader(parts); off *= secsz; return (off); } off_t scheme_next_offset(off_t off, uint64_t sz) { sz = (sz + secsz - 1) & ~(secsz - 1); sz += scheme->padding * secsz; return (off + sz); } void scheme_write(int fd, off_t off) { off_t trailer; trailer = scheme->get_trailer(nparts) * secsz; ftruncate(fd, off + trailer); }