Index: user/marcel/mkimg/mkimg.c =================================================================== --- user/marcel/mkimg/mkimg.c (revision 263381) +++ user/marcel/mkimg/mkimg.c (revision 263382) @@ -1,320 +1,306 @@ /*- * Copyright (c) 2013 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 "mkimg.h" #include "scheme.h" #define BUFFER_SIZE (1024*1024) -struct part { - STAILQ_ENTRY(part) link; - char *type; /* Partition type. */ - 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. */ -}; +struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist); +u_int nparts = 0; -static STAILQ_HEAD(, part) parts = STAILQ_HEAD_INITIALIZER(parts); -static 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) { warnx("error: %s", why); fprintf(stderr, "usage: %s \n", getprogname()); fprintf(stderr, " options:\n"); fprintf(stderr, "\t-b \n"); fprintf(stderr, "\t-o \n"); fprintf(stderr, "\t-p \n"); fprintf(stderr, "\t-s \n"); fprintf(stderr, "\t-z\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) { error = ENOMEM; goto errout; } strlcpy(part->type, 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(&parts, part, link); + STAILQ_INSERT_TAIL(&partlist, part, link); nparts++; return (0); errout: if (part->type != NULL) free(part->type); 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, &parts, link) { + 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_add_part(part->index, part->type, part->offset, - part->size); + scheme_check_part(part); 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() != SCHEME_UNDEF) 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() == SCHEME_UNDEF) 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 (nonexistent) +++ user/marcel/mkimg/mkimg.h (revision 263382) @@ -0,0 +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 *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_ */ Property changes on: user/marcel/mkimg/mkimg.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/marcel/mkimg/scheme.c =================================================================== --- user/marcel/mkimg/scheme.c (revision 263381) +++ user/marcel/mkimg/scheme.c (revision 263382) @@ -1,207 +1,190 @@ /*- * Copyright (c) 2013 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 "mkimg.h" #include "scheme.h" -#define MAX(a, b) ((a < b) ? b : a) - static struct scheme { const char *lexeme; u_int token; } schemes[] = { { .lexeme = "apm", .token = SCHEME_APM }, { .lexeme = "bsd", .token = SCHEME_BSD }, { .lexeme = "ebr", .token = SCHEME_EBR }, { .lexeme = "gpt", .token = SCHEME_GPT }, { .lexeme = "mbr", .token = SCHEME_MBR }, { .lexeme = "pc98", .token = SCHEME_PC98 }, { .lexeme = "vtoc8", .token = SCHEME_VTOC8 }, { .lexeme = NULL, .token = SCHEME_UNDEF } }; static u_int scheme = SCHEME_UNDEF; static u_int secsz = 512; -static u_int nparts = 0; int scheme_select(const char *spec) { struct scheme *s; s = schemes; while (s->lexeme != NULL) { if (strcasecmp(spec, s->lexeme) == 0) { scheme = s->token; return (0); } s++; } return (EINVAL); } u_int scheme_selected(void) { return (scheme); } int -scheme_add_part(u_int idx, const char *type, off_t offset, off_t size) +scheme_check_part(struct part *p __unused) { - warnx("part: index=%u, type=`%s', offset=%ju, size=%ju", idx, - type, (uintmax_t)offset, (uintmax_t)size); - switch (scheme) { - case SCHEME_APM: - break; - case SCHEME_BSD: - break; - case SCHEME_EBR: - break; - case SCHEME_GPT: - break; - case SCHEME_MBR: - break; - case SCHEME_PC98: - break; - case SCHEME_VTOC8: - break; - } + warnx("part: index=%u, type=`%s', offset=%ju, size=%ju", p->index, + p->type, (uintmax_t)p->offset, (uintmax_t)p->size); + return (0); } u_int scheme_max_parts(void) { u_int parts; switch (scheme) { case SCHEME_APM: parts = 4096; break; case SCHEME_BSD: parts = 20; break; case SCHEME_EBR: parts = 4096; break; case SCHEME_GPT: parts = 4096; break; case SCHEME_MBR: parts = NDOSPART; break; case SCHEME_PC98: parts = PC98_NPARTS; break; case SCHEME_VTOC8: parts = VTOC8_NPARTS; break; default: parts = 0; break; } return (parts); } off_t scheme_first_offset(u_int parts) { off_t off; - nparts = parts; /* Save nparts for later. */ switch (scheme) { case SCHEME_APM: off = parts + 1; break; case SCHEME_BSD: off = 16; break; case SCHEME_EBR: off = 1; break; case SCHEME_GPT: - off = 2 + (MAX(128, parts) + 3) / 4; + off = 2 + (parts + 3) / 4; break; case SCHEME_MBR: off = 1; break; case SCHEME_PC98: - off = 16; + off = 2; break; case SCHEME_VTOC8: off = 1; break; default: off = 0; break; } off *= secsz; return (off); } off_t scheme_next_offset(off_t off, uint64_t sz) { sz = (sz + secsz - 1) & ~(secsz - 1); if (scheme == SCHEME_EBR) sz += secsz; return (off + sz); } void scheme_write(int fd, off_t off) { off_t lim; switch (scheme) { case SCHEME_GPT: - lim = off + secsz * (1 + (MAX(128, nparts) + 3) / 4); + lim = off + secsz * (1 + (nparts + 3) / 4); break; case SCHEME_EBR: off -= secsz; /* FALLTHROUGH */ default: lim = off; break; } ftruncate(fd, lim); } Index: user/marcel/mkimg/scheme.h =================================================================== --- user/marcel/mkimg/scheme.h (revision 263381) +++ user/marcel/mkimg/scheme.h (revision 263382) @@ -1,50 +1,50 @@ /*- * Copyright (c) 2013 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_ #define SCHEME_UNDEF 0 #define SCHEME_APM 1 #define SCHEME_BSD 2 #define SCHEME_EBR 3 #define SCHEME_GPT 4 #define SCHEME_MBR 5 #define SCHEME_PC98 6 #define SCHEME_VTOC8 7 int scheme_select(const char *); u_int scheme_selected(void); -int scheme_add_part(u_int, const char *, off_t, off_t); +int scheme_check_part(struct part *); u_int scheme_max_parts(void); off_t scheme_first_offset(u_int); off_t scheme_next_offset(off_t, uint64_t); void scheme_write(int, off_t); #endif /* _MKIMG_SCHEME_H_ */