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 40484b5c25SMarcel Moolenaar #include <sys/types.h> 41484b5c25SMarcel Moolenaar #include <sys/stat.h> 42d347a0daSSam Leffler #include <assert.h> 43d347a0daSSam Leffler #include <ctype.h> 44d347a0daSSam Leffler #include <errno.h> 45d347a0daSSam Leffler #include <limits.h> 46d347a0daSSam Leffler #include <stdio.h> 47d347a0daSSam Leffler #include <stdlib.h> 48d347a0daSSam Leffler #include <string.h> 497649cb00SKirk McKusick #include <time.h> 50d347a0daSSam Leffler #include <unistd.h> 51776c6824SEd Maste #include <stdbool.h> 525f5598b1SEd Maste #include <util.h> 53d347a0daSSam Leffler 54d347a0daSSam Leffler #include "makefs.h" 55d347a0daSSam Leffler #include "mtree.h" 56d347a0daSSam Leffler 57d347a0daSSam Leffler /* 58d347a0daSSam Leffler * list of supported file systems and dispatch functions 59d347a0daSSam Leffler */ 60d347a0daSSam Leffler typedef struct { 61d347a0daSSam Leffler const char *type; 6201a0f853SOlivier Houchard void (*prepare_options)(fsinfo_t *); 63d347a0daSSam Leffler int (*parse_options)(const char *, fsinfo_t *); 6401a0f853SOlivier Houchard void (*cleanup_options)(fsinfo_t *); 65d347a0daSSam Leffler void (*make_fs)(const char *, const char *, fsnode *, 66d347a0daSSam Leffler fsinfo_t *); 67d347a0daSSam Leffler } fstype_t; 68d347a0daSSam Leffler 69d347a0daSSam Leffler static fstype_t fstypes[] = { 70203b6f69SEd Maste #define ENTRY(name) { \ 71203b6f69SEd Maste # name, name ## _prep_opts, name ## _parse_opts, \ 72203b6f69SEd Maste name ## _cleanup_opts, name ## _makefs \ 73203b6f69SEd Maste } 74203b6f69SEd Maste ENTRY(cd9660), 7598dc8da5SEd Maste ENTRY(ffs), 7698dc8da5SEd Maste ENTRY(msdos), 77240afd8cSMark Johnston #ifdef HAVE_ZFS 78240afd8cSMark Johnston ENTRY(zfs), 79240afd8cSMark Johnston #endif 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': 167*e0deb850SMark Johnston dupsok++; 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 default: 274776c6824SEd Maste usage(fstype, &fsoptions); 275d347a0daSSam Leffler /* NOTREACHED */ 276d347a0daSSam Leffler 277d347a0daSSam Leffler } 278d347a0daSSam Leffler } 279d347a0daSSam Leffler if (debug) { 280d347a0daSSam Leffler printf("debug mask: 0x%08x\n", debug); 281d347a0daSSam Leffler printf("start time: %ld.%ld, %s", 282d347a0daSSam Leffler (long)start_time.tv_sec, (long)start_time.tv_nsec, 283d347a0daSSam Leffler ctime(&start_time.tv_sec)); 284d347a0daSSam Leffler } 285d347a0daSSam Leffler argc -= optind; 286d347a0daSSam Leffler argv += optind; 287d347a0daSSam Leffler 288688aaa09SJung-uk Kim if (argc < 2) 289776c6824SEd Maste usage(fstype, &fsoptions); 290d347a0daSSam Leffler 291d347a0daSSam Leffler /* -x must be accompanied by -F */ 292d347a0daSSam Leffler if (fsoptions.onlyspec != 0 && specfile == NULL) 293d347a0daSSam Leffler errx(1, "-x requires -F mtree-specfile."); 294d347a0daSSam Leffler 295484b5c25SMarcel Moolenaar /* Accept '-' as meaning "read from standard input". */ 296484b5c25SMarcel Moolenaar if (strcmp(argv[1], "-") == 0) 297484b5c25SMarcel Moolenaar sb.st_mode = S_IFREG; 298484b5c25SMarcel Moolenaar else { 299484b5c25SMarcel Moolenaar if (stat(argv[1], &sb) == -1) 300484b5c25SMarcel Moolenaar err(1, "Can't stat `%s'", argv[1]); 301484b5c25SMarcel Moolenaar } 302484b5c25SMarcel Moolenaar 303484b5c25SMarcel Moolenaar switch (sb.st_mode & S_IFMT) { 304484b5c25SMarcel Moolenaar case S_IFDIR: /* walk the tree */ 305484b5c25SMarcel Moolenaar subtree = argv[1]; 306d347a0daSSam Leffler TIMER_START(start); 307688aaa09SJung-uk Kim root = walk_dir(subtree, ".", NULL, NULL); 308d347a0daSSam Leffler TIMER_RESULTS(start, "walk_dir"); 309484b5c25SMarcel Moolenaar break; 310484b5c25SMarcel Moolenaar case S_IFREG: /* read the manifest file */ 311484b5c25SMarcel Moolenaar subtree = "."; 312484b5c25SMarcel Moolenaar TIMER_START(start); 313484b5c25SMarcel Moolenaar root = read_mtree(argv[1], NULL); 314484b5c25SMarcel Moolenaar TIMER_RESULTS(start, "manifest"); 315484b5c25SMarcel Moolenaar break; 316484b5c25SMarcel Moolenaar default: 317484b5c25SMarcel Moolenaar errx(1, "%s: not a file or directory", argv[1]); 318484b5c25SMarcel Moolenaar /* NOTREACHED */ 319484b5c25SMarcel Moolenaar } 320d347a0daSSam Leffler 321688aaa09SJung-uk Kim /* append extra directory */ 322688aaa09SJung-uk Kim for (i = 2; i < argc; i++) { 323688aaa09SJung-uk Kim if (stat(argv[i], &sb) == -1) 324688aaa09SJung-uk Kim err(1, "Can't stat `%s'", argv[i]); 325688aaa09SJung-uk Kim if (!S_ISDIR(sb.st_mode)) 326688aaa09SJung-uk Kim errx(1, "%s: not a directory", argv[i]); 327688aaa09SJung-uk Kim TIMER_START(start); 328688aaa09SJung-uk Kim root = walk_dir(argv[i], ".", NULL, root); 329688aaa09SJung-uk Kim TIMER_RESULTS(start, "walk_dir2"); 330688aaa09SJung-uk Kim } 331688aaa09SJung-uk Kim 332d347a0daSSam Leffler if (specfile) { /* apply a specfile */ 333d347a0daSSam Leffler TIMER_START(start); 334484b5c25SMarcel Moolenaar apply_specfile(specfile, subtree, root, fsoptions.onlyspec); 335d347a0daSSam Leffler TIMER_RESULTS(start, "apply_specfile"); 336d347a0daSSam Leffler } 337d347a0daSSam Leffler 338d347a0daSSam Leffler if (debug & DEBUG_DUMP_FSNODES) { 339484b5c25SMarcel Moolenaar printf("\nparent: %s\n", subtree); 340688aaa09SJung-uk Kim dump_fsnodes(root); 341d347a0daSSam Leffler putchar('\n'); 342d347a0daSSam Leffler } 343d347a0daSSam Leffler 344d347a0daSSam Leffler /* build the file system */ 345d347a0daSSam Leffler TIMER_START(start); 346484b5c25SMarcel Moolenaar fstype->make_fs(argv[0], subtree, root, &fsoptions); 347d347a0daSSam Leffler TIMER_RESULTS(start, "make_fs"); 348d347a0daSSam Leffler 34901a0f853SOlivier Houchard free_fsnodes(root); 35001a0f853SOlivier Houchard 351d347a0daSSam Leffler exit(0); 352d347a0daSSam Leffler /* NOTREACHED */ 353d347a0daSSam Leffler } 354d347a0daSSam Leffler 355776c6824SEd Maste int 356776c6824SEd Maste set_option(const option_t *options, const char *option, char *buf, size_t len) 357776c6824SEd Maste { 358776c6824SEd Maste char *var, *val; 359776c6824SEd Maste int retval; 360776c6824SEd Maste 361776c6824SEd Maste assert(option != NULL); 362776c6824SEd Maste 3635f5598b1SEd Maste var = estrdup(option); 364776c6824SEd Maste for (val = var; *val; val++) 365776c6824SEd Maste if (*val == '=') { 366776c6824SEd Maste *val++ = '\0'; 367776c6824SEd Maste break; 368776c6824SEd Maste } 369776c6824SEd Maste retval = set_option_var(options, var, val, buf, len); 370776c6824SEd Maste free(var); 371776c6824SEd Maste return retval; 372776c6824SEd Maste } 373d347a0daSSam Leffler 374d347a0daSSam Leffler int 375776c6824SEd Maste set_option_var(const option_t *options, const char *var, const char *val, 376776c6824SEd Maste char *buf, size_t len) 377d347a0daSSam Leffler { 378776c6824SEd Maste char *s; 379776c6824SEd Maste size_t i; 380776c6824SEd Maste 381776c6824SEd Maste #define NUM(type) \ 382776c6824SEd Maste if (!*val) { \ 383776c6824SEd Maste *(type *)options[i].value = 1; \ 384776c6824SEd Maste break; \ 385776c6824SEd Maste } \ 386776c6824SEd Maste *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ 387776c6824SEd Maste options[i].minimum, options[i].maximum); break 388d347a0daSSam Leffler 389d347a0daSSam Leffler for (i = 0; options[i].name != NULL; i++) { 390776c6824SEd Maste if (var[1] == '\0') { 391776c6824SEd Maste if (options[i].letter != var[0]) 392d347a0daSSam Leffler continue; 393776c6824SEd Maste } else if (strcmp(options[i].name, var) != 0) 394776c6824SEd Maste continue; 395776c6824SEd Maste switch (options[i].type) { 396776c6824SEd Maste case OPT_BOOL: 397776c6824SEd Maste *(bool *)options[i].value = 1; 398776c6824SEd Maste break; 399776c6824SEd Maste case OPT_STRARRAY: 400776c6824SEd Maste strlcpy((void *)options[i].value, val, (size_t) 401776c6824SEd Maste options[i].maximum); 402776c6824SEd Maste break; 403776c6824SEd Maste case OPT_STRPTR: 4045f5598b1SEd Maste s = estrdup(val); 405776c6824SEd Maste *(char **)options[i].value = s; 406776c6824SEd Maste break; 407776c6824SEd Maste case OPT_STRBUF: 408776c6824SEd Maste if (buf == NULL) 409776c6824SEd Maste abort(); 410776c6824SEd Maste strlcpy(buf, val, len); 411776c6824SEd Maste break; 412776c6824SEd Maste case OPT_INT64: 413776c6824SEd Maste NUM(uint64_t); 414776c6824SEd Maste case OPT_INT32: 415776c6824SEd Maste NUM(uint32_t); 416776c6824SEd Maste case OPT_INT16: 417776c6824SEd Maste NUM(uint16_t); 418776c6824SEd Maste case OPT_INT8: 419776c6824SEd Maste NUM(uint8_t); 420776c6824SEd Maste default: 421776c6824SEd Maste warnx("Unknown type %d in option %s", options[i].type, 422776c6824SEd Maste val); 423776c6824SEd Maste return 0; 424776c6824SEd Maste } 425776c6824SEd Maste return i; 426d347a0daSSam Leffler } 427d347a0daSSam Leffler warnx("Unknown option `%s'", var); 428776c6824SEd Maste return -1; 429d347a0daSSam Leffler } 430d347a0daSSam Leffler 431d347a0daSSam Leffler 432d347a0daSSam Leffler static fstype_t * 433d347a0daSSam Leffler get_fstype(const char *type) 434d347a0daSSam Leffler { 435d347a0daSSam Leffler int i; 436d347a0daSSam Leffler 437d347a0daSSam Leffler for (i = 0; fstypes[i].type != NULL; i++) 438d347a0daSSam Leffler if (strcmp(fstypes[i].type, type) == 0) 439d347a0daSSam Leffler return (&fstypes[i]); 440d347a0daSSam Leffler return (NULL); 441d347a0daSSam Leffler } 442d347a0daSSam Leffler 443776c6824SEd Maste option_t * 444776c6824SEd Maste copy_opts(const option_t *o) 445776c6824SEd Maste { 446776c6824SEd Maste size_t i; 447776c6824SEd Maste 448776c6824SEd Maste for (i = 0; o[i].name; i++) 449776c6824SEd Maste continue; 450776c6824SEd Maste i++; 4515f5598b1SEd Maste return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); 452776c6824SEd Maste } 453776c6824SEd Maste 4547b03d164SEd Maste static int 4557b03d164SEd Maste get_tstamp(const char *b, struct stat *st) 4567b03d164SEd Maste { 4577b03d164SEd Maste time_t when; 4587b03d164SEd Maste char *eb; 4597b03d164SEd Maste long long l; 4607b03d164SEd Maste 4617b03d164SEd Maste if (stat(b, st) != -1) 4627b03d164SEd Maste return 0; 4637b03d164SEd Maste 4647b03d164SEd Maste { 4657b03d164SEd Maste errno = 0; 4667b03d164SEd Maste l = strtoll(b, &eb, 0); 4677b03d164SEd Maste if (b == eb || *eb || errno) 4687b03d164SEd Maste return -1; 4697b03d164SEd Maste when = (time_t)l; 4707b03d164SEd Maste } 4717b03d164SEd Maste 4727b03d164SEd Maste st->st_ino = 1; 4737b03d164SEd Maste #ifdef HAVE_STRUCT_STAT_BIRTHTIME 4747b03d164SEd Maste st->st_birthtime = 4757b03d164SEd Maste #endif 4767b03d164SEd Maste st->st_mtime = st->st_ctime = st->st_atime = when; 4777b03d164SEd Maste return 0; 4787b03d164SEd Maste } 4797b03d164SEd Maste 480d347a0daSSam Leffler static void 481776c6824SEd Maste usage(fstype_t *fstype, fsinfo_t *fsoptions) 482d347a0daSSam Leffler { 483d347a0daSSam Leffler const char *prog; 484d347a0daSSam Leffler 485d347a0daSSam Leffler prog = getprogname(); 486d347a0daSSam Leffler fprintf(stderr, 487776c6824SEd Maste "Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" 488298d081cSEd Maste "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" 489b79f050aSEd Maste "\t[-N userdb-dir] [-O offset] [-o fs-options] [-R roundup-size]\n" 490b79f050aSEd Maste "\t[-S sector-size] [-s image-size] [-T <timestamp/file>] [-t fs-type]\n" 4917b03d164SEd Maste "\timage-file directory | manifest [extra-directory ...]\n", 492d347a0daSSam Leffler prog); 493776c6824SEd Maste 494776c6824SEd Maste if (fstype) { 495776c6824SEd Maste size_t i; 496776c6824SEd Maste option_t *o = fsoptions->fs_options; 497776c6824SEd Maste 498776c6824SEd Maste fprintf(stderr, "\n%s specific options:\n", fstype->type); 499776c6824SEd Maste for (i = 0; o[i].name != NULL; i++) 500776c6824SEd Maste fprintf(stderr, "\t%c%c%20.20s\t%s\n", 501776c6824SEd Maste o[i].letter ? o[i].letter : ' ', 502776c6824SEd Maste o[i].letter ? ',' : ' ', 503776c6824SEd Maste o[i].name, o[i].desc); 504776c6824SEd Maste } 505d347a0daSSam Leffler exit(1); 506d347a0daSSam Leffler } 507