1*dc0564c1Schristos /* $NetBSD: makefs.c,v 1.59 2024/10/27 18:35:52 christos Exp $ */ 2de8b3ad2Slukem 3de8b3ad2Slukem /* 4e5f38473Slukem * Copyright (c) 2001-2003 Wasabi Systems, Inc. 5de8b3ad2Slukem * All rights reserved. 6de8b3ad2Slukem * 7de8b3ad2Slukem * Written by Luke Mewburn for Wasabi Systems, Inc. 8de8b3ad2Slukem * 9de8b3ad2Slukem * Redistribution and use in source and binary forms, with or without 10de8b3ad2Slukem * modification, are permitted provided that the following conditions 11de8b3ad2Slukem * are met: 12de8b3ad2Slukem * 1. Redistributions of source code must retain the above copyright 13de8b3ad2Slukem * notice, this list of conditions and the following disclaimer. 14de8b3ad2Slukem * 2. Redistributions in binary form must reproduce the above copyright 15de8b3ad2Slukem * notice, this list of conditions and the following disclaimer in the 16de8b3ad2Slukem * documentation and/or other materials provided with the distribution. 17de8b3ad2Slukem * 3. All advertising materials mentioning features or use of this software 18de8b3ad2Slukem * must display the following acknowledgement: 19de8b3ad2Slukem * This product includes software developed for the NetBSD Project by 20de8b3ad2Slukem * Wasabi Systems, Inc. 21de8b3ad2Slukem * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22de8b3ad2Slukem * or promote products derived from this software without specific prior 23de8b3ad2Slukem * written permission. 24de8b3ad2Slukem * 25de8b3ad2Slukem * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26de8b3ad2Slukem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27de8b3ad2Slukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28de8b3ad2Slukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29de8b3ad2Slukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30de8b3ad2Slukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31de8b3ad2Slukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32de8b3ad2Slukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33de8b3ad2Slukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34de8b3ad2Slukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35de8b3ad2Slukem * POSSIBILITY OF SUCH DAMAGE. 36de8b3ad2Slukem */ 37de8b3ad2Slukem 38b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H 39b2f78261Sjmc #include "nbtool_config.h" 40b2f78261Sjmc #endif 41b2f78261Sjmc 42cafb53fcSlukem #include <sys/cdefs.h> 439fbd8888Stv #if defined(__RCSID) && !defined(__lint) 44*dc0564c1Schristos __RCSID("$NetBSD: makefs.c,v 1.59 2024/10/27 18:35:52 christos Exp $"); 45cafb53fcSlukem #endif /* !__lint */ 46cafb53fcSlukem 47de8b3ad2Slukem #include <assert.h> 48de8b3ad2Slukem #include <ctype.h> 49de8b3ad2Slukem #include <errno.h> 50c71f9f27Ssimonb #include <limits.h> 51de8b3ad2Slukem #include <stdio.h> 52de8b3ad2Slukem #include <stdlib.h> 53de8b3ad2Slukem #include <string.h> 54de8b3ad2Slukem #include <unistd.h> 553d364f54Schristos #include <stdbool.h> 56e4989541Schristos #include <util.h> 57de8b3ad2Slukem 58de8b3ad2Slukem #include "makefs.h" 595781235dSlukem #include "mtree.h" 603550dc98Sfvdl #include "cd9660.h" 61de8b3ad2Slukem 62de8b3ad2Slukem /* 63de8b3ad2Slukem * list of supported file systems and dispatch functions 64de8b3ad2Slukem */ 65de8b3ad2Slukem typedef struct { 66de8b3ad2Slukem const char *type; 672406596eSjmc void (*prepare_options)(fsinfo_t *); 68de8b3ad2Slukem int (*parse_options)(const char *, fsinfo_t *); 692406596eSjmc void (*cleanup_options)(fsinfo_t *); 70de8b3ad2Slukem void (*make_fs)(const char *, const char *, fsnode *, 71de8b3ad2Slukem fsinfo_t *); 72de8b3ad2Slukem } fstype_t; 73de8b3ad2Slukem 74de8b3ad2Slukem static fstype_t fstypes[] = { 753d364f54Schristos #define ENTRY(name) { \ 763d364f54Schristos # name, name ## _prep_opts, name ## _parse_opts, \ 773d364f54Schristos name ## _cleanup_opts, name ## _makefs \ 783d364f54Schristos } 793d364f54Schristos ENTRY(ffs), 803d364f54Schristos ENTRY(cd9660), 813d364f54Schristos ENTRY(chfs), 823d364f54Schristos ENTRY(v7fs), 833d364f54Schristos ENTRY(msdos), 84e2036ad8Sreinoud ENTRY(udf), 85f6a7372bSchristos { .type = NULL }, 86de8b3ad2Slukem }; 87de8b3ad2Slukem 88b2f78261Sjmc u_int debug; 89de8b3ad2Slukem struct timespec start_time; 90799916c0Schristos struct stat stampst; 91de8b3ad2Slukem 92de8b3ad2Slukem static fstype_t *get_fstype(const char *); 93799916c0Schristos static int get_tstamp(const char *, struct stat *); 94e4989541Schristos static void usage(fstype_t *, fsinfo_t *) __dead; 95*dc0564c1Schristos static u_int parse_debug(char *); 96de8b3ad2Slukem 97de8b3ad2Slukem int 98de8b3ad2Slukem main(int argc, char *argv[]) 99de8b3ad2Slukem { 100de8b3ad2Slukem struct timeval start; 101de8b3ad2Slukem fstype_t *fstype; 102de8b3ad2Slukem fsinfo_t fsoptions; 103de8b3ad2Slukem fsnode *root; 104855b7dceSchristos int ch, i; 105855b7dceSchristos size_t len; 106de8b3ad2Slukem char *specfile; 107de8b3ad2Slukem 108bf7e1203Slukem setprogname(argv[0]); 109bf7e1203Slukem 110de8b3ad2Slukem debug = 0; 111de8b3ad2Slukem if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) 112ec5d1d82Stsutsui errx(EXIT_FAILURE, 113ec5d1d82Stsutsui "Unknown default fs type `%s'.", DEFAULT_FSTYPE); 114f4821030Slukem 115f4821030Slukem /* set default fsoptions */ 116de8b3ad2Slukem (void)memset(&fsoptions, 0, sizeof(fsoptions)); 117de8b3ad2Slukem fsoptions.fd = -1; 118f4821030Slukem fsoptions.sectorsize = -1; 1192406596eSjmc 1202406596eSjmc if (fstype->prepare_options) 1212406596eSjmc fstype->prepare_options(&fsoptions); 122f4821030Slukem 123de8b3ad2Slukem specfile = NULL; 124799916c0Schristos #ifdef CLOCK_REALTIME 125799916c0Schristos ch = clock_gettime(CLOCK_REALTIME, &start_time); 126799916c0Schristos #else 127799916c0Schristos ch = gettimeofday(&start, NULL); 1289fbd8888Stv start_time.tv_sec = start.tv_sec; 1299fbd8888Stv start_time.tv_nsec = start.tv_usec * 1000; 130799916c0Schristos #endif 131799916c0Schristos if (ch == -1) 132ec5d1d82Stsutsui err(EXIT_FAILURE, "Unable to get system time"); 133de8b3ad2Slukem 134799916c0Schristos 135ba42c78dSsimonb while ((ch = getopt(argc, argv, "B:b:d:f:F:LM:m:N:O:o:rs:S:t:T:xZ")) != -1) { 136de8b3ad2Slukem switch (ch) { 137de8b3ad2Slukem 138de8b3ad2Slukem case 'B': 139de8b3ad2Slukem if (strcmp(optarg, "be") == 0 || 140e5f38473Slukem strcmp(optarg, "4321") == 0 || 141de8b3ad2Slukem strcmp(optarg, "big") == 0) { 142de8b3ad2Slukem #if BYTE_ORDER == LITTLE_ENDIAN 143de8b3ad2Slukem fsoptions.needswap = 1; 144de8b3ad2Slukem #endif 145de8b3ad2Slukem } else if (strcmp(optarg, "le") == 0 || 146e5f38473Slukem strcmp(optarg, "1234") == 0 || 147de8b3ad2Slukem strcmp(optarg, "little") == 0) { 148de8b3ad2Slukem #if BYTE_ORDER == BIG_ENDIAN 149de8b3ad2Slukem fsoptions.needswap = 1; 150de8b3ad2Slukem #endif 151de8b3ad2Slukem } else { 152de8b3ad2Slukem warnx("Invalid endian `%s'.", optarg); 153e4989541Schristos usage(fstype, &fsoptions); 154de8b3ad2Slukem } 155de8b3ad2Slukem break; 156de8b3ad2Slukem 157de8b3ad2Slukem case 'b': 158de8b3ad2Slukem len = strlen(optarg) - 1; 159de8b3ad2Slukem if (optarg[len] == '%') { 160de8b3ad2Slukem optarg[len] = '\0'; 161855b7dceSchristos fsoptions.freeblockpc = (int) 162d0824326Slukem strsuftoll("free block percentage", 163ae62d656Slukem optarg, 0, 99); 164de8b3ad2Slukem } else { 165ae62d656Slukem fsoptions.freeblocks = 166d0824326Slukem strsuftoll("free blocks", 167de8b3ad2Slukem optarg, 0, LLONG_MAX); 168de8b3ad2Slukem } 169de8b3ad2Slukem break; 170de8b3ad2Slukem 171de8b3ad2Slukem case 'd': 172*dc0564c1Schristos debug = parse_debug(optarg); 173de8b3ad2Slukem break; 174de8b3ad2Slukem 175de8b3ad2Slukem case 'f': 176de8b3ad2Slukem len = strlen(optarg) - 1; 177de8b3ad2Slukem if (optarg[len] == '%') { 178de8b3ad2Slukem optarg[len] = '\0'; 179855b7dceSchristos fsoptions.freefilepc = (int) 180d0824326Slukem strsuftoll("free file percentage", 181ae62d656Slukem optarg, 0, 99); 182de8b3ad2Slukem } else { 183ae62d656Slukem fsoptions.freefiles = 184d0824326Slukem strsuftoll("free files", 185de8b3ad2Slukem optarg, 0, LLONG_MAX); 186de8b3ad2Slukem } 187de8b3ad2Slukem break; 188de8b3ad2Slukem 189de8b3ad2Slukem case 'F': 190de8b3ad2Slukem specfile = optarg; 191de8b3ad2Slukem break; 192de8b3ad2Slukem 193ba42c78dSsimonb case 'L': 194ba42c78dSsimonb fsoptions.follow = true; 195ba42c78dSsimonb break; 196ba42c78dSsimonb 197de8b3ad2Slukem case 'M': 198ae62d656Slukem fsoptions.minsize = 199d0824326Slukem strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); 200de8b3ad2Slukem break; 201de8b3ad2Slukem 2025781235dSlukem case 'N': 2035781235dSlukem if (! setup_getid(optarg)) 204ec5d1d82Stsutsui errx(EXIT_FAILURE, 2055781235dSlukem "Unable to use user and group databases in `%s'", 2065781235dSlukem optarg); 2075781235dSlukem break; 2085781235dSlukem 209de8b3ad2Slukem case 'm': 210ae62d656Slukem fsoptions.maxsize = 211d0824326Slukem strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); 212de8b3ad2Slukem break; 213de8b3ad2Slukem 2142d692a95Schristos case 'O': 2152d692a95Schristos fsoptions.offset = 2162d692a95Schristos strsuftoll("offset", optarg, 0LL, LLONG_MAX); 2172d692a95Schristos break; 2182d692a95Schristos 219de8b3ad2Slukem case 'o': 220de8b3ad2Slukem { 221de8b3ad2Slukem char *p; 222de8b3ad2Slukem 223de8b3ad2Slukem while ((p = strsep(&optarg, ",")) != NULL) { 224de8b3ad2Slukem if (*p == '\0') 225ec5d1d82Stsutsui errx(EXIT_FAILURE, "Empty option"); 226de8b3ad2Slukem if (! fstype->parse_options(p, &fsoptions)) 227e4989541Schristos usage(fstype, &fsoptions); 228de8b3ad2Slukem } 229de8b3ad2Slukem break; 230de8b3ad2Slukem } 231de8b3ad2Slukem 232c06c93b2Schristos case 'r': 233c06c93b2Schristos fsoptions.replace = 1; 234c06c93b2Schristos break; 235c06c93b2Schristos 236de8b3ad2Slukem case 's': 237de8b3ad2Slukem fsoptions.minsize = fsoptions.maxsize = 238d0824326Slukem strsuftoll("size", optarg, 1LL, LLONG_MAX); 239de8b3ad2Slukem break; 240de8b3ad2Slukem 241de8b3ad2Slukem case 'S': 242ae62d656Slukem fsoptions.sectorsize = 243d0824326Slukem (int)strsuftoll("sector size", optarg, 244ae62d656Slukem 1LL, INT_MAX); 245de8b3ad2Slukem break; 246de8b3ad2Slukem 247de8b3ad2Slukem case 't': 2482406596eSjmc /* Check current one and cleanup if necessary. */ 2492406596eSjmc if (fstype->cleanup_options) 2502406596eSjmc fstype->cleanup_options(&fsoptions); 2512406596eSjmc fsoptions.fs_specific = NULL; 252de8b3ad2Slukem if ((fstype = get_fstype(optarg)) == NULL) 253ec5d1d82Stsutsui errx(EXIT_FAILURE, 254ec5d1d82Stsutsui "Unknown fs type `%s'.", optarg); 2552406596eSjmc fstype->prepare_options(&fsoptions); 256de8b3ad2Slukem break; 257de8b3ad2Slukem 258799916c0Schristos case 'T': 259799916c0Schristos if (get_tstamp(optarg, &stampst) == -1) 260ec5d1d82Stsutsui errx(EXIT_FAILURE, 261ec5d1d82Stsutsui "Cannot get timestamp from `%s'", optarg); 262799916c0Schristos break; 263799916c0Schristos 2641bcb9d76Sthorpej case 'x': 2650fe82aa4Schristos fsoptions.onlyspec++; 2661bcb9d76Sthorpej break; 2671bcb9d76Sthorpej 26807f6254fSsjg case 'Z': 26907f6254fSsjg fsoptions.sparse = 1; 27007f6254fSsjg break; 27107f6254fSsjg 272de8b3ad2Slukem case '?': 273de8b3ad2Slukem default: 274e4989541Schristos usage(fstype, &fsoptions); 275de8b3ad2Slukem /* NOTREACHED */ 276de8b3ad2Slukem 277de8b3ad2Slukem } 278de8b3ad2Slukem } 279de8b3ad2Slukem if (debug) { 280de8b3ad2Slukem printf("debug mask: 0x%08x\n", debug); 281de8b3ad2Slukem printf("start time: %ld.%ld, %s", 282ae963680Slukem (long)start_time.tv_sec, (long)start_time.tv_nsec, 283de8b3ad2Slukem ctime(&start_time.tv_sec)); 284de8b3ad2Slukem } 285de8b3ad2Slukem argc -= optind; 286de8b3ad2Slukem argv += optind; 287de8b3ad2Slukem 288f1cc0951Schristos if (argc < 2) 289e4989541Schristos usage(fstype, &fsoptions); 290de8b3ad2Slukem 2911bcb9d76Sthorpej /* -x must be accompanied by -F */ 2926ddeaceaSlukem if (fsoptions.onlyspec != 0 && specfile == NULL) 293ec5d1d82Stsutsui errx(EXIT_FAILURE, "-x requires -F mtree-specfile."); 2941bcb9d76Sthorpej 295de8b3ad2Slukem /* walk the tree */ 296de8b3ad2Slukem TIMER_START(start); 297ba42c78dSsimonb root = walk_dir(argv[1], ".", NULL, NULL, fsoptions.replace, 298ba42c78dSsimonb fsoptions.follow); 299de8b3ad2Slukem TIMER_RESULTS(start, "walk_dir"); 300de8b3ad2Slukem 301f1cc0951Schristos /* append extra directory */ 302f1cc0951Schristos for (i = 2; i < argc; i++) { 303f1cc0951Schristos struct stat sb; 304f1cc0951Schristos if (stat(argv[i], &sb) == -1) 305ec5d1d82Stsutsui err(EXIT_FAILURE, "Can't stat `%s'", argv[i]); 306f1cc0951Schristos if (!S_ISDIR(sb.st_mode)) 307ec5d1d82Stsutsui errx(EXIT_FAILURE, "%s: not a directory", argv[i]); 308f1cc0951Schristos TIMER_START(start); 309ba42c78dSsimonb root = walk_dir(argv[i], ".", NULL, root, fsoptions.replace, 310ba42c78dSsimonb fsoptions.follow); 311f1cc0951Schristos TIMER_RESULTS(start, "walk_dir2"); 312f1cc0951Schristos } 313f1cc0951Schristos 314de8b3ad2Slukem if (specfile) { /* apply a specfile */ 315de8b3ad2Slukem TIMER_START(start); 316d0c4ff45Sdbj apply_specfile(specfile, argv[1], root, fsoptions.onlyspec); 317de8b3ad2Slukem TIMER_RESULTS(start, "apply_specfile"); 318de8b3ad2Slukem } 319de8b3ad2Slukem 320de8b3ad2Slukem if (debug & DEBUG_DUMP_FSNODES) { 321aa99e59fSlukem printf("\nparent: %s\n", argv[1]); 322f1cc0951Schristos dump_fsnodes(root); 323de8b3ad2Slukem putchar('\n'); 324de8b3ad2Slukem } 325de8b3ad2Slukem 326de8b3ad2Slukem /* build the file system */ 327de8b3ad2Slukem TIMER_START(start); 328de8b3ad2Slukem fstype->make_fs(argv[0], argv[1], root, &fsoptions); 329de8b3ad2Slukem TIMER_RESULTS(start, "make_fs"); 330de8b3ad2Slukem 3310e392af9Sdbj free_fsnodes(root); 3320e392af9Sdbj 333ec5d1d82Stsutsui exit(EXIT_SUCCESS); 334de8b3ad2Slukem /* NOTREACHED */ 335de8b3ad2Slukem } 336de8b3ad2Slukem 3371c35cd38Schristos int 33850d02345Schristos set_option(const option_t *options, const char *option, char *buf, size_t len) 3391c35cd38Schristos { 3401c35cd38Schristos char *var, *val; 3411c35cd38Schristos int retval; 3421c35cd38Schristos 3431c35cd38Schristos assert(option != NULL); 3441c35cd38Schristos 345e4989541Schristos var = estrdup(option); 34636e64830Schristos for (val = var; *val; val++) 34736e64830Schristos if (*val == '=') { 3481c35cd38Schristos *val++ = '\0'; 34936e64830Schristos break; 35036e64830Schristos } 35150d02345Schristos retval = set_option_var(options, var, val, buf, len); 3521c35cd38Schristos free(var); 3531c35cd38Schristos return retval; 3541c35cd38Schristos } 355de8b3ad2Slukem 356855b7dceSchristos void 357855b7dceSchristos print_options(FILE *fp, const option_t *options) 358855b7dceSchristos { 359855b7dceSchristos for (size_t i = 0; options[i].name != NULL; i++) { 360855b7dceSchristos fprintf(fp, "%s=", options[i].name); 361855b7dceSchristos switch (options[i].type) { 362855b7dceSchristos case OPT_BOOL: 363855b7dceSchristos fputs(*(bool *)options[i].value ? "true\n" : "false\n", 364855b7dceSchristos fp); 365855b7dceSchristos break; 366855b7dceSchristos case OPT_STRARRAY: 367855b7dceSchristos case OPT_STRPTR: 368855b7dceSchristos case OPT_STRBUF: 369855b7dceSchristos fprintf(fp, "%s\n", *(const char **)options[i].value); 370855b7dceSchristos break; 371855b7dceSchristos case OPT_INT64: 372855b7dceSchristos fprintf(fp, "%" PRIu64 "\n", 373855b7dceSchristos *(uint64_t *)options[i].value); 374855b7dceSchristos break; 375855b7dceSchristos case OPT_INT32: 376855b7dceSchristos fprintf(fp, "%" PRIu32 "\n", 377855b7dceSchristos *(uint32_t *)options[i].value); 378855b7dceSchristos break; 379855b7dceSchristos case OPT_INT16: 380855b7dceSchristos fprintf(fp, "%" PRIu16 "\n", 381855b7dceSchristos *(uint16_t *)options[i].value); 382855b7dceSchristos break; 383855b7dceSchristos case OPT_INT8: 384855b7dceSchristos fprintf(fp, "%" PRIu8 "\n", 385855b7dceSchristos *(uint8_t *)options[i].value); 386855b7dceSchristos break; 387855b7dceSchristos default: 388855b7dceSchristos warnx("Unknown type %d in option %s", options[i].type, 389855b7dceSchristos options[i].name); 390855b7dceSchristos return; 391855b7dceSchristos } 392855b7dceSchristos } 393855b7dceSchristos } 394855b7dceSchristos 395de8b3ad2Slukem int 39650d02345Schristos set_option_var(const option_t *options, const char *var, const char *val, 39750d02345Schristos char *buf, size_t len) 398de8b3ad2Slukem { 3993d364f54Schristos char *s; 4003d364f54Schristos size_t i; 4013d364f54Schristos 4027a9c8c65Schristos #define NUM(type) \ 4039eb809c6Schristos if (!*val) { \ 4047a9c8c65Schristos *(type *)options[i].value = 1; \ 40536e64830Schristos break; \ 40636e64830Schristos } \ 4077a9c8c65Schristos *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ 4083d364f54Schristos options[i].minimum, options[i].maximum); break 409de8b3ad2Slukem 410de8b3ad2Slukem for (i = 0; options[i].name != NULL; i++) { 4117176d59dSchristos if (var[1] == '\0') { 4127176d59dSchristos if (options[i].letter != var[0]) 413de8b3ad2Slukem continue; 4147176d59dSchristos } else if (strcmp(options[i].name, var) != 0) 4153d364f54Schristos continue; 4163d364f54Schristos switch (options[i].type) { 4173d364f54Schristos case OPT_BOOL: 4183d364f54Schristos *(bool *)options[i].value = 1; 4193d364f54Schristos break; 4203d364f54Schristos case OPT_STRARRAY: 4213d364f54Schristos strlcpy((void *)options[i].value, val, (size_t) 4223d364f54Schristos options[i].maximum); 4233d364f54Schristos break; 4243d364f54Schristos case OPT_STRPTR: 425e4989541Schristos s = estrdup(val); 4263d364f54Schristos *(char **)options[i].value = s; 4273d364f54Schristos break; 42850d02345Schristos case OPT_STRBUF: 42950d02345Schristos if (buf == NULL) 43050d02345Schristos abort(); 43150d02345Schristos strlcpy(buf, val, len); 43250d02345Schristos break; 4333d364f54Schristos case OPT_INT64: 4347a9c8c65Schristos NUM(uint64_t); 4353d364f54Schristos case OPT_INT32: 4367a9c8c65Schristos NUM(uint32_t); 4373d364f54Schristos case OPT_INT16: 4387a9c8c65Schristos NUM(uint16_t); 4393d364f54Schristos case OPT_INT8: 4407a9c8c65Schristos NUM(uint8_t); 4413d364f54Schristos default: 4423d364f54Schristos warnx("Unknown type %d in option %s", options[i].type, 4433d364f54Schristos val); 4443d364f54Schristos return 0; 4453d364f54Schristos } 446855b7dceSchristos return (int)i; 447de8b3ad2Slukem } 448de8b3ad2Slukem warnx("Unknown option `%s'", var); 449562664d1Schristos return -1; 450de8b3ad2Slukem } 451de8b3ad2Slukem 452de8b3ad2Slukem 453de8b3ad2Slukem static fstype_t * 454de8b3ad2Slukem get_fstype(const char *type) 455de8b3ad2Slukem { 456de8b3ad2Slukem int i; 457de8b3ad2Slukem 458de8b3ad2Slukem for (i = 0; fstypes[i].type != NULL; i++) 459de8b3ad2Slukem if (strcmp(fstypes[i].type, type) == 0) 460de8b3ad2Slukem return (&fstypes[i]); 461de8b3ad2Slukem return (NULL); 462de8b3ad2Slukem } 463de8b3ad2Slukem 464e4989541Schristos option_t * 465e4989541Schristos copy_opts(const option_t *o) 466e4989541Schristos { 467e4989541Schristos size_t i; 468e4989541Schristos for (i = 0; o[i].name; i++) 469e4989541Schristos continue; 470e4989541Schristos i++; 471e4989541Schristos return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); 472e4989541Schristos } 473e4989541Schristos 474799916c0Schristos static int 475799916c0Schristos get_tstamp(const char *b, struct stat *st) 476799916c0Schristos { 477799916c0Schristos time_t when; 478799916c0Schristos char *eb; 479799916c0Schristos long long l; 480799916c0Schristos 481799916c0Schristos if (stat(b, st) != -1) 482799916c0Schristos return 0; 483799916c0Schristos 484799916c0Schristos #ifndef HAVE_NBTOOL_CONFIG_H 485799916c0Schristos errno = 0; 486d0bd9a5fSjoerg if ((when = parsedate(b, NULL, NULL)) == -1 && errno != 0) 487799916c0Schristos #endif 488799916c0Schristos { 489799916c0Schristos errno = 0; 490799916c0Schristos l = strtoll(b, &eb, 0); 491799916c0Schristos if (b == eb || *eb || errno) 492799916c0Schristos return -1; 493799916c0Schristos when = (time_t)l; 494799916c0Schristos } 495799916c0Schristos 496799916c0Schristos st->st_ino = 1; 497799916c0Schristos #if HAVE_STRUCT_STAT_BIRTHTIME 498799916c0Schristos st->st_birthtime = 499799916c0Schristos #endif 500799916c0Schristos st->st_mtime = st->st_ctime = st->st_atime = when; 501799916c0Schristos return 0; 502799916c0Schristos } 503799916c0Schristos 504*dc0564c1Schristos static struct { 505*dc0564c1Schristos const char *n; 506*dc0564c1Schristos u_int v; 507*dc0564c1Schristos } nv[] = { 508*dc0564c1Schristos DEBUG_STRINGS 509*dc0564c1Schristos }; 510*dc0564c1Schristos 511de8b3ad2Slukem static void 512e4989541Schristos usage(fstype_t *fstype, fsinfo_t *fsoptions) 513de8b3ad2Slukem { 514de8b3ad2Slukem const char *prog; 515de8b3ad2Slukem 516de8b3ad2Slukem prog = getprogname(); 517de8b3ad2Slukem fprintf(stderr, 518*dc0564c1Schristos "Usage: %s [-rxZ] [-B endian] [-b free-blocks] [-d debug-mask|comma-separated-option]\n" 5192d692a95Schristos "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" 5202d692a95Schristos "\t[-N userdb-dir] [-O offset] [-o fs-options] [-S sector-size]\n" 521516ffc06Swiz "\t[-s image-size] [-T <timestamp/file>] [-t fs-type]" 522799916c0Schristos " image-file directory [extra-directory ...]\n", 523de8b3ad2Slukem prog); 524e4989541Schristos 525*dc0564c1Schristos fprintf(stderr, "\nDebugging options:\n"); 526*dc0564c1Schristos for (size_t i = 0; i < __arraycount(nv); i++) 527*dc0564c1Schristos fprintf(stderr, "\t0x%8.8x\t%s\n", nv[i].v, nv[i].n); 528*dc0564c1Schristos 529e4989541Schristos if (fstype) { 530e4989541Schristos size_t i; 531e4989541Schristos option_t *o = fsoptions->fs_options; 532e4989541Schristos 533e4989541Schristos fprintf(stderr, "\n%s specific options:\n", fstype->type); 534e4989541Schristos for (i = 0; o[i].name != NULL; i++) 5352246e723Schristos fprintf(stderr, "\t%c%c%20.20s\t%s\n", 5362246e723Schristos o[i].letter ? o[i].letter : ' ', 5372246e723Schristos o[i].letter ? ',' : ' ', 538e4989541Schristos o[i].name, o[i].desc); 539e4989541Schristos } 540ec5d1d82Stsutsui exit(EXIT_FAILURE); 541de8b3ad2Slukem } 542*dc0564c1Schristos 543*dc0564c1Schristos 544*dc0564c1Schristos static u_int 545*dc0564c1Schristos parse_debug(char *str) 546*dc0564c1Schristos { 547*dc0564c1Schristos char *ep; 548*dc0564c1Schristos u_int d; 549*dc0564c1Schristos size_t i; 550*dc0564c1Schristos 551*dc0564c1Schristos errno = 0; 552*dc0564c1Schristos d = (u_int)strtoul(str, &ep, 0); 553*dc0564c1Schristos if (str != ep && !*ep && errno == 0) 554*dc0564c1Schristos return d; 555*dc0564c1Schristos d = 0; 556*dc0564c1Schristos for (char *a = strtok(str, ","); a != NULL; a = strtok(NULL, ",")) { 557*dc0564c1Schristos for (i = 0; i < __arraycount(nv); i++) 558*dc0564c1Schristos if (strcmp(nv[i].n, a) == 0) { 559*dc0564c1Schristos d |= nv[i].v; 560*dc0564c1Schristos break; 561*dc0564c1Schristos } 562*dc0564c1Schristos if (i == __arraycount(nv)) 563*dc0564c1Schristos errx(EXIT_FAILURE, "Unknown debug option `%s'", a); 564*dc0564c1Schristos } 565*dc0564c1Schristos return d; 566*dc0564c1Schristos } 567*dc0564c1Schristos 568