1*a5eb4ea3SMarcel Moolenaar /*- 2*a5eb4ea3SMarcel Moolenaar * Copyright (c) 2013,2014 Juniper Networks, Inc. 3*a5eb4ea3SMarcel Moolenaar * All rights reserved. 4*a5eb4ea3SMarcel Moolenaar * 5*a5eb4ea3SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 6*a5eb4ea3SMarcel Moolenaar * modification, are permitted provided that the following conditions 7*a5eb4ea3SMarcel Moolenaar * are met: 8*a5eb4ea3SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 9*a5eb4ea3SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 10*a5eb4ea3SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 11*a5eb4ea3SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 12*a5eb4ea3SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 13*a5eb4ea3SMarcel Moolenaar * 14*a5eb4ea3SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*a5eb4ea3SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*a5eb4ea3SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*a5eb4ea3SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*a5eb4ea3SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*a5eb4ea3SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*a5eb4ea3SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*a5eb4ea3SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*a5eb4ea3SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*a5eb4ea3SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*a5eb4ea3SMarcel Moolenaar * SUCH DAMAGE. 25*a5eb4ea3SMarcel Moolenaar */ 26*a5eb4ea3SMarcel Moolenaar 27*a5eb4ea3SMarcel Moolenaar #include <sys/cdefs.h> 28*a5eb4ea3SMarcel Moolenaar __FBSDID("$FreeBSD$"); 29*a5eb4ea3SMarcel Moolenaar 30*a5eb4ea3SMarcel Moolenaar #include <sys/linker_set.h> 31*a5eb4ea3SMarcel Moolenaar #include <sys/queue.h> 32*a5eb4ea3SMarcel Moolenaar #include <sys/stat.h> 33*a5eb4ea3SMarcel Moolenaar #include <sys/types.h> 34*a5eb4ea3SMarcel Moolenaar #include <errno.h> 35*a5eb4ea3SMarcel Moolenaar #include <err.h> 36*a5eb4ea3SMarcel Moolenaar #include <fcntl.h> 37*a5eb4ea3SMarcel Moolenaar #include <libutil.h> 38*a5eb4ea3SMarcel Moolenaar #include <limits.h> 39*a5eb4ea3SMarcel Moolenaar #include <stdio.h> 40*a5eb4ea3SMarcel Moolenaar #include <stdlib.h> 41*a5eb4ea3SMarcel Moolenaar #include <string.h> 42*a5eb4ea3SMarcel Moolenaar #include <sysexits.h> 43*a5eb4ea3SMarcel Moolenaar #include <unistd.h> 44*a5eb4ea3SMarcel Moolenaar 45*a5eb4ea3SMarcel Moolenaar #include "mkimg.h" 46*a5eb4ea3SMarcel Moolenaar #include "scheme.h" 47*a5eb4ea3SMarcel Moolenaar 48*a5eb4ea3SMarcel Moolenaar #if !defined(SPARSE_WRITE) 49*a5eb4ea3SMarcel Moolenaar #define sparse_write write 50*a5eb4ea3SMarcel Moolenaar #endif 51*a5eb4ea3SMarcel Moolenaar 52*a5eb4ea3SMarcel Moolenaar #define BUFFER_SIZE (1024*1024) 53*a5eb4ea3SMarcel Moolenaar 54*a5eb4ea3SMarcel Moolenaar struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist); 55*a5eb4ea3SMarcel Moolenaar u_int nparts = 0; 56*a5eb4ea3SMarcel Moolenaar 57*a5eb4ea3SMarcel Moolenaar u_int verbose; 58*a5eb4ea3SMarcel Moolenaar 59*a5eb4ea3SMarcel Moolenaar u_int ncyls = 0; 60*a5eb4ea3SMarcel Moolenaar u_int nheads = 1; 61*a5eb4ea3SMarcel Moolenaar u_int nsecs = 1; 62*a5eb4ea3SMarcel Moolenaar u_int secsz = 512; 63*a5eb4ea3SMarcel Moolenaar u_int blksz = 0; 64*a5eb4ea3SMarcel Moolenaar 65*a5eb4ea3SMarcel Moolenaar static int bcfd = -1; 66*a5eb4ea3SMarcel Moolenaar static int outfd = 0; 67*a5eb4ea3SMarcel Moolenaar static int tmpfd = -1; 68*a5eb4ea3SMarcel Moolenaar 69*a5eb4ea3SMarcel Moolenaar static char tmpfname[] = "/tmp/mkimg-XXXXXX"; 70*a5eb4ea3SMarcel Moolenaar 71*a5eb4ea3SMarcel Moolenaar static void 72*a5eb4ea3SMarcel Moolenaar cleanup(void) 73*a5eb4ea3SMarcel Moolenaar { 74*a5eb4ea3SMarcel Moolenaar 75*a5eb4ea3SMarcel Moolenaar if (tmpfd != -1) 76*a5eb4ea3SMarcel Moolenaar close(tmpfd); 77*a5eb4ea3SMarcel Moolenaar unlink(tmpfname); 78*a5eb4ea3SMarcel Moolenaar } 79*a5eb4ea3SMarcel Moolenaar 80*a5eb4ea3SMarcel Moolenaar static void 81*a5eb4ea3SMarcel Moolenaar usage(const char *why) 82*a5eb4ea3SMarcel Moolenaar { 83*a5eb4ea3SMarcel Moolenaar struct mkimg_scheme *s, **iter; 84*a5eb4ea3SMarcel Moolenaar 85*a5eb4ea3SMarcel Moolenaar warnx("error: %s", why); 86*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\nusage: %s <options>\n", getprogname()); 87*a5eb4ea3SMarcel Moolenaar 88*a5eb4ea3SMarcel Moolenaar fprintf(stderr, " options:\n"); 89*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-b <file>\t- file containing boot code\n"); 90*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-o <file>\t- file to write image into\n"); 91*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-p <partition>\n"); 92*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-s <scheme>\n"); 93*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-H <num>\t- number of heads to simulate\n"); 94*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-P <num>\t- physical sector size\n"); 95*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-S <num>\t- logical sector size\n"); 96*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n"); 97*a5eb4ea3SMarcel Moolenaar 98*a5eb4ea3SMarcel Moolenaar fprintf(stderr, " schemes:\n"); 99*a5eb4ea3SMarcel Moolenaar SET_FOREACH(iter, schemes) { 100*a5eb4ea3SMarcel Moolenaar s = *iter; 101*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t%s\t- %s\n", s->name, s->description); 102*a5eb4ea3SMarcel Moolenaar } 103*a5eb4ea3SMarcel Moolenaar 104*a5eb4ea3SMarcel Moolenaar fprintf(stderr, " partition specification:\n"); 105*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t<t>[/<l>]::<size>\t- empty partition of given " 106*a5eb4ea3SMarcel Moolenaar "size\n"); 107*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t<t>[/<l>]:=<file>\t- partition content and size " 108*a5eb4ea3SMarcel Moolenaar "are determined\n\t\t\t\t by the named file\n"); 109*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t- partition content and size " 110*a5eb4ea3SMarcel Moolenaar "are taken from\n\t\t\t\t the output of the command to run\n"); 111*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t where:\n"); 112*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t\t<t>\t- scheme neutral partition type\n"); 113*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "\t\t<l>\t- optional scheme-dependent partition " 114*a5eb4ea3SMarcel Moolenaar "label\n"); 115*a5eb4ea3SMarcel Moolenaar 116*a5eb4ea3SMarcel Moolenaar exit(EX_USAGE); 117*a5eb4ea3SMarcel Moolenaar } 118*a5eb4ea3SMarcel Moolenaar 119*a5eb4ea3SMarcel Moolenaar static int 120*a5eb4ea3SMarcel Moolenaar parse_number(u_int *valp, u_int min, u_int max, const char *arg) 121*a5eb4ea3SMarcel Moolenaar { 122*a5eb4ea3SMarcel Moolenaar uint64_t val; 123*a5eb4ea3SMarcel Moolenaar 124*a5eb4ea3SMarcel Moolenaar if (expand_number(arg, &val) == -1) 125*a5eb4ea3SMarcel Moolenaar return (errno); 126*a5eb4ea3SMarcel Moolenaar if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max) 127*a5eb4ea3SMarcel Moolenaar return (EINVAL); 128*a5eb4ea3SMarcel Moolenaar *valp = (u_int)val; 129*a5eb4ea3SMarcel Moolenaar return (0); 130*a5eb4ea3SMarcel Moolenaar } 131*a5eb4ea3SMarcel Moolenaar 132*a5eb4ea3SMarcel Moolenaar static int 133*a5eb4ea3SMarcel Moolenaar pwr_of_two(u_int nr) 134*a5eb4ea3SMarcel Moolenaar { 135*a5eb4ea3SMarcel Moolenaar 136*a5eb4ea3SMarcel Moolenaar return (((nr & (nr - 1)) == 0) ? 1 : 0); 137*a5eb4ea3SMarcel Moolenaar } 138*a5eb4ea3SMarcel Moolenaar 139*a5eb4ea3SMarcel Moolenaar /* 140*a5eb4ea3SMarcel Moolenaar * A partition specification has the following format: 141*a5eb4ea3SMarcel Moolenaar * <type> ':' <kind> <contents> 142*a5eb4ea3SMarcel Moolenaar * where: 143*a5eb4ea3SMarcel Moolenaar * type the partition type alias 144*a5eb4ea3SMarcel Moolenaar * kind the interpretation of the contents specification 145*a5eb4ea3SMarcel Moolenaar * ':' contents holds the size of an empty partition 146*a5eb4ea3SMarcel Moolenaar * '=' contents holds the name of a file to read 147*a5eb4ea3SMarcel Moolenaar * '-' contents holds a command to run; the output of 148*a5eb4ea3SMarcel Moolenaar * which is the contents of the partition. 149*a5eb4ea3SMarcel Moolenaar * contents the specification of a partition's contents 150*a5eb4ea3SMarcel Moolenaar */ 151*a5eb4ea3SMarcel Moolenaar static int 152*a5eb4ea3SMarcel Moolenaar parse_part(const char *spec) 153*a5eb4ea3SMarcel Moolenaar { 154*a5eb4ea3SMarcel Moolenaar struct part *part; 155*a5eb4ea3SMarcel Moolenaar char *sep; 156*a5eb4ea3SMarcel Moolenaar size_t len; 157*a5eb4ea3SMarcel Moolenaar int error; 158*a5eb4ea3SMarcel Moolenaar 159*a5eb4ea3SMarcel Moolenaar part = calloc(1, sizeof(struct part)); 160*a5eb4ea3SMarcel Moolenaar if (part == NULL) 161*a5eb4ea3SMarcel Moolenaar return (ENOMEM); 162*a5eb4ea3SMarcel Moolenaar 163*a5eb4ea3SMarcel Moolenaar sep = strchr(spec, ':'); 164*a5eb4ea3SMarcel Moolenaar if (sep == NULL) { 165*a5eb4ea3SMarcel Moolenaar error = EINVAL; 166*a5eb4ea3SMarcel Moolenaar goto errout; 167*a5eb4ea3SMarcel Moolenaar } 168*a5eb4ea3SMarcel Moolenaar len = sep - spec + 1; 169*a5eb4ea3SMarcel Moolenaar if (len < 2) { 170*a5eb4ea3SMarcel Moolenaar error = EINVAL; 171*a5eb4ea3SMarcel Moolenaar goto errout; 172*a5eb4ea3SMarcel Moolenaar } 173*a5eb4ea3SMarcel Moolenaar part->alias = malloc(len); 174*a5eb4ea3SMarcel Moolenaar if (part->alias == NULL) { 175*a5eb4ea3SMarcel Moolenaar error = ENOMEM; 176*a5eb4ea3SMarcel Moolenaar goto errout; 177*a5eb4ea3SMarcel Moolenaar } 178*a5eb4ea3SMarcel Moolenaar strlcpy(part->alias, spec, len); 179*a5eb4ea3SMarcel Moolenaar spec = sep + 1; 180*a5eb4ea3SMarcel Moolenaar 181*a5eb4ea3SMarcel Moolenaar switch (*spec) { 182*a5eb4ea3SMarcel Moolenaar case ':': 183*a5eb4ea3SMarcel Moolenaar part->kind = PART_KIND_SIZE; 184*a5eb4ea3SMarcel Moolenaar break; 185*a5eb4ea3SMarcel Moolenaar case '=': 186*a5eb4ea3SMarcel Moolenaar part->kind = PART_KIND_FILE; 187*a5eb4ea3SMarcel Moolenaar break; 188*a5eb4ea3SMarcel Moolenaar case '-': 189*a5eb4ea3SMarcel Moolenaar part->kind = PART_KIND_PIPE; 190*a5eb4ea3SMarcel Moolenaar break; 191*a5eb4ea3SMarcel Moolenaar default: 192*a5eb4ea3SMarcel Moolenaar error = EINVAL; 193*a5eb4ea3SMarcel Moolenaar goto errout; 194*a5eb4ea3SMarcel Moolenaar } 195*a5eb4ea3SMarcel Moolenaar spec++; 196*a5eb4ea3SMarcel Moolenaar 197*a5eb4ea3SMarcel Moolenaar part->contents = strdup(spec); 198*a5eb4ea3SMarcel Moolenaar if (part->contents == NULL) { 199*a5eb4ea3SMarcel Moolenaar error = ENOMEM; 200*a5eb4ea3SMarcel Moolenaar goto errout; 201*a5eb4ea3SMarcel Moolenaar } 202*a5eb4ea3SMarcel Moolenaar 203*a5eb4ea3SMarcel Moolenaar spec = part->alias; 204*a5eb4ea3SMarcel Moolenaar sep = strchr(spec, '/'); 205*a5eb4ea3SMarcel Moolenaar if (sep != NULL) { 206*a5eb4ea3SMarcel Moolenaar *sep++ = '\0'; 207*a5eb4ea3SMarcel Moolenaar if (strlen(part->alias) == 0 || strlen(sep) == 0) { 208*a5eb4ea3SMarcel Moolenaar error = EINVAL; 209*a5eb4ea3SMarcel Moolenaar goto errout; 210*a5eb4ea3SMarcel Moolenaar } 211*a5eb4ea3SMarcel Moolenaar part->label = strdup(sep); 212*a5eb4ea3SMarcel Moolenaar if (part->label == NULL) { 213*a5eb4ea3SMarcel Moolenaar error = ENOMEM; 214*a5eb4ea3SMarcel Moolenaar goto errout; 215*a5eb4ea3SMarcel Moolenaar } 216*a5eb4ea3SMarcel Moolenaar } 217*a5eb4ea3SMarcel Moolenaar 218*a5eb4ea3SMarcel Moolenaar part->index = nparts; 219*a5eb4ea3SMarcel Moolenaar STAILQ_INSERT_TAIL(&partlist, part, link); 220*a5eb4ea3SMarcel Moolenaar nparts++; 221*a5eb4ea3SMarcel Moolenaar return (0); 222*a5eb4ea3SMarcel Moolenaar 223*a5eb4ea3SMarcel Moolenaar errout: 224*a5eb4ea3SMarcel Moolenaar if (part->alias != NULL) 225*a5eb4ea3SMarcel Moolenaar free(part->alias); 226*a5eb4ea3SMarcel Moolenaar free(part); 227*a5eb4ea3SMarcel Moolenaar return (error); 228*a5eb4ea3SMarcel Moolenaar } 229*a5eb4ea3SMarcel Moolenaar 230*a5eb4ea3SMarcel Moolenaar #if defined(SPARSE_WRITE) 231*a5eb4ea3SMarcel Moolenaar static ssize_t 232*a5eb4ea3SMarcel Moolenaar sparse_write(int fd, const char *buf, size_t sz) 233*a5eb4ea3SMarcel Moolenaar { 234*a5eb4ea3SMarcel Moolenaar const char *p; 235*a5eb4ea3SMarcel Moolenaar off_t ofs; 236*a5eb4ea3SMarcel Moolenaar size_t len; 237*a5eb4ea3SMarcel Moolenaar ssize_t wr, wrsz; 238*a5eb4ea3SMarcel Moolenaar 239*a5eb4ea3SMarcel Moolenaar wrsz = 0; 240*a5eb4ea3SMarcel Moolenaar p = memchr(buf, 0, sz); 241*a5eb4ea3SMarcel Moolenaar while (sz > 0) { 242*a5eb4ea3SMarcel Moolenaar len = (p != NULL) ? (size_t)(p - buf) : sz; 243*a5eb4ea3SMarcel Moolenaar if (len > 0) { 244*a5eb4ea3SMarcel Moolenaar len = (len + secsz - 1) & ~(secsz - 1); 245*a5eb4ea3SMarcel Moolenaar if (len > sz) 246*a5eb4ea3SMarcel Moolenaar len = sz; 247*a5eb4ea3SMarcel Moolenaar wr = write(fd, buf, len); 248*a5eb4ea3SMarcel Moolenaar if (wr < 0) 249*a5eb4ea3SMarcel Moolenaar return (-1); 250*a5eb4ea3SMarcel Moolenaar } else { 251*a5eb4ea3SMarcel Moolenaar while (len < sz && *p++ == '\0') 252*a5eb4ea3SMarcel Moolenaar len++; 253*a5eb4ea3SMarcel Moolenaar if (len < sz) 254*a5eb4ea3SMarcel Moolenaar len &= ~(secsz - 1); 255*a5eb4ea3SMarcel Moolenaar if (len == 0) 256*a5eb4ea3SMarcel Moolenaar continue; 257*a5eb4ea3SMarcel Moolenaar ofs = lseek(fd, len, SEEK_CUR); 258*a5eb4ea3SMarcel Moolenaar if (ofs < 0) 259*a5eb4ea3SMarcel Moolenaar return (-1); 260*a5eb4ea3SMarcel Moolenaar wr = len; 261*a5eb4ea3SMarcel Moolenaar } 262*a5eb4ea3SMarcel Moolenaar buf += wr; 263*a5eb4ea3SMarcel Moolenaar sz -= wr; 264*a5eb4ea3SMarcel Moolenaar wrsz += wr; 265*a5eb4ea3SMarcel Moolenaar p = memchr(buf, 0, sz); 266*a5eb4ea3SMarcel Moolenaar } 267*a5eb4ea3SMarcel Moolenaar return (wrsz); 268*a5eb4ea3SMarcel Moolenaar } 269*a5eb4ea3SMarcel Moolenaar #endif /* SPARSE_WRITE */ 270*a5eb4ea3SMarcel Moolenaar 271*a5eb4ea3SMarcel Moolenaar static int 272*a5eb4ea3SMarcel Moolenaar fdcopy(int src, int dst, uint64_t *count) 273*a5eb4ea3SMarcel Moolenaar { 274*a5eb4ea3SMarcel Moolenaar char *buffer; 275*a5eb4ea3SMarcel Moolenaar off_t ofs; 276*a5eb4ea3SMarcel Moolenaar ssize_t rdsz, wrsz; 277*a5eb4ea3SMarcel Moolenaar 278*a5eb4ea3SMarcel Moolenaar /* A return value of -1 means that we can't write a sparse file. */ 279*a5eb4ea3SMarcel Moolenaar ofs = lseek(dst, 0L, SEEK_CUR); 280*a5eb4ea3SMarcel Moolenaar 281*a5eb4ea3SMarcel Moolenaar if (count != NULL) 282*a5eb4ea3SMarcel Moolenaar *count = 0; 283*a5eb4ea3SMarcel Moolenaar 284*a5eb4ea3SMarcel Moolenaar buffer = malloc(BUFFER_SIZE); 285*a5eb4ea3SMarcel Moolenaar if (buffer == NULL) 286*a5eb4ea3SMarcel Moolenaar return (errno); 287*a5eb4ea3SMarcel Moolenaar while (1) { 288*a5eb4ea3SMarcel Moolenaar rdsz = read(src, buffer, BUFFER_SIZE); 289*a5eb4ea3SMarcel Moolenaar if (rdsz <= 0) { 290*a5eb4ea3SMarcel Moolenaar free(buffer); 291*a5eb4ea3SMarcel Moolenaar return ((rdsz < 0) ? errno : 0); 292*a5eb4ea3SMarcel Moolenaar } 293*a5eb4ea3SMarcel Moolenaar if (count != NULL) 294*a5eb4ea3SMarcel Moolenaar *count += rdsz; 295*a5eb4ea3SMarcel Moolenaar wrsz = (ofs == -1) ? 296*a5eb4ea3SMarcel Moolenaar write(dst, buffer, rdsz) : 297*a5eb4ea3SMarcel Moolenaar sparse_write(dst, buffer, rdsz); 298*a5eb4ea3SMarcel Moolenaar if (wrsz < 0) 299*a5eb4ea3SMarcel Moolenaar break; 300*a5eb4ea3SMarcel Moolenaar } 301*a5eb4ea3SMarcel Moolenaar free(buffer); 302*a5eb4ea3SMarcel Moolenaar return (errno); 303*a5eb4ea3SMarcel Moolenaar } 304*a5eb4ea3SMarcel Moolenaar 305*a5eb4ea3SMarcel Moolenaar int 306*a5eb4ea3SMarcel Moolenaar mkimg_seek(int fd, lba_t blk) 307*a5eb4ea3SMarcel Moolenaar { 308*a5eb4ea3SMarcel Moolenaar off_t off; 309*a5eb4ea3SMarcel Moolenaar 310*a5eb4ea3SMarcel Moolenaar off = blk * secsz; 311*a5eb4ea3SMarcel Moolenaar if (lseek(fd, off, SEEK_SET) != off) 312*a5eb4ea3SMarcel Moolenaar return (errno); 313*a5eb4ea3SMarcel Moolenaar return (0); 314*a5eb4ea3SMarcel Moolenaar } 315*a5eb4ea3SMarcel Moolenaar 316*a5eb4ea3SMarcel Moolenaar static void 317*a5eb4ea3SMarcel Moolenaar mkimg(int bfd) 318*a5eb4ea3SMarcel Moolenaar { 319*a5eb4ea3SMarcel Moolenaar FILE *fp; 320*a5eb4ea3SMarcel Moolenaar struct part *part; 321*a5eb4ea3SMarcel Moolenaar lba_t block; 322*a5eb4ea3SMarcel Moolenaar off_t bytesize; 323*a5eb4ea3SMarcel Moolenaar int error, fd; 324*a5eb4ea3SMarcel Moolenaar 325*a5eb4ea3SMarcel Moolenaar error = scheme_bootcode(bfd); 326*a5eb4ea3SMarcel Moolenaar if (error) 327*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "boot code"); 328*a5eb4ea3SMarcel Moolenaar 329*a5eb4ea3SMarcel Moolenaar /* First check partition information */ 330*a5eb4ea3SMarcel Moolenaar STAILQ_FOREACH(part, &partlist, link) { 331*a5eb4ea3SMarcel Moolenaar error = scheme_check_part(part); 332*a5eb4ea3SMarcel Moolenaar if (error) 333*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "partition %d", part->index+1); 334*a5eb4ea3SMarcel Moolenaar } 335*a5eb4ea3SMarcel Moolenaar 336*a5eb4ea3SMarcel Moolenaar block = scheme_metadata(SCHEME_META_IMG_START, 0); 337*a5eb4ea3SMarcel Moolenaar STAILQ_FOREACH(part, &partlist, link) { 338*a5eb4ea3SMarcel Moolenaar block = scheme_metadata(SCHEME_META_PART_BEFORE, block); 339*a5eb4ea3SMarcel Moolenaar if (verbose) 340*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "partition %d: starting block %llu " 341*a5eb4ea3SMarcel Moolenaar "... ", part->index + 1, (long long)block); 342*a5eb4ea3SMarcel Moolenaar part->block = block; 343*a5eb4ea3SMarcel Moolenaar error = mkimg_seek(tmpfd, block); 344*a5eb4ea3SMarcel Moolenaar switch (part->kind) { 345*a5eb4ea3SMarcel Moolenaar case PART_KIND_SIZE: 346*a5eb4ea3SMarcel Moolenaar if (expand_number(part->contents, &bytesize) == -1) 347*a5eb4ea3SMarcel Moolenaar error = errno; 348*a5eb4ea3SMarcel Moolenaar break; 349*a5eb4ea3SMarcel Moolenaar case PART_KIND_FILE: 350*a5eb4ea3SMarcel Moolenaar fd = open(part->contents, O_RDONLY, 0); 351*a5eb4ea3SMarcel Moolenaar if (fd != -1) { 352*a5eb4ea3SMarcel Moolenaar error = fdcopy(fd, tmpfd, &bytesize); 353*a5eb4ea3SMarcel Moolenaar close(fd); 354*a5eb4ea3SMarcel Moolenaar } else 355*a5eb4ea3SMarcel Moolenaar error = errno; 356*a5eb4ea3SMarcel Moolenaar break; 357*a5eb4ea3SMarcel Moolenaar case PART_KIND_PIPE: 358*a5eb4ea3SMarcel Moolenaar fp = popen(part->contents, "r"); 359*a5eb4ea3SMarcel Moolenaar if (fp != NULL) { 360*a5eb4ea3SMarcel Moolenaar error = fdcopy(fileno(fp), tmpfd, &bytesize); 361*a5eb4ea3SMarcel Moolenaar pclose(fp); 362*a5eb4ea3SMarcel Moolenaar } else 363*a5eb4ea3SMarcel Moolenaar error = errno; 364*a5eb4ea3SMarcel Moolenaar break; 365*a5eb4ea3SMarcel Moolenaar } 366*a5eb4ea3SMarcel Moolenaar if (error) 367*a5eb4ea3SMarcel Moolenaar errc(EX_IOERR, error, "partition %d", part->index + 1); 368*a5eb4ea3SMarcel Moolenaar part->size = (bytesize + secsz - 1) / secsz; 369*a5eb4ea3SMarcel Moolenaar if (verbose) { 370*a5eb4ea3SMarcel Moolenaar bytesize = part->size * secsz; 371*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "size %llu bytes (%llu blocks)\n", 372*a5eb4ea3SMarcel Moolenaar (long long)bytesize, (long long)part->size); 373*a5eb4ea3SMarcel Moolenaar } 374*a5eb4ea3SMarcel Moolenaar block = scheme_metadata(SCHEME_META_PART_AFTER, 375*a5eb4ea3SMarcel Moolenaar part->block + part->size); 376*a5eb4ea3SMarcel Moolenaar } 377*a5eb4ea3SMarcel Moolenaar 378*a5eb4ea3SMarcel Moolenaar block = scheme_metadata(SCHEME_META_IMG_END, block); 379*a5eb4ea3SMarcel Moolenaar error = (scheme_write(tmpfd, block)); 380*a5eb4ea3SMarcel Moolenaar } 381*a5eb4ea3SMarcel Moolenaar 382*a5eb4ea3SMarcel Moolenaar int 383*a5eb4ea3SMarcel Moolenaar main(int argc, char *argv[]) 384*a5eb4ea3SMarcel Moolenaar { 385*a5eb4ea3SMarcel Moolenaar int c, error; 386*a5eb4ea3SMarcel Moolenaar 387*a5eb4ea3SMarcel Moolenaar while ((c = getopt(argc, argv, "b:o:p:s:vH:P:S:T:")) != -1) { 388*a5eb4ea3SMarcel Moolenaar switch (c) { 389*a5eb4ea3SMarcel Moolenaar case 'b': /* BOOT CODE */ 390*a5eb4ea3SMarcel Moolenaar if (bcfd != -1) 391*a5eb4ea3SMarcel Moolenaar usage("multiple bootcode given"); 392*a5eb4ea3SMarcel Moolenaar bcfd = open(optarg, O_RDONLY, 0); 393*a5eb4ea3SMarcel Moolenaar if (bcfd == -1) 394*a5eb4ea3SMarcel Moolenaar err(EX_UNAVAILABLE, "%s", optarg); 395*a5eb4ea3SMarcel Moolenaar break; 396*a5eb4ea3SMarcel Moolenaar case 'o': /* OUTPUT FILE */ 397*a5eb4ea3SMarcel Moolenaar if (outfd != 0) 398*a5eb4ea3SMarcel Moolenaar usage("multiple output files given"); 399*a5eb4ea3SMarcel Moolenaar outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 400*a5eb4ea3SMarcel Moolenaar S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 401*a5eb4ea3SMarcel Moolenaar if (outfd == -1) 402*a5eb4ea3SMarcel Moolenaar err(EX_CANTCREAT, "%s", optarg); 403*a5eb4ea3SMarcel Moolenaar break; 404*a5eb4ea3SMarcel Moolenaar case 'p': /* PARTITION */ 405*a5eb4ea3SMarcel Moolenaar error = parse_part(optarg); 406*a5eb4ea3SMarcel Moolenaar if (error) 407*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "partition"); 408*a5eb4ea3SMarcel Moolenaar break; 409*a5eb4ea3SMarcel Moolenaar case 's': /* SCHEME */ 410*a5eb4ea3SMarcel Moolenaar if (scheme_selected() != NULL) 411*a5eb4ea3SMarcel Moolenaar usage("multiple schemes given"); 412*a5eb4ea3SMarcel Moolenaar error = scheme_select(optarg); 413*a5eb4ea3SMarcel Moolenaar if (error) 414*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "scheme"); 415*a5eb4ea3SMarcel Moolenaar break; 416*a5eb4ea3SMarcel Moolenaar case 'v': 417*a5eb4ea3SMarcel Moolenaar verbose++; 418*a5eb4ea3SMarcel Moolenaar break; 419*a5eb4ea3SMarcel Moolenaar case 'H': /* GEOMETRY: HEADS */ 420*a5eb4ea3SMarcel Moolenaar error = parse_number(&nheads, 1, 255, optarg); 421*a5eb4ea3SMarcel Moolenaar if (error) 422*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "number of heads"); 423*a5eb4ea3SMarcel Moolenaar break; 424*a5eb4ea3SMarcel Moolenaar case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */ 425*a5eb4ea3SMarcel Moolenaar error = parse_number(&blksz, 512, INT_MAX+1U, optarg); 426*a5eb4ea3SMarcel Moolenaar if (error == 0 && !pwr_of_two(blksz)) 427*a5eb4ea3SMarcel Moolenaar error = EINVAL; 428*a5eb4ea3SMarcel Moolenaar if (error) 429*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "physical sector size"); 430*a5eb4ea3SMarcel Moolenaar break; 431*a5eb4ea3SMarcel Moolenaar case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */ 432*a5eb4ea3SMarcel Moolenaar error = parse_number(&secsz, 512, INT_MAX+1U, optarg); 433*a5eb4ea3SMarcel Moolenaar if (error == 0 && !pwr_of_two(secsz)) 434*a5eb4ea3SMarcel Moolenaar error = EINVAL; 435*a5eb4ea3SMarcel Moolenaar if (error) 436*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "logical sector size"); 437*a5eb4ea3SMarcel Moolenaar break; 438*a5eb4ea3SMarcel Moolenaar case 'T': /* GEOMETRY: TRACK SIZE */ 439*a5eb4ea3SMarcel Moolenaar error = parse_number(&nsecs, 1, 63, optarg); 440*a5eb4ea3SMarcel Moolenaar if (error) 441*a5eb4ea3SMarcel Moolenaar errc(EX_DATAERR, error, "track size"); 442*a5eb4ea3SMarcel Moolenaar break; 443*a5eb4ea3SMarcel Moolenaar default: 444*a5eb4ea3SMarcel Moolenaar usage("unknown option"); 445*a5eb4ea3SMarcel Moolenaar } 446*a5eb4ea3SMarcel Moolenaar } 447*a5eb4ea3SMarcel Moolenaar 448*a5eb4ea3SMarcel Moolenaar if (argc > optind) 449*a5eb4ea3SMarcel Moolenaar usage("trailing arguments"); 450*a5eb4ea3SMarcel Moolenaar if (scheme_selected() == NULL) 451*a5eb4ea3SMarcel Moolenaar usage("no scheme"); 452*a5eb4ea3SMarcel Moolenaar if (nparts == 0) 453*a5eb4ea3SMarcel Moolenaar usage("no partitions"); 454*a5eb4ea3SMarcel Moolenaar 455*a5eb4ea3SMarcel Moolenaar if (secsz > blksz) { 456*a5eb4ea3SMarcel Moolenaar if (blksz != 0) 457*a5eb4ea3SMarcel Moolenaar errx(EX_DATAERR, "the physical block size cannot " 458*a5eb4ea3SMarcel Moolenaar "be smaller than the sector size"); 459*a5eb4ea3SMarcel Moolenaar blksz = secsz; 460*a5eb4ea3SMarcel Moolenaar } 461*a5eb4ea3SMarcel Moolenaar 462*a5eb4ea3SMarcel Moolenaar if (secsz > scheme_max_secsz()) 463*a5eb4ea3SMarcel Moolenaar errx(EX_DATAERR, "maximum sector size supported is %u; " 464*a5eb4ea3SMarcel Moolenaar "size specified is %u", scheme_max_secsz(), secsz); 465*a5eb4ea3SMarcel Moolenaar 466*a5eb4ea3SMarcel Moolenaar if (nparts > scheme_max_parts()) 467*a5eb4ea3SMarcel Moolenaar errx(EX_DATAERR, "%d partitions supported; %d given", 468*a5eb4ea3SMarcel Moolenaar scheme_max_parts(), nparts); 469*a5eb4ea3SMarcel Moolenaar 470*a5eb4ea3SMarcel Moolenaar if (outfd == 0) { 471*a5eb4ea3SMarcel Moolenaar if (atexit(cleanup) == -1) 472*a5eb4ea3SMarcel Moolenaar err(EX_OSERR, "cannot register cleanup function"); 473*a5eb4ea3SMarcel Moolenaar outfd = 1; 474*a5eb4ea3SMarcel Moolenaar tmpfd = mkstemp(tmpfname); 475*a5eb4ea3SMarcel Moolenaar if (tmpfd == -1) 476*a5eb4ea3SMarcel Moolenaar err(EX_OSERR, "cannot create temporary file"); 477*a5eb4ea3SMarcel Moolenaar } else 478*a5eb4ea3SMarcel Moolenaar tmpfd = outfd; 479*a5eb4ea3SMarcel Moolenaar 480*a5eb4ea3SMarcel Moolenaar if (verbose) { 481*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "Logical sector size: %u\n", secsz); 482*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "Physical block size: %u\n", blksz); 483*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "Sectors per track: %u\n", nsecs); 484*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "Number of heads: %u\n", nheads); 485*a5eb4ea3SMarcel Moolenaar } 486*a5eb4ea3SMarcel Moolenaar 487*a5eb4ea3SMarcel Moolenaar mkimg(bcfd); 488*a5eb4ea3SMarcel Moolenaar 489*a5eb4ea3SMarcel Moolenaar if (verbose) 490*a5eb4ea3SMarcel Moolenaar fprintf(stderr, "Number of cylinders: %u\n", ncyls); 491*a5eb4ea3SMarcel Moolenaar 492*a5eb4ea3SMarcel Moolenaar if (tmpfd != outfd) { 493*a5eb4ea3SMarcel Moolenaar error = mkimg_seek(tmpfd, 0); 494*a5eb4ea3SMarcel Moolenaar if (error == 0) 495*a5eb4ea3SMarcel Moolenaar error = fdcopy(tmpfd, outfd, NULL); 496*a5eb4ea3SMarcel Moolenaar if (error) 497*a5eb4ea3SMarcel Moolenaar errc(EX_IOERR, error, "writing to stdout"); 498*a5eb4ea3SMarcel Moolenaar } 499*a5eb4ea3SMarcel Moolenaar 500*a5eb4ea3SMarcel Moolenaar return (0); 501*a5eb4ea3SMarcel Moolenaar } 502