101a0f853SOlivier Houchard /* $NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $ */ 2d347a0daSSam Leffler 3d347a0daSSam Leffler /* 4d347a0daSSam Leffler * Copyright (c) 2001-2003 Wasabi Systems, Inc. 5d347a0daSSam Leffler * All rights reserved. 6d347a0daSSam Leffler * 7d347a0daSSam Leffler * Written by Luke Mewburn for Wasabi Systems, Inc. 8d347a0daSSam Leffler * 9d347a0daSSam Leffler * Redistribution and use in source and binary forms, with or without 10d347a0daSSam Leffler * modification, are permitted provided that the following conditions 11d347a0daSSam Leffler * are met: 12d347a0daSSam Leffler * 1. Redistributions of source code must retain the above copyright 13d347a0daSSam Leffler * notice, this list of conditions and the following disclaimer. 14d347a0daSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 15d347a0daSSam Leffler * notice, this list of conditions and the following disclaimer in the 16d347a0daSSam Leffler * documentation and/or other materials provided with the distribution. 17d347a0daSSam Leffler * 3. All advertising materials mentioning features or use of this software 18d347a0daSSam Leffler * must display the following acknowledgement: 19d347a0daSSam Leffler * This product includes software developed for the NetBSD Project by 20d347a0daSSam Leffler * Wasabi Systems, Inc. 21d347a0daSSam Leffler * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22d347a0daSSam Leffler * or promote products derived from this software without specific prior 23d347a0daSSam Leffler * written permission. 24d347a0daSSam Leffler * 25d347a0daSSam Leffler * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26d347a0daSSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27d347a0daSSam Leffler * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28d347a0daSSam Leffler * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29d347a0daSSam Leffler * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30d347a0daSSam Leffler * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31d347a0daSSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32d347a0daSSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33d347a0daSSam Leffler * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34d347a0daSSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35d347a0daSSam Leffler * POSSIBILITY OF SUCH DAMAGE. 36d347a0daSSam Leffler */ 37d347a0daSSam Leffler 38d347a0daSSam Leffler #include <sys/cdefs.h> 39d347a0daSSam Leffler __FBSDID("$FreeBSD$"); 40d347a0daSSam Leffler 41484b5c25SMarcel Moolenaar #include <sys/types.h> 42484b5c25SMarcel Moolenaar #include <sys/stat.h> 43d347a0daSSam Leffler #include <assert.h> 44d347a0daSSam Leffler #include <ctype.h> 45d347a0daSSam Leffler #include <errno.h> 46d347a0daSSam Leffler #include <limits.h> 47d347a0daSSam Leffler #include <stdio.h> 48d347a0daSSam Leffler #include <stdlib.h> 49d347a0daSSam Leffler #include <string.h> 507649cb00SKirk McKusick #include <time.h> 51d347a0daSSam Leffler #include <unistd.h> 52776c6824SEd Maste #include <stdbool.h> 535f5598b1SEd Maste #include <util.h> 54d347a0daSSam Leffler 55d347a0daSSam Leffler #include "makefs.h" 56d347a0daSSam Leffler #include "mtree.h" 57d347a0daSSam Leffler 58d347a0daSSam Leffler /* 59d347a0daSSam Leffler * list of supported file systems and dispatch functions 60d347a0daSSam Leffler */ 61d347a0daSSam Leffler typedef struct { 62d347a0daSSam Leffler const char *type; 6301a0f853SOlivier Houchard void (*prepare_options)(fsinfo_t *); 64d347a0daSSam Leffler int (*parse_options)(const char *, fsinfo_t *); 6501a0f853SOlivier Houchard void (*cleanup_options)(fsinfo_t *); 66d347a0daSSam Leffler void (*make_fs)(const char *, const char *, fsnode *, 67d347a0daSSam Leffler fsinfo_t *); 68d347a0daSSam Leffler } fstype_t; 69d347a0daSSam Leffler 70d347a0daSSam Leffler static fstype_t fstypes[] = { 71203b6f69SEd Maste #define ENTRY(name) { \ 72203b6f69SEd Maste # name, name ## _prep_opts, name ## _parse_opts, \ 73203b6f69SEd Maste name ## _cleanup_opts, name ## _makefs \ 74203b6f69SEd Maste } 75203b6f69SEd Maste ENTRY(ffs), 76203b6f69SEd Maste ENTRY(cd9660), 7701a0f853SOlivier Houchard { .type = NULL }, 78d347a0daSSam Leffler }; 79d347a0daSSam Leffler 80d347a0daSSam Leffler u_int debug; 81b0d9addeSBrooks Davis int dupsok; 82d347a0daSSam Leffler struct timespec start_time; 837b03d164SEd Maste struct stat stampst; 84d347a0daSSam Leffler 85d347a0daSSam Leffler static fstype_t *get_fstype(const char *); 867b03d164SEd Maste static int get_tstamp(const char *, struct stat *); 87776c6824SEd Maste static void usage(fstype_t *, fsinfo_t *); 88d347a0daSSam Leffler 89d347a0daSSam Leffler int 90d347a0daSSam Leffler main(int argc, char *argv[]) 91d347a0daSSam Leffler { 92484b5c25SMarcel Moolenaar struct stat sb; 93d347a0daSSam Leffler struct timeval start; 94d347a0daSSam Leffler fstype_t *fstype; 95d347a0daSSam Leffler fsinfo_t fsoptions; 96d347a0daSSam Leffler fsnode *root; 97688aaa09SJung-uk Kim int ch, i, len; 98*9e96f90bSEd Maste const char *subtree; 99*9e96f90bSEd Maste const char *specfile; 100d347a0daSSam Leffler 101d347a0daSSam Leffler setprogname(argv[0]); 102d347a0daSSam Leffler 103d347a0daSSam Leffler debug = 0; 104d347a0daSSam Leffler if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) 105d347a0daSSam Leffler errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE); 106d347a0daSSam Leffler 107d347a0daSSam Leffler /* set default fsoptions */ 108d347a0daSSam Leffler (void)memset(&fsoptions, 0, sizeof(fsoptions)); 109d347a0daSSam Leffler fsoptions.fd = -1; 110d347a0daSSam Leffler fsoptions.sectorsize = -1; 11101a0f853SOlivier Houchard 11201a0f853SOlivier Houchard if (fstype->prepare_options) 11301a0f853SOlivier Houchard fstype->prepare_options(&fsoptions); 114d347a0daSSam Leffler 115d347a0daSSam Leffler specfile = NULL; 116f490b9b3SEd Maste #ifdef CLOCK_REALTIME 117f490b9b3SEd Maste ch = clock_gettime(CLOCK_REALTIME, &start_time); 118f490b9b3SEd Maste #else 1197b03d164SEd Maste ch = gettimeofday(&start, NULL); 120d347a0daSSam Leffler start_time.tv_sec = start.tv_sec; 121d347a0daSSam Leffler start_time.tv_nsec = start.tv_usec * 1000; 122f490b9b3SEd Maste #endif 1237b03d164SEd Maste if (ch == -1) 1247b03d164SEd Maste err(1, "Unable to get system time"); 1257b03d164SEd Maste 1267b03d164SEd Maste 1277b03d164SEd Maste while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:T:xZ")) != -1) { 128d347a0daSSam Leffler switch (ch) { 129d347a0daSSam Leffler 130d347a0daSSam Leffler case 'B': 131d347a0daSSam Leffler if (strcmp(optarg, "be") == 0 || 132d347a0daSSam Leffler strcmp(optarg, "4321") == 0 || 133d347a0daSSam Leffler strcmp(optarg, "big") == 0) { 134d347a0daSSam Leffler #if BYTE_ORDER == LITTLE_ENDIAN 135d347a0daSSam Leffler fsoptions.needswap = 1; 136d347a0daSSam Leffler #endif 137d347a0daSSam Leffler } else if (strcmp(optarg, "le") == 0 || 138d347a0daSSam Leffler strcmp(optarg, "1234") == 0 || 139d347a0daSSam Leffler strcmp(optarg, "little") == 0) { 140d347a0daSSam Leffler #if BYTE_ORDER == BIG_ENDIAN 141d347a0daSSam Leffler fsoptions.needswap = 1; 142d347a0daSSam Leffler #endif 143d347a0daSSam Leffler } else { 144d347a0daSSam Leffler warnx("Invalid endian `%s'.", optarg); 145776c6824SEd Maste usage(fstype, &fsoptions); 146d347a0daSSam Leffler } 147d347a0daSSam Leffler break; 148d347a0daSSam Leffler 149d347a0daSSam Leffler case 'b': 150d347a0daSSam Leffler len = strlen(optarg) - 1; 151d347a0daSSam Leffler if (optarg[len] == '%') { 152d347a0daSSam Leffler optarg[len] = '\0'; 153d347a0daSSam Leffler fsoptions.freeblockpc = 154d347a0daSSam Leffler strsuftoll("free block percentage", 155d347a0daSSam Leffler optarg, 0, 99); 156d347a0daSSam Leffler } else { 157d347a0daSSam Leffler fsoptions.freeblocks = 158d347a0daSSam Leffler strsuftoll("free blocks", 159d347a0daSSam Leffler optarg, 0, LLONG_MAX); 160d347a0daSSam Leffler } 161d347a0daSSam Leffler break; 162d347a0daSSam Leffler 163b0d9addeSBrooks Davis case 'D': 164b0d9addeSBrooks Davis dupsok = 1; 165b0d9addeSBrooks Davis break; 166b0d9addeSBrooks Davis 167d347a0daSSam Leffler case 'd': 16801a0f853SOlivier Houchard debug = strtoll(optarg, NULL, 0); 169d347a0daSSam Leffler break; 170d347a0daSSam Leffler 171d347a0daSSam Leffler case 'f': 172d347a0daSSam Leffler len = strlen(optarg) - 1; 173d347a0daSSam Leffler if (optarg[len] == '%') { 174d347a0daSSam Leffler optarg[len] = '\0'; 175d347a0daSSam Leffler fsoptions.freefilepc = 176d347a0daSSam Leffler strsuftoll("free file percentage", 177d347a0daSSam Leffler optarg, 0, 99); 178d347a0daSSam Leffler } else { 179d347a0daSSam Leffler fsoptions.freefiles = 180d347a0daSSam Leffler strsuftoll("free files", 181d347a0daSSam Leffler optarg, 0, LLONG_MAX); 182d347a0daSSam Leffler } 183d347a0daSSam Leffler break; 184d347a0daSSam Leffler 185d347a0daSSam Leffler case 'F': 186d347a0daSSam Leffler specfile = optarg; 187d347a0daSSam Leffler break; 188d347a0daSSam Leffler 189d347a0daSSam Leffler case 'M': 190d347a0daSSam Leffler fsoptions.minsize = 191d347a0daSSam Leffler strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); 192d347a0daSSam Leffler break; 193d347a0daSSam Leffler 194d347a0daSSam Leffler case 'N': 195d347a0daSSam Leffler if (! setup_getid(optarg)) 196d347a0daSSam Leffler errx(1, 197d347a0daSSam Leffler "Unable to use user and group databases in `%s'", 198d347a0daSSam Leffler optarg); 199d347a0daSSam Leffler break; 200d347a0daSSam Leffler 201d347a0daSSam Leffler case 'm': 202d347a0daSSam Leffler fsoptions.maxsize = 203d347a0daSSam Leffler strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); 204d347a0daSSam Leffler break; 205d347a0daSSam Leffler 206d347a0daSSam Leffler case 'o': 207d347a0daSSam Leffler { 208d347a0daSSam Leffler char *p; 209d347a0daSSam Leffler 210d347a0daSSam Leffler while ((p = strsep(&optarg, ",")) != NULL) { 211d347a0daSSam Leffler if (*p == '\0') 212d347a0daSSam Leffler errx(1, "Empty option"); 213d347a0daSSam Leffler if (! fstype->parse_options(p, &fsoptions)) 214776c6824SEd Maste usage(fstype, &fsoptions); 215d347a0daSSam Leffler } 216d347a0daSSam Leffler break; 217d347a0daSSam Leffler } 21899c841b1SHiroki Sato case 'p': 2199ab90e8aSGlen Barber /* Deprecated in favor of 'Z' */ 22099c841b1SHiroki Sato fsoptions.sparse = 1; 22199c841b1SHiroki Sato break; 222d347a0daSSam Leffler 22378d2334fSEnji Cooper case 'R': 224a08b904cSAdrian Chadd /* Round image size up to specified block size */ 225a08b904cSAdrian Chadd fsoptions.roundup = 22678d2334fSEnji Cooper strsuftoll("roundup-size", optarg, 0, LLONG_MAX); 227a08b904cSAdrian Chadd break; 228a08b904cSAdrian Chadd 229d347a0daSSam Leffler case 's': 230d347a0daSSam Leffler fsoptions.minsize = fsoptions.maxsize = 231d347a0daSSam Leffler strsuftoll("size", optarg, 1LL, LLONG_MAX); 232d347a0daSSam Leffler break; 233d347a0daSSam Leffler 234d347a0daSSam Leffler case 'S': 235d347a0daSSam Leffler fsoptions.sectorsize = 236d347a0daSSam Leffler (int)strsuftoll("sector size", optarg, 237d347a0daSSam Leffler 1LL, INT_MAX); 238d347a0daSSam Leffler break; 239d347a0daSSam Leffler 240d347a0daSSam Leffler case 't': 24101a0f853SOlivier Houchard /* Check current one and cleanup if necessary. */ 24201a0f853SOlivier Houchard if (fstype->cleanup_options) 24301a0f853SOlivier Houchard fstype->cleanup_options(&fsoptions); 24401a0f853SOlivier Houchard fsoptions.fs_specific = NULL; 245d347a0daSSam Leffler if ((fstype = get_fstype(optarg)) == NULL) 246d347a0daSSam Leffler errx(1, "Unknown fs type `%s'.", optarg); 24701a0f853SOlivier Houchard fstype->prepare_options(&fsoptions); 248d347a0daSSam Leffler break; 249d347a0daSSam Leffler 2507b03d164SEd Maste case 'T': 2517b03d164SEd Maste if (get_tstamp(optarg, &stampst) == -1) 2527b03d164SEd Maste errx(1, "Cannot get timestamp from `%s'", 2537b03d164SEd Maste optarg); 2547b03d164SEd Maste break; 2557b03d164SEd Maste 256d347a0daSSam Leffler case 'x': 257d347a0daSSam Leffler fsoptions.onlyspec = 1; 258d347a0daSSam Leffler break; 259d347a0daSSam Leffler 2609ab90e8aSGlen Barber case 'Z': 2619ab90e8aSGlen Barber /* Superscedes 'p' for compatibility with NetBSD makefs(8) */ 2629ab90e8aSGlen Barber fsoptions.sparse = 1; 2639ab90e8aSGlen Barber break; 2649ab90e8aSGlen Barber 265d347a0daSSam Leffler case '?': 266d347a0daSSam Leffler default: 267776c6824SEd Maste usage(fstype, &fsoptions); 268d347a0daSSam Leffler /* NOTREACHED */ 269d347a0daSSam Leffler 270d347a0daSSam Leffler } 271d347a0daSSam Leffler } 272d347a0daSSam Leffler if (debug) { 273d347a0daSSam Leffler printf("debug mask: 0x%08x\n", debug); 274d347a0daSSam Leffler printf("start time: %ld.%ld, %s", 275d347a0daSSam Leffler (long)start_time.tv_sec, (long)start_time.tv_nsec, 276d347a0daSSam Leffler ctime(&start_time.tv_sec)); 277d347a0daSSam Leffler } 278d347a0daSSam Leffler argc -= optind; 279d347a0daSSam Leffler argv += optind; 280d347a0daSSam Leffler 281688aaa09SJung-uk Kim if (argc < 2) 282776c6824SEd Maste usage(fstype, &fsoptions); 283d347a0daSSam Leffler 284d347a0daSSam Leffler /* -x must be accompanied by -F */ 285d347a0daSSam Leffler if (fsoptions.onlyspec != 0 && specfile == NULL) 286d347a0daSSam Leffler errx(1, "-x requires -F mtree-specfile."); 287d347a0daSSam Leffler 288484b5c25SMarcel Moolenaar /* Accept '-' as meaning "read from standard input". */ 289484b5c25SMarcel Moolenaar if (strcmp(argv[1], "-") == 0) 290484b5c25SMarcel Moolenaar sb.st_mode = S_IFREG; 291484b5c25SMarcel Moolenaar else { 292484b5c25SMarcel Moolenaar if (stat(argv[1], &sb) == -1) 293484b5c25SMarcel Moolenaar err(1, "Can't stat `%s'", argv[1]); 294484b5c25SMarcel Moolenaar } 295484b5c25SMarcel Moolenaar 296484b5c25SMarcel Moolenaar switch (sb.st_mode & S_IFMT) { 297484b5c25SMarcel Moolenaar case S_IFDIR: /* walk the tree */ 298484b5c25SMarcel Moolenaar subtree = argv[1]; 299d347a0daSSam Leffler TIMER_START(start); 300688aaa09SJung-uk Kim root = walk_dir(subtree, ".", NULL, NULL); 301d347a0daSSam Leffler TIMER_RESULTS(start, "walk_dir"); 302484b5c25SMarcel Moolenaar break; 303484b5c25SMarcel Moolenaar case S_IFREG: /* read the manifest file */ 304484b5c25SMarcel Moolenaar subtree = "."; 305484b5c25SMarcel Moolenaar TIMER_START(start); 306484b5c25SMarcel Moolenaar root = read_mtree(argv[1], NULL); 307484b5c25SMarcel Moolenaar TIMER_RESULTS(start, "manifest"); 308484b5c25SMarcel Moolenaar break; 309484b5c25SMarcel Moolenaar default: 310484b5c25SMarcel Moolenaar errx(1, "%s: not a file or directory", argv[1]); 311484b5c25SMarcel Moolenaar /* NOTREACHED */ 312484b5c25SMarcel Moolenaar } 313d347a0daSSam Leffler 314688aaa09SJung-uk Kim /* append extra directory */ 315688aaa09SJung-uk Kim for (i = 2; i < argc; i++) { 316688aaa09SJung-uk Kim if (stat(argv[i], &sb) == -1) 317688aaa09SJung-uk Kim err(1, "Can't stat `%s'", argv[i]); 318688aaa09SJung-uk Kim if (!S_ISDIR(sb.st_mode)) 319688aaa09SJung-uk Kim errx(1, "%s: not a directory", argv[i]); 320688aaa09SJung-uk Kim TIMER_START(start); 321688aaa09SJung-uk Kim root = walk_dir(argv[i], ".", NULL, root); 322688aaa09SJung-uk Kim TIMER_RESULTS(start, "walk_dir2"); 323688aaa09SJung-uk Kim } 324688aaa09SJung-uk Kim 325d347a0daSSam Leffler if (specfile) { /* apply a specfile */ 326d347a0daSSam Leffler TIMER_START(start); 327484b5c25SMarcel Moolenaar apply_specfile(specfile, subtree, root, fsoptions.onlyspec); 328d347a0daSSam Leffler TIMER_RESULTS(start, "apply_specfile"); 329d347a0daSSam Leffler } 330d347a0daSSam Leffler 331d347a0daSSam Leffler if (debug & DEBUG_DUMP_FSNODES) { 332484b5c25SMarcel Moolenaar printf("\nparent: %s\n", subtree); 333688aaa09SJung-uk Kim dump_fsnodes(root); 334d347a0daSSam Leffler putchar('\n'); 335d347a0daSSam Leffler } 336d347a0daSSam Leffler 337d347a0daSSam Leffler /* build the file system */ 338d347a0daSSam Leffler TIMER_START(start); 339484b5c25SMarcel Moolenaar fstype->make_fs(argv[0], subtree, root, &fsoptions); 340d347a0daSSam Leffler TIMER_RESULTS(start, "make_fs"); 341d347a0daSSam Leffler 34201a0f853SOlivier Houchard free_fsnodes(root); 34301a0f853SOlivier Houchard 344d347a0daSSam Leffler exit(0); 345d347a0daSSam Leffler /* NOTREACHED */ 346d347a0daSSam Leffler } 347d347a0daSSam Leffler 348776c6824SEd Maste int 349776c6824SEd Maste set_option(const option_t *options, const char *option, char *buf, size_t len) 350776c6824SEd Maste { 351776c6824SEd Maste char *var, *val; 352776c6824SEd Maste int retval; 353776c6824SEd Maste 354776c6824SEd Maste assert(option != NULL); 355776c6824SEd Maste 3565f5598b1SEd Maste var = estrdup(option); 357776c6824SEd Maste for (val = var; *val; val++) 358776c6824SEd Maste if (*val == '=') { 359776c6824SEd Maste *val++ = '\0'; 360776c6824SEd Maste break; 361776c6824SEd Maste } 362776c6824SEd Maste retval = set_option_var(options, var, val, buf, len); 363776c6824SEd Maste free(var); 364776c6824SEd Maste return retval; 365776c6824SEd Maste } 366d347a0daSSam Leffler 367d347a0daSSam Leffler int 368776c6824SEd Maste set_option_var(const option_t *options, const char *var, const char *val, 369776c6824SEd Maste char *buf, size_t len) 370d347a0daSSam Leffler { 371776c6824SEd Maste char *s; 372776c6824SEd Maste size_t i; 373776c6824SEd Maste 374776c6824SEd Maste #define NUM(type) \ 375776c6824SEd Maste if (!*val) { \ 376776c6824SEd Maste *(type *)options[i].value = 1; \ 377776c6824SEd Maste break; \ 378776c6824SEd Maste } \ 379776c6824SEd Maste *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ 380776c6824SEd Maste options[i].minimum, options[i].maximum); break 381d347a0daSSam Leffler 382d347a0daSSam Leffler for (i = 0; options[i].name != NULL; i++) { 383776c6824SEd Maste if (var[1] == '\0') { 384776c6824SEd Maste if (options[i].letter != var[0]) 385d347a0daSSam Leffler continue; 386776c6824SEd Maste } else if (strcmp(options[i].name, var) != 0) 387776c6824SEd Maste continue; 388776c6824SEd Maste switch (options[i].type) { 389776c6824SEd Maste case OPT_BOOL: 390776c6824SEd Maste *(bool *)options[i].value = 1; 391776c6824SEd Maste break; 392776c6824SEd Maste case OPT_STRARRAY: 393776c6824SEd Maste strlcpy((void *)options[i].value, val, (size_t) 394776c6824SEd Maste options[i].maximum); 395776c6824SEd Maste break; 396776c6824SEd Maste case OPT_STRPTR: 3975f5598b1SEd Maste s = estrdup(val); 398776c6824SEd Maste *(char **)options[i].value = s; 399776c6824SEd Maste break; 400776c6824SEd Maste case OPT_STRBUF: 401776c6824SEd Maste if (buf == NULL) 402776c6824SEd Maste abort(); 403776c6824SEd Maste strlcpy(buf, val, len); 404776c6824SEd Maste break; 405776c6824SEd Maste case OPT_INT64: 406776c6824SEd Maste NUM(uint64_t); 407776c6824SEd Maste case OPT_INT32: 408776c6824SEd Maste NUM(uint32_t); 409776c6824SEd Maste case OPT_INT16: 410776c6824SEd Maste NUM(uint16_t); 411776c6824SEd Maste case OPT_INT8: 412776c6824SEd Maste NUM(uint8_t); 413776c6824SEd Maste default: 414776c6824SEd Maste warnx("Unknown type %d in option %s", options[i].type, 415776c6824SEd Maste val); 416776c6824SEd Maste return 0; 417776c6824SEd Maste } 418776c6824SEd Maste return i; 419d347a0daSSam Leffler } 420d347a0daSSam Leffler warnx("Unknown option `%s'", var); 421776c6824SEd Maste return -1; 422d347a0daSSam Leffler } 423d347a0daSSam Leffler 424d347a0daSSam Leffler 425d347a0daSSam Leffler static fstype_t * 426d347a0daSSam Leffler get_fstype(const char *type) 427d347a0daSSam Leffler { 428d347a0daSSam Leffler int i; 429d347a0daSSam Leffler 430d347a0daSSam Leffler for (i = 0; fstypes[i].type != NULL; i++) 431d347a0daSSam Leffler if (strcmp(fstypes[i].type, type) == 0) 432d347a0daSSam Leffler return (&fstypes[i]); 433d347a0daSSam Leffler return (NULL); 434d347a0daSSam Leffler } 435d347a0daSSam Leffler 436776c6824SEd Maste option_t * 437776c6824SEd Maste copy_opts(const option_t *o) 438776c6824SEd Maste { 439776c6824SEd Maste size_t i; 440776c6824SEd Maste 441776c6824SEd Maste for (i = 0; o[i].name; i++) 442776c6824SEd Maste continue; 443776c6824SEd Maste i++; 4445f5598b1SEd Maste return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); 445776c6824SEd Maste } 446776c6824SEd Maste 4477b03d164SEd Maste static int 4487b03d164SEd Maste get_tstamp(const char *b, struct stat *st) 4497b03d164SEd Maste { 4507b03d164SEd Maste time_t when; 4517b03d164SEd Maste char *eb; 4527b03d164SEd Maste long long l; 4537b03d164SEd Maste 4547b03d164SEd Maste if (stat(b, st) != -1) 4557b03d164SEd Maste return 0; 4567b03d164SEd Maste 4577b03d164SEd Maste { 4587b03d164SEd Maste errno = 0; 4597b03d164SEd Maste l = strtoll(b, &eb, 0); 4607b03d164SEd Maste if (b == eb || *eb || errno) 4617b03d164SEd Maste return -1; 4627b03d164SEd Maste when = (time_t)l; 4637b03d164SEd Maste } 4647b03d164SEd Maste 4657b03d164SEd Maste st->st_ino = 1; 4667b03d164SEd Maste #ifdef HAVE_STRUCT_STAT_BIRTHTIME 4677b03d164SEd Maste st->st_birthtime = 4687b03d164SEd Maste #endif 4697b03d164SEd Maste st->st_mtime = st->st_ctime = st->st_atime = when; 4707b03d164SEd Maste return 0; 4717b03d164SEd Maste } 4727b03d164SEd Maste 473d347a0daSSam Leffler static void 474776c6824SEd Maste usage(fstype_t *fstype, fsinfo_t *fsoptions) 475d347a0daSSam Leffler { 476d347a0daSSam Leffler const char *prog; 477d347a0daSSam Leffler 478d347a0daSSam Leffler prog = getprogname(); 479d347a0daSSam Leffler fprintf(stderr, 480776c6824SEd Maste "Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" 481298d081cSEd Maste "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" 482298d081cSEd Maste "\t[-N userdb-dir] [-o fs-options] [-R roundup-size] [-S sector-size]\n" 483298d081cSEd Maste "\t[-s image-size] [-T <timestamp/file>] [-t fs-type]\n" 4847b03d164SEd Maste "\timage-file directory | manifest [extra-directory ...]\n", 485d347a0daSSam Leffler prog); 486776c6824SEd Maste 487776c6824SEd Maste if (fstype) { 488776c6824SEd Maste size_t i; 489776c6824SEd Maste option_t *o = fsoptions->fs_options; 490776c6824SEd Maste 491776c6824SEd Maste fprintf(stderr, "\n%s specific options:\n", fstype->type); 492776c6824SEd Maste for (i = 0; o[i].name != NULL; i++) 493776c6824SEd Maste fprintf(stderr, "\t%c%c%20.20s\t%s\n", 494776c6824SEd Maste o[i].letter ? o[i].letter : ' ', 495776c6824SEd Maste o[i].letter ? ',' : ' ', 496776c6824SEd Maste o[i].name, o[i].desc); 497776c6824SEd Maste } 498d347a0daSSam Leffler exit(1); 499d347a0daSSam Leffler } 500