1 /*- 2 * Copyright (c) 2013,2014 Juniper Networks, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/stat.h> 29 #include <errno.h> 30 #include <err.h> 31 #include <fcntl.h> 32 #include <getopt.h> 33 #include <libutil.h> 34 #include <limits.h> 35 #include <stdbool.h> 36 #include <stdint.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sysexits.h> 41 #include <unistd.h> 42 43 #include "image.h" 44 #include "format.h" 45 #include "mkimg.h" 46 #include "scheme.h" 47 48 #define LONGOPT_FORMATS 0x01000001 49 #define LONGOPT_SCHEMES 0x01000002 50 #define LONGOPT_VERSION 0x01000003 51 #define LONGOPT_CAPACITY 0x01000004 52 53 static struct option longopts[] = { 54 { "formats", no_argument, NULL, LONGOPT_FORMATS }, 55 { "schemes", no_argument, NULL, LONGOPT_SCHEMES }, 56 { "version", no_argument, NULL, LONGOPT_VERSION }, 57 { "capacity", required_argument, NULL, LONGOPT_CAPACITY }, 58 { NULL, 0, NULL, 0 } 59 }; 60 61 static uint64_t min_capacity = 0; 62 static uint64_t max_capacity = 0; 63 64 /* Fixed timestamp for reproducible builds. */ 65 time_t timestamp = (time_t)-1; 66 67 struct partlisthead partlist = TAILQ_HEAD_INITIALIZER(partlist); 68 u_int nparts = 0; 69 70 u_int unit_testing; 71 u_int verbose; 72 73 u_int ncyls = 0; 74 u_int nheads = 1; 75 u_int nsecs = 1; 76 u_int secsz = 512; 77 u_int blksz = 0; 78 uint32_t active_partition = 0; 79 80 static void 81 print_formats(int usage) 82 { 83 struct mkimg_format *f; 84 const char *sep; 85 86 if (usage) { 87 fprintf(stderr, " formats:\n"); 88 f = NULL; 89 while ((f = format_iterate(f)) != NULL) { 90 fprintf(stderr, "\t%s\t- %s\n", f->name, 91 f->description); 92 } 93 } else { 94 sep = ""; 95 f = NULL; 96 while ((f = format_iterate(f)) != NULL) { 97 printf("%s%s", sep, f->name); 98 sep = " "; 99 } 100 putchar('\n'); 101 } 102 } 103 104 static void 105 print_schemes(int usage) 106 { 107 struct mkimg_scheme *s; 108 const char *sep; 109 110 if (usage) { 111 fprintf(stderr, " schemes:\n"); 112 s = NULL; 113 while ((s = scheme_iterate(s)) != NULL) { 114 fprintf(stderr, "\t%s\t- %s\n", s->name, 115 s->description); 116 } 117 } else { 118 sep = ""; 119 s = NULL; 120 while ((s = scheme_iterate(s)) != NULL) { 121 printf("%s%s", sep, s->name); 122 sep = " "; 123 } 124 putchar('\n'); 125 } 126 } 127 128 static void 129 print_version(void) 130 { 131 u_int width; 132 133 #ifdef __LP64__ 134 width = 64; 135 #else 136 width = 32; 137 #endif 138 printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width); 139 } 140 141 static void 142 usage(const char *why) 143 { 144 145 if (why != NULL) { 146 warnx("error: %s", why); 147 fputc('\n', stderr); 148 } 149 fprintf(stderr, "usage: %s <options>\n", getprogname()); 150 151 fprintf(stderr, " options:\n"); 152 fprintf(stderr, "\t--formats\t- list image formats\n"); 153 fprintf(stderr, "\t--schemes\t- list partition schemes\n"); 154 fprintf(stderr, "\t--version\t- show version information\n"); 155 fputc('\n', stderr); 156 fprintf(stderr, "\t-a <num>\t- mark num'th partition as active\n"); 157 fprintf(stderr, "\t-b <file>\t- file containing boot code\n"); 158 fprintf(stderr, "\t-c <num>\t- minimum capacity (in bytes) of the disk\n"); 159 fprintf(stderr, "\t-C <num>\t- maximum capacity (in bytes) of the disk\n"); 160 fprintf(stderr, "\t-f <format>\n"); 161 fprintf(stderr, "\t-o <file>\t- file to write image into\n"); 162 fprintf(stderr, "\t-p <partition>\n"); 163 fprintf(stderr, "\t-s <scheme>\n"); 164 fprintf(stderr, "\t-v\t\t- increase verbosity\n"); 165 fprintf(stderr, "\t-y\t\t- [developers] enable unit test\n"); 166 fprintf(stderr, "\t-H <num>\t- number of heads to simulate\n"); 167 fprintf(stderr, "\t-P <num>\t- physical sector size\n"); 168 fprintf(stderr, "\t-S <num>\t- logical sector size\n"); 169 fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n"); 170 fputc('\n', stderr); 171 print_formats(1); 172 fputc('\n', stderr); 173 print_schemes(1); 174 fputc('\n', stderr); 175 fprintf(stderr, " partition specification:\n"); 176 fprintf(stderr, "\t<type>[/<label>]::<size>[:[+]<offset>]\t- " 177 "empty partition of given size and\n\t\t\t\t\t" 178 " optional relative or absolute offset\n"); 179 fprintf(stderr, "\t<type>[/<label>]:=<file>[:[+]offset]\t- partition " 180 "content and size are\n\t\t\t\t\t" 181 " determined by the named file and\n" 182 "\t\t\t\t\t optional relative or absolute offset\n"); 183 fprintf(stderr, "\t<type>[/<label>]:-<cmd>\t\t- partition content and size " 184 "are taken\n\t\t\t\t\t from the output of the command to run\n"); 185 fprintf(stderr, "\t-\t\t\t\t- unused partition entry\n"); 186 fprintf(stderr, "\t where:\n"); 187 fprintf(stderr, "\t\t<type>\t- scheme neutral partition type\n"); 188 fprintf(stderr, "\t\t<label>\t- optional scheme-dependent partition " 189 "label\n"); 190 191 exit(EX_USAGE); 192 } 193 194 static int 195 parse_uint32(uint32_t *valp, uint32_t min, uint32_t max, const char *arg) 196 { 197 uint64_t val; 198 199 if (expand_number(arg, &val) == -1) 200 return (errno); 201 if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max) 202 return (EINVAL); 203 *valp = (uint32_t)val; 204 return (0); 205 } 206 207 static int 208 parse_uint64(uint64_t *valp, uint64_t min, uint64_t max, const char *arg) 209 { 210 uint64_t val; 211 212 if (expand_number(arg, &val) == -1) 213 return (errno); 214 if (val < min || val > max) 215 return (EINVAL); 216 *valp = val; 217 return (0); 218 } 219 220 static int 221 pwr_of_two(u_int nr) 222 { 223 224 return (((nr & (nr - 1)) == 0) ? 1 : 0); 225 } 226 227 /* 228 * A partition specification has the following format: 229 * <type> ':' <kind> <contents> 230 * where: 231 * type the partition type alias 232 * kind the interpretation of the contents specification 233 * ':' contents holds the size of an empty partition 234 * '=' contents holds the name of a file to read 235 * '-' contents holds a command to run; the output of 236 * which is the contents of the partition. 237 * contents the specification of a partition's contents 238 * 239 * A specification that is a single dash indicates an unused partition 240 * entry. 241 */ 242 static int 243 parse_part(const char *spec) 244 { 245 struct part *part; 246 char *sep; 247 size_t len; 248 int error; 249 250 if (strcmp(spec, "-") == 0) { 251 nparts++; 252 return (0); 253 } 254 255 part = calloc(1, sizeof(struct part)); 256 if (part == NULL) 257 return (ENOMEM); 258 259 sep = strchr(spec, ':'); 260 if (sep == NULL) { 261 error = EINVAL; 262 goto errout; 263 } 264 len = sep - spec + 1; 265 if (len < 2) { 266 error = EINVAL; 267 goto errout; 268 } 269 part->alias = malloc(len); 270 if (part->alias == NULL) { 271 error = ENOMEM; 272 goto errout; 273 } 274 strlcpy(part->alias, spec, len); 275 spec = sep + 1; 276 277 switch (*spec) { 278 case ':': 279 part->kind = PART_KIND_SIZE; 280 break; 281 case '=': 282 part->kind = PART_KIND_FILE; 283 break; 284 case '-': 285 part->kind = PART_KIND_PIPE; 286 break; 287 default: 288 error = EINVAL; 289 goto errout; 290 } 291 spec++; 292 293 part->contents = strdup(spec); 294 if (part->contents == NULL) { 295 error = ENOMEM; 296 goto errout; 297 } 298 299 spec = part->alias; 300 sep = strchr(spec, '/'); 301 if (sep != NULL) { 302 *sep++ = '\0'; 303 if (strlen(part->alias) == 0 || strlen(sep) == 0) { 304 error = EINVAL; 305 goto errout; 306 } 307 part->label = strdup(sep); 308 if (part->label == NULL) { 309 error = ENOMEM; 310 goto errout; 311 } 312 } 313 314 part->index = nparts; 315 TAILQ_INSERT_TAIL(&partlist, part, link); 316 nparts++; 317 return (0); 318 319 errout: 320 if (part->alias != NULL) 321 free(part->alias); 322 free(part); 323 return (error); 324 } 325 326 #if defined(SPARSE_WRITE) 327 ssize_t 328 sparse_write(int fd, const void *ptr, size_t sz) 329 { 330 const char *buf, *p; 331 off_t ofs; 332 size_t len; 333 ssize_t wr, wrsz; 334 335 buf = ptr; 336 wrsz = 0; 337 p = memchr(buf, 0, sz); 338 while (sz > 0) { 339 len = (p != NULL) ? (size_t)(p - buf) : sz; 340 if (len > 0) { 341 len = (len + secsz - 1) & ~(secsz - 1); 342 if (len > sz) 343 len = sz; 344 wr = write(fd, buf, len); 345 if (wr < 0) 346 return (-1); 347 } else { 348 while (len < sz && *p++ == '\0') 349 len++; 350 if (len < sz) 351 len &= ~(secsz - 1); 352 if (len == 0) 353 continue; 354 ofs = lseek(fd, len, SEEK_CUR); 355 if (ofs < 0) 356 return (-1); 357 wr = len; 358 } 359 buf += wr; 360 sz -= wr; 361 wrsz += wr; 362 p = memchr(buf, 0, sz); 363 } 364 return (wrsz); 365 } 366 #endif /* SPARSE_WRITE */ 367 368 void 369 mkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp) 370 { 371 u_int hd, sec; 372 373 *cylp = *hdp = *secp = ~0U; 374 if (nsecs == 1 || nheads == 1) 375 return; 376 377 sec = lba % nsecs + 1; 378 lba /= nsecs; 379 hd = lba % nheads; 380 lba /= nheads; 381 if (lba > maxcyl) 382 return; 383 384 *cylp = lba; 385 *hdp = hd; 386 *secp = sec; 387 } 388 389 static int 390 capacity_resize(lba_t end) 391 { 392 lba_t min_capsz, max_capsz; 393 394 min_capsz = (min_capacity + secsz - 1) / secsz; 395 max_capsz = (max_capacity + secsz - 1) / secsz; 396 397 if (max_capsz != 0 && end > max_capsz) 398 return (ENOSPC); 399 if (end >= min_capsz) 400 return (0); 401 402 return (image_set_size(min_capsz)); 403 } 404 405 static void 406 mkimg_validate(void) 407 { 408 struct part *part, *part2; 409 lba_t start, end, start2, end2; 410 int i, j; 411 412 i = 0; 413 414 TAILQ_FOREACH(part, &partlist, link) { 415 start = part->block; 416 end = part->block + part->size; 417 j = i + 1; 418 part2 = TAILQ_NEXT(part, link); 419 if (part2 == NULL) 420 break; 421 422 TAILQ_FOREACH_FROM(part2, &partlist, link) { 423 start2 = part2->block; 424 end2 = part2->block + part2->size; 425 426 if ((start >= start2 && start < end2) || 427 (end > start2 && end <= end2)) { 428 errx(1, "partition %d overlaps partition %d", 429 i, j); 430 } 431 432 j++; 433 } 434 435 i++; 436 } 437 } 438 439 static void 440 mkimg(void) 441 { 442 FILE *fp; 443 struct part *part; 444 lba_t block, blkoffset; 445 uint64_t bytesize, byteoffset; 446 char *size, *offset; 447 bool abs_offset; 448 int error, fd; 449 450 /* First check partition information */ 451 TAILQ_FOREACH(part, &partlist, link) { 452 error = scheme_check_part(part); 453 if (error) 454 errc(EX_DATAERR, error, "partition %d", part->index+1); 455 } 456 457 block = scheme_metadata(SCHEME_META_IMG_START, 0); 458 abs_offset = false; 459 TAILQ_FOREACH(part, &partlist, link) { 460 byteoffset = blkoffset = 0; 461 abs_offset = false; 462 463 /* Look for an offset. Set size too if we can. */ 464 switch (part->kind) { 465 case PART_KIND_SIZE: 466 case PART_KIND_FILE: 467 offset = part->contents; 468 size = strsep(&offset, ":"); 469 if (part->kind == PART_KIND_SIZE && 470 expand_number(size, &bytesize) == -1) 471 error = errno; 472 if (offset != NULL) { 473 if (*offset != '+') 474 abs_offset = true; 475 else 476 offset++; 477 if (expand_number(offset, &byteoffset) == -1) 478 error = errno; 479 } 480 break; 481 } 482 483 /* Work out exactly where the partition starts. */ 484 blkoffset = (byteoffset + secsz - 1) / secsz; 485 if (abs_offset) 486 block = scheme_metadata(SCHEME_META_PART_ABSOLUTE, 487 blkoffset); 488 else 489 block = scheme_metadata(SCHEME_META_PART_BEFORE, 490 block + blkoffset); 491 part->block = block; 492 493 if (verbose) 494 fprintf(stderr, "partition %d: starting block %llu " 495 "... ", part->index + 1, (long long)part->block); 496 497 /* Pull in partition contents, set size if we haven't yet. */ 498 switch (part->kind) { 499 case PART_KIND_FILE: 500 fd = open(part->contents, O_RDONLY, 0); 501 if (fd != -1) { 502 error = image_copyin(block, fd, &bytesize); 503 close(fd); 504 } else 505 error = errno; 506 break; 507 case PART_KIND_PIPE: 508 fp = popen(part->contents, "r"); 509 if (fp != NULL) { 510 fd = fileno(fp); 511 error = image_copyin(block, fd, &bytesize); 512 pclose(fp); 513 } else 514 error = errno; 515 break; 516 } 517 if (error) 518 errc(EX_IOERR, error, "partition %d", part->index + 1); 519 part->size = (bytesize + secsz - 1) / secsz; 520 if (verbose) { 521 bytesize = part->size * secsz; 522 fprintf(stderr, "size %llu bytes (%llu blocks)\n", 523 (long long)bytesize, (long long)part->size); 524 if (abs_offset) { 525 fprintf(stderr, 526 " location %llu bytes (%llu blocks)\n", 527 (long long)byteoffset, 528 (long long)blkoffset); 529 } else if (blkoffset > 0) { 530 fprintf(stderr, 531 " offset %llu bytes (%llu blocks)\n", 532 (long long)byteoffset, 533 (long long)blkoffset); 534 } 535 } 536 block = scheme_metadata(SCHEME_META_PART_AFTER, 537 part->block + part->size); 538 } 539 540 mkimg_validate(); 541 542 block = scheme_metadata(SCHEME_META_IMG_END, block); 543 error = image_set_size(block); 544 if (!error) { 545 error = capacity_resize(block); 546 block = image_get_size(); 547 } 548 if (!error) { 549 error = format_resize(block); 550 block = image_get_size(); 551 } 552 if (error) 553 errc(EX_IOERR, error, "image sizing"); 554 ncyls = block / (nsecs * nheads); 555 error = scheme_write(block); 556 if (error) 557 errc(EX_IOERR, error, "writing metadata"); 558 } 559 560 int 561 main(int argc, char *argv[]) 562 { 563 const char *format_name; 564 int bcfd, outfd; 565 int c, error; 566 567 bcfd = -1; 568 outfd = 1; /* Write to stdout by default */ 569 while ((c = getopt_long(argc, argv, "a:b:c:C:f:ho:p:s:t:vyH:P:S:T:", 570 longopts, NULL)) != -1) { 571 switch (c) { 572 case 'a': /* ACTIVE PARTITION, if supported */ 573 error = parse_uint32(&active_partition, 1, 100, optarg); 574 if (error) 575 errc(EX_DATAERR, error, "Partition ordinal"); 576 break; 577 case 'b': /* BOOT CODE */ 578 if (bcfd != -1) 579 usage("multiple bootcode given"); 580 bcfd = open(optarg, O_RDONLY, 0); 581 if (bcfd == -1) 582 err(EX_UNAVAILABLE, "%s", optarg); 583 break; 584 case 'c': /* MINIMUM CAPACITY */ 585 error = parse_uint64(&min_capacity, 1, INT64_MAX, optarg); 586 if (error) 587 errc(EX_DATAERR, error, "minimum capacity in bytes"); 588 break; 589 case 'C': /* MAXIMUM CAPACITY */ 590 error = parse_uint64(&max_capacity, 1, INT64_MAX, optarg); 591 if (error) 592 errc(EX_DATAERR, error, "maximum capacity in bytes"); 593 break; 594 case 'f': /* OUTPUT FORMAT */ 595 if (format_selected() != NULL) 596 usage("multiple formats given"); 597 error = format_select(optarg); 598 if (error) 599 errc(EX_DATAERR, error, "format"); 600 break; 601 case 'h': /* HELP */ 602 usage(NULL); 603 break; 604 case 'o': /* OUTPUT FILE */ 605 if (outfd != 1) 606 usage("multiple output files given"); 607 outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 608 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 609 if (outfd == -1) 610 err(EX_CANTCREAT, "%s", optarg); 611 break; 612 case 'p': /* PARTITION */ 613 error = parse_part(optarg); 614 if (error) 615 errc(EX_DATAERR, error, "partition"); 616 break; 617 case 's': /* SCHEME */ 618 if (scheme_selected() != NULL) 619 usage("multiple schemes given"); 620 error = scheme_select(optarg); 621 if (error) 622 errc(EX_DATAERR, error, "scheme"); 623 break; 624 case 't': { 625 char *ep; 626 long long val; 627 628 errno = 0; 629 val = strtoll(optarg, &ep, 0); 630 if (ep == optarg || *ep != '\0') 631 errno = EINVAL; 632 if (errno != 0) 633 errc(EX_DATAERR, errno, "timestamp"); 634 timestamp = (time_t)val; 635 break; 636 } 637 case 'y': 638 unit_testing++; 639 break; 640 case 'v': 641 verbose++; 642 break; 643 case 'H': /* GEOMETRY: HEADS */ 644 error = parse_uint32(&nheads, 1, 255, optarg); 645 if (error) 646 errc(EX_DATAERR, error, "number of heads"); 647 break; 648 case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */ 649 error = parse_uint32(&blksz, 512, INT_MAX+1U, optarg); 650 if (error == 0 && !pwr_of_two(blksz)) 651 error = EINVAL; 652 if (error) 653 errc(EX_DATAERR, error, "physical sector size"); 654 break; 655 case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */ 656 error = parse_uint32(&secsz, 512, INT_MAX+1U, optarg); 657 if (error == 0 && !pwr_of_two(secsz)) 658 error = EINVAL; 659 if (error) 660 errc(EX_DATAERR, error, "logical sector size"); 661 break; 662 case 'T': /* GEOMETRY: TRACK SIZE */ 663 error = parse_uint32(&nsecs, 1, 63, optarg); 664 if (error) 665 errc(EX_DATAERR, error, "track size"); 666 break; 667 case LONGOPT_FORMATS: 668 print_formats(0); 669 exit(EX_OK); 670 /*NOTREACHED*/ 671 case LONGOPT_SCHEMES: 672 print_schemes(0); 673 exit(EX_OK); 674 /*NOTREACHED*/ 675 case LONGOPT_VERSION: 676 print_version(); 677 exit(EX_OK); 678 /*NOTREACHED*/ 679 case LONGOPT_CAPACITY: 680 error = parse_uint64(&min_capacity, 1, INT64_MAX, optarg); 681 if (error) 682 errc(EX_DATAERR, error, "capacity in bytes"); 683 max_capacity = min_capacity; 684 break; 685 default: 686 usage("unknown option"); 687 } 688 } 689 690 if (argc > optind) 691 usage("trailing arguments"); 692 if (scheme_selected() == NULL && nparts > 0) 693 usage("no scheme"); 694 if (nparts == 0 && min_capacity == 0) 695 usage("no partitions"); 696 if (max_capacity != 0 && min_capacity > max_capacity) 697 usage("minimum capacity cannot be larger than the maximum one"); 698 699 if (secsz > blksz) { 700 if (blksz != 0) 701 errx(EX_DATAERR, "the physical block size cannot " 702 "be smaller than the sector size"); 703 blksz = secsz; 704 } 705 706 if (secsz > scheme_max_secsz()) 707 errx(EX_DATAERR, "maximum sector size supported is %u; " 708 "size specified is %u", scheme_max_secsz(), secsz); 709 710 if (nparts > scheme_max_parts()) 711 errx(EX_DATAERR, "%d partitions supported; %d given", 712 scheme_max_parts(), nparts); 713 714 if (format_selected() == NULL) 715 format_select("raw"); 716 717 if (bcfd != -1) { 718 error = scheme_bootcode(bcfd); 719 close(bcfd); 720 if (error) 721 errc(EX_DATAERR, error, "boot code"); 722 } 723 724 format_name = format_selected()->name; 725 if (verbose) { 726 fprintf(stderr, "Logical sector size: %u\n", secsz); 727 fprintf(stderr, "Physical block size: %u\n", blksz); 728 fprintf(stderr, "Sectors per track: %u\n", nsecs); 729 fprintf(stderr, "Number of heads: %u\n", nheads); 730 fputc('\n', stderr); 731 if (scheme_selected()) 732 fprintf(stderr, "Partitioning scheme: %s\n", 733 scheme_selected()->name); 734 fprintf(stderr, "Output file format: %s\n", 735 format_name); 736 fputc('\n', stderr); 737 } 738 739 #if defined(SPARSE_WRITE) 740 /* 741 * sparse_write() fails if output is not seekable so fail early 742 * not wasting some load unless output format is raw 743 */ 744 if (strcmp("raw", format_name) && 745 lseek(outfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) 746 errx(EX_USAGE, "%s: output must be seekable", format_name); 747 #endif 748 749 error = image_init(); 750 if (error) 751 errc(EX_OSERR, error, "cannot initialize"); 752 753 mkimg(); 754 755 if (verbose) { 756 fputc('\n', stderr); 757 fprintf(stderr, "Number of cylinders: %u\n", ncyls); 758 } 759 760 error = format_write(outfd); 761 if (error) 762 errc(EX_IOERR, error, "writing image"); 763 764 return (0); 765 } 766