mkimg.c 18 KB

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