101a0f853SOlivier Houchard /* $NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $ */ 2d347a0daSSam Leffler 31de7b4b8SPedro F. Giffuni /*- 41de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 51de7b4b8SPedro F. Giffuni * 6d347a0daSSam Leffler * Copyright (c) 2001-2003 Wasabi Systems, Inc. 7d347a0daSSam Leffler * All rights reserved. 8d347a0daSSam Leffler * 9d347a0daSSam Leffler * Written by Luke Mewburn for Wasabi Systems, Inc. 10d347a0daSSam Leffler * 11d347a0daSSam Leffler * Redistribution and use in source and binary forms, with or without 12d347a0daSSam Leffler * modification, are permitted provided that the following conditions 13d347a0daSSam Leffler * are met: 14d347a0daSSam Leffler * 1. Redistributions of source code must retain the above copyright 15d347a0daSSam Leffler * notice, this list of conditions and the following disclaimer. 16d347a0daSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 17d347a0daSSam Leffler * notice, this list of conditions and the following disclaimer in the 18d347a0daSSam Leffler * documentation and/or other materials provided with the distribution. 19d347a0daSSam Leffler * 3. All advertising materials mentioning features or use of this software 20d347a0daSSam Leffler * must display the following acknowledgement: 21d347a0daSSam Leffler * This product includes software developed for the NetBSD Project by 22d347a0daSSam Leffler * Wasabi Systems, Inc. 23d347a0daSSam Leffler * 4. The name of Wasabi Systems, Inc. may not be used to endorse 24d347a0daSSam Leffler * or promote products derived from this software without specific prior 25d347a0daSSam Leffler * written permission. 26d347a0daSSam Leffler * 27d347a0daSSam Leffler * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 28d347a0daSSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29d347a0daSSam Leffler * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30d347a0daSSam Leffler * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 31d347a0daSSam Leffler * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32d347a0daSSam Leffler * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33d347a0daSSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34d347a0daSSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35d347a0daSSam Leffler * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36d347a0daSSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37d347a0daSSam Leffler * POSSIBILITY OF SUCH DAMAGE. 38d347a0daSSam Leffler */ 39d347a0daSSam Leffler 40d347a0daSSam Leffler #include <sys/cdefs.h> 41d347a0daSSam Leffler __FBSDID("$FreeBSD$"); 42d347a0daSSam Leffler 43484b5c25SMarcel Moolenaar #include <sys/types.h> 44484b5c25SMarcel Moolenaar #include <sys/stat.h> 45d347a0daSSam Leffler #include <assert.h> 46d347a0daSSam Leffler #include <ctype.h> 47d347a0daSSam Leffler #include <errno.h> 48d347a0daSSam Leffler #include <limits.h> 49d347a0daSSam Leffler #include <stdio.h> 50d347a0daSSam Leffler #include <stdlib.h> 51d347a0daSSam Leffler #include <string.h> 527649cb00SKirk McKusick #include <time.h> 53d347a0daSSam Leffler #include <unistd.h> 54776c6824SEd Maste #include <stdbool.h> 555f5598b1SEd Maste #include <util.h> 56d347a0daSSam Leffler 57d347a0daSSam Leffler #include "makefs.h" 58d347a0daSSam Leffler #include "mtree.h" 59d347a0daSSam Leffler 60d347a0daSSam Leffler /* 61d347a0daSSam Leffler * list of supported file systems and dispatch functions 62d347a0daSSam Leffler */ 63d347a0daSSam Leffler typedef struct { 64d347a0daSSam Leffler const char *type; 6501a0f853SOlivier Houchard void (*prepare_options)(fsinfo_t *); 66d347a0daSSam Leffler int (*parse_options)(const char *, fsinfo_t *); 6701a0f853SOlivier Houchard void (*cleanup_options)(fsinfo_t *); 68d347a0daSSam Leffler void (*make_fs)(const char *, const char *, fsnode *, 69d347a0daSSam Leffler fsinfo_t *); 70d347a0daSSam Leffler } fstype_t; 71d347a0daSSam Leffler 72d347a0daSSam Leffler static fstype_t fstypes[] = { 73203b6f69SEd Maste #define ENTRY(name) { \ 74203b6f69SEd Maste # name, name ## _prep_opts, name ## _parse_opts, \ 75203b6f69SEd Maste name ## _cleanup_opts, name ## _makefs \ 76203b6f69SEd Maste } 77203b6f69SEd Maste ENTRY(cd9660), 78*98dc8da5SEd Maste ENTRY(ffs), 79*98dc8da5SEd Maste ENTRY(msdos), 8001a0f853SOlivier Houchard { .type = NULL }, 81d347a0daSSam Leffler }; 82d347a0daSSam Leffler 83d347a0daSSam Leffler u_int debug; 84b0d9addeSBrooks Davis int dupsok; 85d347a0daSSam Leffler struct timespec start_time; 867b03d164SEd Maste struct stat stampst; 87d347a0daSSam Leffler 88d347a0daSSam Leffler static fstype_t *get_fstype(const char *); 897b03d164SEd Maste static int get_tstamp(const char *, struct stat *); 90776c6824SEd Maste static void usage(fstype_t *, fsinfo_t *); 91d347a0daSSam Leffler 92d347a0daSSam Leffler int 93d347a0daSSam Leffler main(int argc, char *argv[]) 94d347a0daSSam Leffler { 95484b5c25SMarcel Moolenaar struct stat sb; 96d347a0daSSam Leffler struct timeval start; 97d347a0daSSam Leffler fstype_t *fstype; 98d347a0daSSam Leffler fsinfo_t fsoptions; 99d347a0daSSam Leffler fsnode *root; 100688aaa09SJung-uk Kim int ch, i, len; 1019e96f90bSEd Maste const char *subtree; 1029e96f90bSEd Maste const char *specfile; 103d347a0daSSam Leffler 104d347a0daSSam Leffler setprogname(argv[0]); 105d347a0daSSam Leffler 106d347a0daSSam Leffler debug = 0; 107d347a0daSSam Leffler if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) 108d347a0daSSam Leffler errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE); 109d347a0daSSam Leffler 110d347a0daSSam Leffler /* set default fsoptions */ 111d347a0daSSam Leffler (void)memset(&fsoptions, 0, sizeof(fsoptions)); 112d347a0daSSam Leffler fsoptions.fd = -1; 113d347a0daSSam Leffler fsoptions.sectorsize = -1; 11401a0f853SOlivier Houchard 11501a0f853SOlivier Houchard if (fstype->prepare_options) 11601a0f853SOlivier Houchard fstype->prepare_options(&fsoptions); 117d347a0daSSam Leffler 118d347a0daSSam Leffler specfile = NULL; 119f490b9b3SEd Maste #ifdef CLOCK_REALTIME 120f490b9b3SEd Maste ch = clock_gettime(CLOCK_REALTIME, &start_time); 121f490b9b3SEd Maste #else 1227b03d164SEd Maste ch = gettimeofday(&start, NULL); 123d347a0daSSam Leffler start_time.tv_sec = start.tv_sec; 124d347a0daSSam Leffler start_time.tv_nsec = start.tv_usec * 1000; 125f490b9b3SEd Maste #endif 1267b03d164SEd Maste if (ch == -1) 1277b03d164SEd Maste err(1, "Unable to get system time"); 1287b03d164SEd Maste 1297b03d164SEd Maste 130b79f050aSEd Maste while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:O:o:pR:s:S:t:T:xZ")) != -1) { 131d347a0daSSam Leffler switch (ch) { 132d347a0daSSam Leffler 133d347a0daSSam Leffler case 'B': 134d347a0daSSam Leffler if (strcmp(optarg, "be") == 0 || 135d347a0daSSam Leffler strcmp(optarg, "4321") == 0 || 136d347a0daSSam Leffler strcmp(optarg, "big") == 0) { 137d347a0daSSam Leffler #if BYTE_ORDER == LITTLE_ENDIAN 138d347a0daSSam Leffler fsoptions.needswap = 1; 139d347a0daSSam Leffler #endif 140d347a0daSSam Leffler } else if (strcmp(optarg, "le") == 0 || 141d347a0daSSam Leffler strcmp(optarg, "1234") == 0 || 142d347a0daSSam Leffler strcmp(optarg, "little") == 0) { 143d347a0daSSam Leffler #if BYTE_ORDER == BIG_ENDIAN 144d347a0daSSam Leffler fsoptions.needswap = 1; 145d347a0daSSam Leffler #endif 146d347a0daSSam Leffler } else { 147d347a0daSSam Leffler warnx("Invalid endian `%s'.", optarg); 148776c6824SEd Maste usage(fstype, &fsoptions); 149d347a0daSSam Leffler } 150d347a0daSSam Leffler break; 151d347a0daSSam Leffler 152d347a0daSSam Leffler case 'b': 153d347a0daSSam Leffler len = strlen(optarg) - 1; 154d347a0daSSam Leffler if (optarg[len] == '%') { 155d347a0daSSam Leffler optarg[len] = '\0'; 156d347a0daSSam Leffler fsoptions.freeblockpc = 157d347a0daSSam Leffler strsuftoll("free block percentage", 158d347a0daSSam Leffler optarg, 0, 99); 159d347a0daSSam Leffler } else { 160d347a0daSSam Leffler fsoptions.freeblocks = 161d347a0daSSam Leffler strsuftoll("free blocks", 162d347a0daSSam Leffler optarg, 0, LLONG_MAX); 163d347a0daSSam Leffler } 164d347a0daSSam Leffler break; 165d347a0daSSam Leffler 166b0d9addeSBrooks Davis case 'D': 167b0d9addeSBrooks Davis dupsok = 1; 168b0d9addeSBrooks Davis break; 169b0d9addeSBrooks Davis 170d347a0daSSam Leffler case 'd': 17101a0f853SOlivier Houchard debug = strtoll(optarg, NULL, 0); 172d347a0daSSam Leffler break; 173d347a0daSSam Leffler 174d347a0daSSam Leffler case 'f': 175d347a0daSSam Leffler len = strlen(optarg) - 1; 176d347a0daSSam Leffler if (optarg[len] == '%') { 177d347a0daSSam Leffler optarg[len] = '\0'; 178d347a0daSSam Leffler fsoptions.freefilepc = 179d347a0daSSam Leffler strsuftoll("free file percentage", 180d347a0daSSam Leffler optarg, 0, 99); 181d347a0daSSam Leffler } else { 182d347a0daSSam Leffler fsoptions.freefiles = 183d347a0daSSam Leffler strsuftoll("free files", 184d347a0daSSam Leffler optarg, 0, LLONG_MAX); 185d347a0daSSam Leffler } 186d347a0daSSam Leffler break; 187d347a0daSSam Leffler 188d347a0daSSam Leffler case 'F': 189d347a0daSSam Leffler specfile = optarg; 190d347a0daSSam Leffler break; 191d347a0daSSam Leffler 192d347a0daSSam Leffler case 'M': 193d347a0daSSam Leffler fsoptions.minsize = 194d347a0daSSam Leffler strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); 195d347a0daSSam Leffler break; 196d347a0daSSam Leffler 197d347a0daSSam Leffler case 'N': 198d347a0daSSam Leffler if (! setup_getid(optarg)) 199d347a0daSSam Leffler errx(1, 200d347a0daSSam Leffler "Unable to use user and group databases in `%s'", 201d347a0daSSam Leffler optarg); 202d347a0daSSam Leffler break; 203d347a0daSSam Leffler 204d347a0daSSam Leffler case 'm': 205d347a0daSSam Leffler fsoptions.maxsize = 206d347a0daSSam Leffler strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); 207d347a0daSSam Leffler break; 208d347a0daSSam Leffler 209b79f050aSEd Maste case 'O': 210b79f050aSEd Maste fsoptions.offset = 211b79f050aSEd Maste strsuftoll("offset", optarg, 0LL, LLONG_MAX); 212b79f050aSEd Maste break; 213b79f050aSEd Maste 214d347a0daSSam Leffler case 'o': 215d347a0daSSam Leffler { 216d347a0daSSam Leffler char *p; 217d347a0daSSam Leffler 218d347a0daSSam Leffler while ((p = strsep(&optarg, ",")) != NULL) { 219d347a0daSSam Leffler if (*p == '\0') 220d347a0daSSam Leffler errx(1, "Empty option"); 221d347a0daSSam Leffler if (! fstype->parse_options(p, &fsoptions)) 222776c6824SEd Maste usage(fstype, &fsoptions); 223d347a0daSSam Leffler } 224d347a0daSSam Leffler break; 225d347a0daSSam Leffler } 22699c841b1SHiroki Sato case 'p': 2279ab90e8aSGlen Barber /* Deprecated in favor of 'Z' */ 22899c841b1SHiroki Sato fsoptions.sparse = 1; 22999c841b1SHiroki Sato break; 230d347a0daSSam Leffler 23178d2334fSEnji Cooper case 'R': 232a08b904cSAdrian Chadd /* Round image size up to specified block size */ 233a08b904cSAdrian Chadd fsoptions.roundup = 23478d2334fSEnji Cooper strsuftoll("roundup-size", optarg, 0, LLONG_MAX); 235a08b904cSAdrian Chadd break; 236a08b904cSAdrian Chadd 237d347a0daSSam Leffler case 's': 238d347a0daSSam Leffler fsoptions.minsize = fsoptions.maxsize = 239d347a0daSSam Leffler strsuftoll("size", optarg, 1LL, LLONG_MAX); 240d347a0daSSam Leffler break; 241d347a0daSSam Leffler 242d347a0daSSam Leffler case 'S': 243d347a0daSSam Leffler fsoptions.sectorsize = 244d347a0daSSam Leffler (int)strsuftoll("sector size", optarg, 245d347a0daSSam Leffler 1LL, INT_MAX); 246d347a0daSSam Leffler break; 247d347a0daSSam Leffler 248d347a0daSSam Leffler case 't': 24901a0f853SOlivier Houchard /* Check current one and cleanup if necessary. */ 25001a0f853SOlivier Houchard if (fstype->cleanup_options) 25101a0f853SOlivier Houchard fstype->cleanup_options(&fsoptions); 25201a0f853SOlivier Houchard fsoptions.fs_specific = NULL; 253d347a0daSSam Leffler if ((fstype = get_fstype(optarg)) == NULL) 254d347a0daSSam Leffler errx(1, "Unknown fs type `%s'.", optarg); 25501a0f853SOlivier Houchard fstype->prepare_options(&fsoptions); 256d347a0daSSam Leffler break; 257d347a0daSSam Leffler 2587b03d164SEd Maste case 'T': 2597b03d164SEd Maste if (get_tstamp(optarg, &stampst) == -1) 2607b03d164SEd Maste errx(1, "Cannot get timestamp from `%s'", 2617b03d164SEd Maste optarg); 2627b03d164SEd Maste break; 2637b03d164SEd Maste 264d347a0daSSam Leffler case 'x': 265d347a0daSSam Leffler fsoptions.onlyspec = 1; 266d347a0daSSam Leffler break; 267d347a0daSSam Leffler 2689ab90e8aSGlen Barber case 'Z': 2699ab90e8aSGlen Barber /* Superscedes 'p' for compatibility with NetBSD makefs(8) */ 2709ab90e8aSGlen Barber fsoptions.sparse = 1; 2719ab90e8aSGlen Barber break; 2729ab90e8aSGlen Barber 273d347a0daSSam Leffler case '?': 274d347a0daSSam Leffler default: 275776c6824SEd Maste usage(fstype, &fsoptions); 276d347a0daSSam Leffler /* NOTREACHED */ 277d347a0daSSam Leffler 278d347a0daSSam Leffler } 279d347a0daSSam Leffler } 280d347a0daSSam Leffler if (debug) { 281d347a0daSSam Leffler printf("debug mask: 0x%08x\n", debug); 282d347a0daSSam Leffler printf("start time: %ld.%ld, %s", 283d347a0daSSam Leffler (long)start_time.tv_sec, (long)start_time.tv_nsec, 284d347a0daSSam Leffler ctime(&start_time.tv_sec)); 285d347a0daSSam Leffler } 286d347a0daSSam Leffler argc -= optind; 287d347a0daSSam Leffler argv += optind; 288d347a0daSSam Leffler 289688aaa09SJung-uk Kim if (argc < 2) 290776c6824SEd Maste usage(fstype, &fsoptions); 291d347a0daSSam Leffler 292d347a0daSSam Leffler /* -x must be accompanied by -F */ 293d347a0daSSam Leffler if (fsoptions.onlyspec != 0 && specfile == NULL) 294d347a0daSSam Leffler errx(1, "-x requires -F mtree-specfile."); 295d347a0daSSam Leffler 296484b5c25SMarcel Moolenaar /* Accept '-' as meaning "read from standard input". */ 297484b5c25SMarcel Moolenaar if (strcmp(argv[1], "-") == 0) 298484b5c25SMarcel Moolenaar sb.st_mode = S_IFREG; 299484b5c25SMarcel Moolenaar else { 300484b5c25SMarcel Moolenaar if (stat(argv[1], &sb) == -1) 301484b5c25SMarcel Moolenaar err(1, "Can't stat `%s'", argv[1]); 302484b5c25SMarcel Moolenaar } 303484b5c25SMarcel Moolenaar 304484b5c25SMarcel Moolenaar switch (sb.st_mode & S_IFMT) { 305484b5c25SMarcel Moolenaar case S_IFDIR: /* walk the tree */ 306484b5c25SMarcel Moolenaar subtree = argv[1]; 307d347a0daSSam Leffler TIMER_START(start); 308688aaa09SJung-uk Kim root = walk_dir(subtree, ".", NULL, NULL); 309d347a0daSSam Leffler TIMER_RESULTS(start, "walk_dir"); 310484b5c25SMarcel Moolenaar break; 311484b5c25SMarcel Moolenaar case S_IFREG: /* read the manifest file */ 312484b5c25SMarcel Moolenaar subtree = "."; 313484b5c25SMarcel Moolenaar TIMER_START(start); 314484b5c25SMarcel Moolenaar root = read_mtree(argv[1], NULL); 315484b5c25SMarcel Moolenaar TIMER_RESULTS(start, "manifest"); 316484b5c25SMarcel Moolenaar break; 317484b5c25SMarcel Moolenaar default: 318484b5c25SMarcel Moolenaar errx(1, "%s: not a file or directory", argv[1]); 319484b5c25SMarcel Moolenaar /* NOTREACHED */ 320484b5c25SMarcel Moolenaar } 321d347a0daSSam Leffler 322688aaa09SJung-uk Kim /* append extra directory */ 323688aaa09SJung-uk Kim for (i = 2; i < argc; i++) { 324688aaa09SJung-uk Kim if (stat(argv[i], &sb) == -1) 325688aaa09SJung-uk Kim err(1, "Can't stat `%s'", argv[i]); 326688aaa09SJung-uk Kim if (!S_ISDIR(sb.st_mode)) 327688aaa09SJung-uk Kim errx(1, "%s: not a directory", argv[i]); 328688aaa09SJung-uk Kim TIMER_START(start); 329688aaa09SJung-uk Kim root = walk_dir(argv[i], ".", NULL, root); 330688aaa09SJung-uk Kim TIMER_RESULTS(start, "walk_dir2"); 331688aaa09SJung-uk Kim } 332688aaa09SJung-uk Kim 333d347a0daSSam Leffler if (specfile) { /* apply a specfile */ 334d347a0daSSam Leffler TIMER_START(start); 335484b5c25SMarcel Moolenaar apply_specfile(specfile, subtree, root, fsoptions.onlyspec); 336d347a0daSSam Leffler TIMER_RESULTS(start, "apply_specfile"); 337d347a0daSSam Leffler } 338d347a0daSSam Leffler 339d347a0daSSam Leffler if (debug & DEBUG_DUMP_FSNODES) { 340484b5c25SMarcel Moolenaar printf("\nparent: %s\n", subtree); 341688aaa09SJung-uk Kim dump_fsnodes(root); 342d347a0daSSam Leffler putchar('\n'); 343d347a0daSSam Leffler } 344d347a0daSSam Leffler 345d347a0daSSam Leffler /* build the file system */ 346d347a0daSSam Leffler TIMER_START(start); 347484b5c25SMarcel Moolenaar fstype->make_fs(argv[0], subtree, root, &fsoptions); 348d347a0daSSam Leffler TIMER_RESULTS(start, "make_fs"); 349d347a0daSSam Leffler 35001a0f853SOlivier Houchard free_fsnodes(root); 35101a0f853SOlivier Houchard 352d347a0daSSam Leffler exit(0); 353d347a0daSSam Leffler /* NOTREACHED */ 354d347a0daSSam Leffler } 355d347a0daSSam Leffler 356776c6824SEd Maste int 357776c6824SEd Maste set_option(const option_t *options, const char *option, char *buf, size_t len) 358776c6824SEd Maste { 359776c6824SEd Maste char *var, *val; 360776c6824SEd Maste int retval; 361776c6824SEd Maste 362776c6824SEd Maste assert(option != NULL); 363776c6824SEd Maste 3645f5598b1SEd Maste var = estrdup(option); 365776c6824SEd Maste for (val = var; *val; val++) 366776c6824SEd Maste if (*val == '=') { 367776c6824SEd Maste *val++ = '\0'; 368776c6824SEd Maste break; 369776c6824SEd Maste } 370776c6824SEd Maste retval = set_option_var(options, var, val, buf, len); 371776c6824SEd Maste free(var); 372776c6824SEd Maste return retval; 373776c6824SEd Maste } 374d347a0daSSam Leffler 375d347a0daSSam Leffler int 376776c6824SEd Maste set_option_var(const option_t *options, const char *var, const char *val, 377776c6824SEd Maste char *buf, size_t len) 378d347a0daSSam Leffler { 379776c6824SEd Maste char *s; 380776c6824SEd Maste size_t i; 381776c6824SEd Maste 382776c6824SEd Maste #define NUM(type) \ 383776c6824SEd Maste if (!*val) { \ 384776c6824SEd Maste *(type *)options[i].value = 1; \ 385776c6824SEd Maste break; \ 386776c6824SEd Maste } \ 387776c6824SEd Maste *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ 388776c6824SEd Maste options[i].minimum, options[i].maximum); break 389d347a0daSSam Leffler 390d347a0daSSam Leffler for (i = 0; options[i].name != NULL; i++) { 391776c6824SEd Maste if (var[1] == '\0') { 392776c6824SEd Maste if (options[i].letter != var[0]) 393d347a0daSSam Leffler continue; 394776c6824SEd Maste } else if (strcmp(options[i].name, var) != 0) 395776c6824SEd Maste continue; 396776c6824SEd Maste switch (options[i].type) { 397776c6824SEd Maste case OPT_BOOL: 398776c6824SEd Maste *(bool *)options[i].value = 1; 399776c6824SEd Maste break; 400776c6824SEd Maste case OPT_STRARRAY: 401776c6824SEd Maste strlcpy((void *)options[i].value, val, (size_t) 402776c6824SEd Maste options[i].maximum); 403776c6824SEd Maste break; 404776c6824SEd Maste case OPT_STRPTR: 4055f5598b1SEd Maste s = estrdup(val); 406776c6824SEd Maste *(char **)options[i].value = s; 407776c6824SEd Maste break; 408776c6824SEd Maste case OPT_STRBUF: 409776c6824SEd Maste if (buf == NULL) 410776c6824SEd Maste abort(); 411776c6824SEd Maste strlcpy(buf, val, len); 412776c6824SEd Maste break; 413776c6824SEd Maste case OPT_INT64: 414776c6824SEd Maste NUM(uint64_t); 415776c6824SEd Maste case OPT_INT32: 416776c6824SEd Maste NUM(uint32_t); 417776c6824SEd Maste case OPT_INT16: 418776c6824SEd Maste NUM(uint16_t); 419776c6824SEd Maste case OPT_INT8: 420776c6824SEd Maste NUM(uint8_t); 421776c6824SEd Maste default: 422776c6824SEd Maste warnx("Unknown type %d in option %s", options[i].type, 423776c6824SEd Maste val); 424776c6824SEd Maste return 0; 425776c6824SEd Maste } 426776c6824SEd Maste return i; 427d347a0daSSam Leffler } 428d347a0daSSam Leffler warnx("Unknown option `%s'", var); 429776c6824SEd Maste return -1; 430d347a0daSSam Leffler } 431d347a0daSSam Leffler 432d347a0daSSam Leffler 433d347a0daSSam Leffler static fstype_t * 434d347a0daSSam Leffler get_fstype(const char *type) 435d347a0daSSam Leffler { 436d347a0daSSam Leffler int i; 437d347a0daSSam Leffler 438d347a0daSSam Leffler for (i = 0; fstypes[i].type != NULL; i++) 439d347a0daSSam Leffler if (strcmp(fstypes[i].type, type) == 0) 440d347a0daSSam Leffler return (&fstypes[i]); 441d347a0daSSam Leffler return (NULL); 442d347a0daSSam Leffler } 443d347a0daSSam Leffler 444776c6824SEd Maste option_t * 445776c6824SEd Maste copy_opts(const option_t *o) 446776c6824SEd Maste { 447776c6824SEd Maste size_t i; 448776c6824SEd Maste 449776c6824SEd Maste for (i = 0; o[i].name; i++) 450776c6824SEd Maste continue; 451776c6824SEd Maste i++; 4525f5598b1SEd Maste return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); 453776c6824SEd Maste } 454776c6824SEd Maste 4557b03d164SEd Maste static int 4567b03d164SEd Maste get_tstamp(const char *b, struct stat *st) 4577b03d164SEd Maste { 4587b03d164SEd Maste time_t when; 4597b03d164SEd Maste char *eb; 4607b03d164SEd Maste long long l; 4617b03d164SEd Maste 4627b03d164SEd Maste if (stat(b, st) != -1) 4637b03d164SEd Maste return 0; 4647b03d164SEd Maste 4657b03d164SEd Maste { 4667b03d164SEd Maste errno = 0; 4677b03d164SEd Maste l = strtoll(b, &eb, 0); 4687b03d164SEd Maste if (b == eb || *eb || errno) 4697b03d164SEd Maste return -1; 4707b03d164SEd Maste when = (time_t)l; 4717b03d164SEd Maste } 4727b03d164SEd Maste 4737b03d164SEd Maste st->st_ino = 1; 4747b03d164SEd Maste #ifdef HAVE_STRUCT_STAT_BIRTHTIME 4757b03d164SEd Maste st->st_birthtime = 4767b03d164SEd Maste #endif 4777b03d164SEd Maste st->st_mtime = st->st_ctime = st->st_atime = when; 4787b03d164SEd Maste return 0; 4797b03d164SEd Maste } 4807b03d164SEd Maste 481d347a0daSSam Leffler static void 482776c6824SEd Maste usage(fstype_t *fstype, fsinfo_t *fsoptions) 483d347a0daSSam Leffler { 484d347a0daSSam Leffler const char *prog; 485d347a0daSSam Leffler 486d347a0daSSam Leffler prog = getprogname(); 487d347a0daSSam Leffler fprintf(stderr, 488776c6824SEd Maste "Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" 489298d081cSEd Maste "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" 490b79f050aSEd Maste "\t[-N userdb-dir] [-O offset] [-o fs-options] [-R roundup-size]\n" 491b79f050aSEd Maste "\t[-S sector-size] [-s image-size] [-T <timestamp/file>] [-t fs-type]\n" 4927b03d164SEd Maste "\timage-file directory | manifest [extra-directory ...]\n", 493d347a0daSSam Leffler prog); 494776c6824SEd Maste 495776c6824SEd Maste if (fstype) { 496776c6824SEd Maste size_t i; 497776c6824SEd Maste option_t *o = fsoptions->fs_options; 498776c6824SEd Maste 499776c6824SEd Maste fprintf(stderr, "\n%s specific options:\n", fstype->type); 500776c6824SEd Maste for (i = 0; o[i].name != NULL; i++) 501776c6824SEd Maste fprintf(stderr, "\t%c%c%20.20s\t%s\n", 502776c6824SEd Maste o[i].letter ? o[i].letter : ' ', 503776c6824SEd Maste o[i].letter ? ',' : ' ', 504776c6824SEd Maste o[i].name, o[i].desc); 505776c6824SEd Maste } 506d347a0daSSam Leffler exit(1); 507d347a0daSSam Leffler } 508