1 1.59 christos /* $NetBSD: makefs.c,v 1.59 2024/10/27 18:35:52 christos Exp $ */ 2 1.1 lukem 3 1.1 lukem /* 4 1.15 lukem * Copyright (c) 2001-2003 Wasabi Systems, Inc. 5 1.1 lukem * All rights reserved. 6 1.1 lukem * 7 1.1 lukem * Written by Luke Mewburn for Wasabi Systems, Inc. 8 1.1 lukem * 9 1.1 lukem * Redistribution and use in source and binary forms, with or without 10 1.1 lukem * modification, are permitted provided that the following conditions 11 1.1 lukem * are met: 12 1.1 lukem * 1. Redistributions of source code must retain the above copyright 13 1.1 lukem * notice, this list of conditions and the following disclaimer. 14 1.1 lukem * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 lukem * notice, this list of conditions and the following disclaimer in the 16 1.1 lukem * documentation and/or other materials provided with the distribution. 17 1.1 lukem * 3. All advertising materials mentioning features or use of this software 18 1.1 lukem * must display the following acknowledgement: 19 1.1 lukem * This product includes software developed for the NetBSD Project by 20 1.1 lukem * Wasabi Systems, Inc. 21 1.1 lukem * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 lukem * or promote products derived from this software without specific prior 23 1.1 lukem * written permission. 24 1.1 lukem * 25 1.1 lukem * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 lukem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 lukem * POSSIBILITY OF SUCH DAMAGE. 36 1.1 lukem */ 37 1.2 lukem 38 1.20 jmc #if HAVE_NBTOOL_CONFIG_H 39 1.20 jmc #include "nbtool_config.h" 40 1.20 jmc #endif 41 1.20 jmc 42 1.2 lukem #include <sys/cdefs.h> 43 1.13 tv #if defined(__RCSID) && !defined(__lint) 44 1.59 christos __RCSID("$NetBSD: makefs.c,v 1.59 2024/10/27 18:35:52 christos Exp $"); 45 1.2 lukem #endif /* !__lint */ 46 1.10 is 47 1.1 lukem #include <assert.h> 48 1.1 lukem #include <ctype.h> 49 1.1 lukem #include <errno.h> 50 1.5 simonb #include <limits.h> 51 1.1 lukem #include <stdio.h> 52 1.1 lukem #include <stdlib.h> 53 1.1 lukem #include <string.h> 54 1.1 lukem #include <unistd.h> 55 1.36 christos #include <stdbool.h> 56 1.41 christos #include <util.h> 57 1.1 lukem 58 1.1 lukem #include "makefs.h" 59 1.11 lukem #include "mtree.h" 60 1.22 fvdl #include "cd9660.h" 61 1.1 lukem 62 1.1 lukem /* 63 1.1 lukem * list of supported file systems and dispatch functions 64 1.1 lukem */ 65 1.1 lukem typedef struct { 66 1.1 lukem const char *type; 67 1.21 jmc void (*prepare_options)(fsinfo_t *); 68 1.1 lukem int (*parse_options)(const char *, fsinfo_t *); 69 1.21 jmc void (*cleanup_options)(fsinfo_t *); 70 1.1 lukem void (*make_fs)(const char *, const char *, fsnode *, 71 1.1 lukem fsinfo_t *); 72 1.1 lukem } fstype_t; 73 1.1 lukem 74 1.1 lukem static fstype_t fstypes[] = { 75 1.36 christos #define ENTRY(name) { \ 76 1.36 christos # name, name ## _prep_opts, name ## _parse_opts, \ 77 1.36 christos name ## _cleanup_opts, name ## _makefs \ 78 1.36 christos } 79 1.36 christos ENTRY(ffs), 80 1.36 christos ENTRY(cd9660), 81 1.36 christos ENTRY(chfs), 82 1.36 christos ENTRY(v7fs), 83 1.36 christos ENTRY(msdos), 84 1.50 reinoud ENTRY(udf), 85 1.26 christos { .type = NULL }, 86 1.1 lukem }; 87 1.1 lukem 88 1.20 jmc u_int debug; 89 1.1 lukem struct timespec start_time; 90 1.51 christos struct stat stampst; 91 1.1 lukem 92 1.59 christos static fstype_t *get_fstype(const char *); 93 1.51 christos static int get_tstamp(const char *, struct stat *); 94 1.59 christos static void usage(fstype_t *, fsinfo_t *) __dead; 95 1.59 christos static u_int parse_debug(char *); 96 1.1 lukem 97 1.1 lukem int 98 1.1 lukem main(int argc, char *argv[]) 99 1.1 lukem { 100 1.1 lukem struct timeval start; 101 1.1 lukem fstype_t *fstype; 102 1.1 lukem fsinfo_t fsoptions; 103 1.1 lukem fsnode *root; 104 1.57 christos int ch, i; 105 1.57 christos size_t len; 106 1.1 lukem char *specfile; 107 1.8 lukem 108 1.8 lukem setprogname(argv[0]); 109 1.1 lukem 110 1.1 lukem debug = 0; 111 1.1 lukem if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) 112 1.56 tsutsui errx(EXIT_FAILURE, 113 1.56 tsutsui "Unknown default fs type `%s'.", DEFAULT_FSTYPE); 114 1.9 lukem 115 1.9 lukem /* set default fsoptions */ 116 1.1 lukem (void)memset(&fsoptions, 0, sizeof(fsoptions)); 117 1.1 lukem fsoptions.fd = -1; 118 1.9 lukem fsoptions.sectorsize = -1; 119 1.21 jmc 120 1.21 jmc if (fstype->prepare_options) 121 1.21 jmc fstype->prepare_options(&fsoptions); 122 1.9 lukem 123 1.1 lukem specfile = NULL; 124 1.51 christos #ifdef CLOCK_REALTIME 125 1.51 christos ch = clock_gettime(CLOCK_REALTIME, &start_time); 126 1.51 christos #else 127 1.51 christos ch = gettimeofday(&start, NULL); 128 1.51 christos start_time.tv_sec = start.tv_sec; 129 1.51 christos start_time.tv_nsec = start.tv_usec * 1000; 130 1.51 christos #endif 131 1.51 christos if (ch == -1) 132 1.56 tsutsui err(EXIT_FAILURE, "Unable to get system time"); 133 1.13 tv 134 1.1 lukem 135 1.54 simonb while ((ch = getopt(argc, argv, "B:b:d:f:F:LM:m:N:O:o:rs:S:t:T:xZ")) != -1) { 136 1.1 lukem switch (ch) { 137 1.1 lukem 138 1.1 lukem case 'B': 139 1.1 lukem if (strcmp(optarg, "be") == 0 || 140 1.15 lukem strcmp(optarg, "4321") == 0 || 141 1.1 lukem strcmp(optarg, "big") == 0) { 142 1.1 lukem #if BYTE_ORDER == LITTLE_ENDIAN 143 1.1 lukem fsoptions.needswap = 1; 144 1.1 lukem #endif 145 1.1 lukem } else if (strcmp(optarg, "le") == 0 || 146 1.15 lukem strcmp(optarg, "1234") == 0 || 147 1.1 lukem strcmp(optarg, "little") == 0) { 148 1.1 lukem #if BYTE_ORDER == BIG_ENDIAN 149 1.1 lukem fsoptions.needswap = 1; 150 1.1 lukem #endif 151 1.1 lukem } else { 152 1.1 lukem warnx("Invalid endian `%s'.", optarg); 153 1.41 christos usage(fstype, &fsoptions); 154 1.1 lukem } 155 1.1 lukem break; 156 1.1 lukem 157 1.1 lukem case 'b': 158 1.1 lukem len = strlen(optarg) - 1; 159 1.1 lukem if (optarg[len] == '%') { 160 1.1 lukem optarg[len] = '\0'; 161 1.57 christos fsoptions.freeblockpc = (int) 162 1.14 lukem strsuftoll("free block percentage", 163 1.6 lukem optarg, 0, 99); 164 1.1 lukem } else { 165 1.6 lukem fsoptions.freeblocks = 166 1.14 lukem strsuftoll("free blocks", 167 1.6 lukem optarg, 0, LLONG_MAX); 168 1.1 lukem } 169 1.1 lukem break; 170 1.1 lukem 171 1.1 lukem case 'd': 172 1.59 christos debug = parse_debug(optarg); 173 1.1 lukem break; 174 1.1 lukem 175 1.1 lukem case 'f': 176 1.1 lukem len = strlen(optarg) - 1; 177 1.1 lukem if (optarg[len] == '%') { 178 1.1 lukem optarg[len] = '\0'; 179 1.57 christos fsoptions.freefilepc = (int) 180 1.14 lukem strsuftoll("free file percentage", 181 1.6 lukem optarg, 0, 99); 182 1.1 lukem } else { 183 1.6 lukem fsoptions.freefiles = 184 1.14 lukem strsuftoll("free files", 185 1.6 lukem optarg, 0, LLONG_MAX); 186 1.1 lukem } 187 1.1 lukem break; 188 1.1 lukem 189 1.1 lukem case 'F': 190 1.1 lukem specfile = optarg; 191 1.1 lukem break; 192 1.1 lukem 193 1.54 simonb case 'L': 194 1.54 simonb fsoptions.follow = true; 195 1.54 simonb break; 196 1.54 simonb 197 1.1 lukem case 'M': 198 1.6 lukem fsoptions.minsize = 199 1.14 lukem strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); 200 1.1 lukem break; 201 1.1 lukem 202 1.11 lukem case 'N': 203 1.11 lukem if (! setup_getid(optarg)) 204 1.56 tsutsui errx(EXIT_FAILURE, 205 1.11 lukem "Unable to use user and group databases in `%s'", 206 1.11 lukem optarg); 207 1.11 lukem break; 208 1.11 lukem 209 1.1 lukem case 'm': 210 1.6 lukem fsoptions.maxsize = 211 1.14 lukem strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); 212 1.1 lukem break; 213 1.48 christos 214 1.48 christos case 'O': 215 1.55 riastrad fsoptions.offset = 216 1.48 christos strsuftoll("offset", optarg, 0LL, LLONG_MAX); 217 1.48 christos break; 218 1.55 riastrad 219 1.1 lukem case 'o': 220 1.1 lukem { 221 1.1 lukem char *p; 222 1.1 lukem 223 1.1 lukem while ((p = strsep(&optarg, ",")) != NULL) { 224 1.1 lukem if (*p == '\0') 225 1.56 tsutsui errx(EXIT_FAILURE, "Empty option"); 226 1.1 lukem if (! fstype->parse_options(p, &fsoptions)) 227 1.41 christos usage(fstype, &fsoptions); 228 1.1 lukem } 229 1.1 lukem break; 230 1.1 lukem } 231 1.1 lukem 232 1.49 christos case 'r': 233 1.49 christos fsoptions.replace = 1; 234 1.49 christos break; 235 1.49 christos 236 1.1 lukem case 's': 237 1.1 lukem fsoptions.minsize = fsoptions.maxsize = 238 1.14 lukem strsuftoll("size", optarg, 1LL, LLONG_MAX); 239 1.1 lukem break; 240 1.1 lukem 241 1.1 lukem case 'S': 242 1.6 lukem fsoptions.sectorsize = 243 1.14 lukem (int)strsuftoll("sector size", optarg, 244 1.6 lukem 1LL, INT_MAX); 245 1.1 lukem break; 246 1.1 lukem 247 1.1 lukem case 't': 248 1.21 jmc /* Check current one and cleanup if necessary. */ 249 1.21 jmc if (fstype->cleanup_options) 250 1.21 jmc fstype->cleanup_options(&fsoptions); 251 1.21 jmc fsoptions.fs_specific = NULL; 252 1.1 lukem if ((fstype = get_fstype(optarg)) == NULL) 253 1.56 tsutsui errx(EXIT_FAILURE, 254 1.56 tsutsui "Unknown fs type `%s'.", optarg); 255 1.21 jmc fstype->prepare_options(&fsoptions); 256 1.1 lukem break; 257 1.1 lukem 258 1.51 christos case 'T': 259 1.51 christos if (get_tstamp(optarg, &stampst) == -1) 260 1.56 tsutsui errx(EXIT_FAILURE, 261 1.56 tsutsui "Cannot get timestamp from `%s'", optarg); 262 1.51 christos break; 263 1.51 christos 264 1.16 thorpej case 'x': 265 1.58 christos fsoptions.onlyspec++; 266 1.16 thorpej break; 267 1.16 thorpej 268 1.35 sjg case 'Z': 269 1.35 sjg fsoptions.sparse = 1; 270 1.35 sjg break; 271 1.35 sjg 272 1.1 lukem case '?': 273 1.1 lukem default: 274 1.41 christos usage(fstype, &fsoptions); 275 1.1 lukem /* NOTREACHED */ 276 1.1 lukem 277 1.1 lukem } 278 1.1 lukem } 279 1.1 lukem if (debug) { 280 1.1 lukem printf("debug mask: 0x%08x\n", debug); 281 1.1 lukem printf("start time: %ld.%ld, %s", 282 1.3 lukem (long)start_time.tv_sec, (long)start_time.tv_nsec, 283 1.1 lukem ctime(&start_time.tv_sec)); 284 1.1 lukem } 285 1.1 lukem argc -= optind; 286 1.1 lukem argv += optind; 287 1.1 lukem 288 1.31 christos if (argc < 2) 289 1.41 christos usage(fstype, &fsoptions); 290 1.16 thorpej 291 1.16 thorpej /* -x must be accompanied by -F */ 292 1.17 lukem if (fsoptions.onlyspec != 0 && specfile == NULL) 293 1.56 tsutsui errx(EXIT_FAILURE, "-x requires -F mtree-specfile."); 294 1.1 lukem 295 1.1 lukem /* walk the tree */ 296 1.1 lukem TIMER_START(start); 297 1.54 simonb root = walk_dir(argv[1], ".", NULL, NULL, fsoptions.replace, 298 1.54 simonb fsoptions.follow); 299 1.1 lukem TIMER_RESULTS(start, "walk_dir"); 300 1.1 lukem 301 1.31 christos /* append extra directory */ 302 1.31 christos for (i = 2; i < argc; i++) { 303 1.31 christos struct stat sb; 304 1.31 christos if (stat(argv[i], &sb) == -1) 305 1.56 tsutsui err(EXIT_FAILURE, "Can't stat `%s'", argv[i]); 306 1.31 christos if (!S_ISDIR(sb.st_mode)) 307 1.56 tsutsui errx(EXIT_FAILURE, "%s: not a directory", argv[i]); 308 1.31 christos TIMER_START(start); 309 1.54 simonb root = walk_dir(argv[i], ".", NULL, root, fsoptions.replace, 310 1.54 simonb fsoptions.follow); 311 1.31 christos TIMER_RESULTS(start, "walk_dir2"); 312 1.31 christos } 313 1.31 christos 314 1.1 lukem if (specfile) { /* apply a specfile */ 315 1.1 lukem TIMER_START(start); 316 1.25 dbj apply_specfile(specfile, argv[1], root, fsoptions.onlyspec); 317 1.1 lukem TIMER_RESULTS(start, "apply_specfile"); 318 1.1 lukem } 319 1.1 lukem 320 1.1 lukem if (debug & DEBUG_DUMP_FSNODES) { 321 1.12 lukem printf("\nparent: %s\n", argv[1]); 322 1.31 christos dump_fsnodes(root); 323 1.1 lukem putchar('\n'); 324 1.1 lukem } 325 1.1 lukem 326 1.1 lukem /* build the file system */ 327 1.1 lukem TIMER_START(start); 328 1.1 lukem fstype->make_fs(argv[0], argv[1], root, &fsoptions); 329 1.1 lukem TIMER_RESULTS(start, "make_fs"); 330 1.1 lukem 331 1.24 dbj free_fsnodes(root); 332 1.24 dbj 333 1.56 tsutsui exit(EXIT_SUCCESS); 334 1.1 lukem /* NOTREACHED */ 335 1.1 lukem } 336 1.1 lukem 337 1.37 christos int 338 1.44 christos set_option(const option_t *options, const char *option, char *buf, size_t len) 339 1.37 christos { 340 1.37 christos char *var, *val; 341 1.37 christos int retval; 342 1.37 christos 343 1.37 christos assert(option != NULL); 344 1.37 christos 345 1.41 christos var = estrdup(option); 346 1.43 christos for (val = var; *val; val++) 347 1.43 christos if (*val == '=') { 348 1.43 christos *val++ = '\0'; 349 1.43 christos break; 350 1.43 christos } 351 1.44 christos retval = set_option_var(options, var, val, buf, len); 352 1.37 christos free(var); 353 1.37 christos return retval; 354 1.37 christos } 355 1.1 lukem 356 1.57 christos void 357 1.57 christos print_options(FILE *fp, const option_t *options) 358 1.57 christos { 359 1.57 christos for (size_t i = 0; options[i].name != NULL; i++) { 360 1.57 christos fprintf(fp, "%s=", options[i].name); 361 1.57 christos switch (options[i].type) { 362 1.57 christos case OPT_BOOL: 363 1.57 christos fputs(*(bool *)options[i].value ? "true\n" : "false\n", 364 1.57 christos fp); 365 1.57 christos break; 366 1.57 christos case OPT_STRARRAY: 367 1.57 christos case OPT_STRPTR: 368 1.57 christos case OPT_STRBUF: 369 1.57 christos fprintf(fp, "%s\n", *(const char **)options[i].value); 370 1.57 christos break; 371 1.57 christos case OPT_INT64: 372 1.57 christos fprintf(fp, "%" PRIu64 "\n", 373 1.57 christos *(uint64_t *)options[i].value); 374 1.57 christos break; 375 1.57 christos case OPT_INT32: 376 1.57 christos fprintf(fp, "%" PRIu32 "\n", 377 1.57 christos *(uint32_t *)options[i].value); 378 1.57 christos break; 379 1.57 christos case OPT_INT16: 380 1.57 christos fprintf(fp, "%" PRIu16 "\n", 381 1.57 christos *(uint16_t *)options[i].value); 382 1.57 christos break; 383 1.57 christos case OPT_INT8: 384 1.57 christos fprintf(fp, "%" PRIu8 "\n", 385 1.57 christos *(uint8_t *)options[i].value); 386 1.57 christos break; 387 1.57 christos default: 388 1.57 christos warnx("Unknown type %d in option %s", options[i].type, 389 1.57 christos options[i].name); 390 1.57 christos return; 391 1.57 christos } 392 1.57 christos } 393 1.57 christos } 394 1.57 christos 395 1.1 lukem int 396 1.44 christos set_option_var(const option_t *options, const char *var, const char *val, 397 1.44 christos char *buf, size_t len) 398 1.1 lukem { 399 1.36 christos char *s; 400 1.36 christos size_t i; 401 1.36 christos 402 1.46 christos #define NUM(type) \ 403 1.45 christos if (!*val) { \ 404 1.46 christos *(type *)options[i].value = 1; \ 405 1.43 christos break; \ 406 1.43 christos } \ 407 1.46 christos *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ 408 1.43 christos options[i].minimum, options[i].maximum); break 409 1.1 lukem 410 1.1 lukem for (i = 0; options[i].name != NULL; i++) { 411 1.40 christos if (var[1] == '\0') { 412 1.40 christos if (options[i].letter != var[0]) 413 1.40 christos continue; 414 1.40 christos } else if (strcmp(options[i].name, var) != 0) 415 1.1 lukem continue; 416 1.36 christos switch (options[i].type) { 417 1.36 christos case OPT_BOOL: 418 1.36 christos *(bool *)options[i].value = 1; 419 1.36 christos break; 420 1.36 christos case OPT_STRARRAY: 421 1.36 christos strlcpy((void *)options[i].value, val, (size_t) 422 1.36 christos options[i].maximum); 423 1.36 christos break; 424 1.36 christos case OPT_STRPTR: 425 1.41 christos s = estrdup(val); 426 1.36 christos *(char **)options[i].value = s; 427 1.36 christos break; 428 1.44 christos case OPT_STRBUF: 429 1.44 christos if (buf == NULL) 430 1.44 christos abort(); 431 1.44 christos strlcpy(buf, val, len); 432 1.44 christos break; 433 1.36 christos case OPT_INT64: 434 1.46 christos NUM(uint64_t); 435 1.36 christos case OPT_INT32: 436 1.46 christos NUM(uint32_t); 437 1.36 christos case OPT_INT16: 438 1.46 christos NUM(uint16_t); 439 1.36 christos case OPT_INT8: 440 1.46 christos NUM(uint8_t); 441 1.36 christos default: 442 1.36 christos warnx("Unknown type %d in option %s", options[i].type, 443 1.36 christos val); 444 1.36 christos return 0; 445 1.36 christos } 446 1.57 christos return (int)i; 447 1.1 lukem } 448 1.1 lukem warnx("Unknown option `%s'", var); 449 1.39 christos return -1; 450 1.1 lukem } 451 1.1 lukem 452 1.1 lukem 453 1.1 lukem static fstype_t * 454 1.1 lukem get_fstype(const char *type) 455 1.1 lukem { 456 1.1 lukem int i; 457 1.55 riastrad 458 1.1 lukem for (i = 0; fstypes[i].type != NULL; i++) 459 1.1 lukem if (strcmp(fstypes[i].type, type) == 0) 460 1.1 lukem return (&fstypes[i]); 461 1.1 lukem return (NULL); 462 1.1 lukem } 463 1.1 lukem 464 1.41 christos option_t * 465 1.41 christos copy_opts(const option_t *o) 466 1.41 christos { 467 1.41 christos size_t i; 468 1.41 christos for (i = 0; o[i].name; i++) 469 1.41 christos continue; 470 1.41 christos i++; 471 1.41 christos return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); 472 1.41 christos } 473 1.41 christos 474 1.51 christos static int 475 1.51 christos get_tstamp(const char *b, struct stat *st) 476 1.51 christos { 477 1.51 christos time_t when; 478 1.51 christos char *eb; 479 1.51 christos long long l; 480 1.51 christos 481 1.51 christos if (stat(b, st) != -1) 482 1.51 christos return 0; 483 1.51 christos 484 1.51 christos #ifndef HAVE_NBTOOL_CONFIG_H 485 1.51 christos errno = 0; 486 1.53 joerg if ((when = parsedate(b, NULL, NULL)) == -1 && errno != 0) 487 1.51 christos #endif 488 1.51 christos { 489 1.51 christos errno = 0; 490 1.51 christos l = strtoll(b, &eb, 0); 491 1.51 christos if (b == eb || *eb || errno) 492 1.51 christos return -1; 493 1.51 christos when = (time_t)l; 494 1.51 christos } 495 1.51 christos 496 1.51 christos st->st_ino = 1; 497 1.55 riastrad #if HAVE_STRUCT_STAT_BIRTHTIME 498 1.51 christos st->st_birthtime = 499 1.51 christos #endif 500 1.51 christos st->st_mtime = st->st_ctime = st->st_atime = when; 501 1.51 christos return 0; 502 1.51 christos } 503 1.51 christos 504 1.59 christos static struct { 505 1.59 christos const char *n; 506 1.59 christos u_int v; 507 1.59 christos } nv[] = { 508 1.59 christos DEBUG_STRINGS 509 1.59 christos }; 510 1.59 christos 511 1.1 lukem static void 512 1.41 christos usage(fstype_t *fstype, fsinfo_t *fsoptions) 513 1.1 lukem { 514 1.1 lukem const char *prog; 515 1.1 lukem 516 1.1 lukem prog = getprogname(); 517 1.1 lukem fprintf(stderr, 518 1.59 christos "Usage: %s [-rxZ] [-B endian] [-b free-blocks] [-d debug-mask|comma-separated-option]\n" 519 1.48 christos "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" 520 1.48 christos "\t[-N userdb-dir] [-O offset] [-o fs-options] [-S sector-size]\n" 521 1.52 wiz "\t[-s image-size] [-T <timestamp/file>] [-t fs-type]" 522 1.51 christos " image-file directory [extra-directory ...]\n", 523 1.1 lukem prog); 524 1.41 christos 525 1.59 christos fprintf(stderr, "\nDebugging options:\n"); 526 1.59 christos for (size_t i = 0; i < __arraycount(nv); i++) 527 1.59 christos fprintf(stderr, "\t0x%8.8x\t%s\n", nv[i].v, nv[i].n); 528 1.59 christos 529 1.41 christos if (fstype) { 530 1.41 christos size_t i; 531 1.41 christos option_t *o = fsoptions->fs_options; 532 1.41 christos 533 1.41 christos fprintf(stderr, "\n%s specific options:\n", fstype->type); 534 1.41 christos for (i = 0; o[i].name != NULL; i++) 535 1.42 christos fprintf(stderr, "\t%c%c%20.20s\t%s\n", 536 1.42 christos o[i].letter ? o[i].letter : ' ', 537 1.42 christos o[i].letter ? ',' : ' ', 538 1.41 christos o[i].name, o[i].desc); 539 1.41 christos } 540 1.56 tsutsui exit(EXIT_FAILURE); 541 1.1 lukem } 542 1.59 christos 543 1.59 christos 544 1.59 christos static u_int 545 1.59 christos parse_debug(char *str) 546 1.59 christos { 547 1.59 christos char *ep; 548 1.59 christos u_int d; 549 1.59 christos size_t i; 550 1.59 christos 551 1.59 christos errno = 0; 552 1.59 christos d = (u_int)strtoul(str, &ep, 0); 553 1.59 christos if (str != ep && !*ep && errno == 0) 554 1.59 christos return d; 555 1.59 christos d = 0; 556 1.59 christos for (char *a = strtok(str, ","); a != NULL; a = strtok(NULL, ",")) { 557 1.59 christos for (i = 0; i < __arraycount(nv); i++) 558 1.59 christos if (strcmp(nv[i].n, a) == 0) { 559 1.59 christos d |= nv[i].v; 560 1.59 christos break; 561 1.59 christos } 562 1.59 christos if (i == __arraycount(nv)) 563 1.59 christos errx(EXIT_FAILURE, "Unknown debug option `%s'", a); 564 1.59 christos } 565 1.59 christos return d; 566 1.59 christos } 567 1.59 christos 568