xref: /dflybsd-src/usr.sbin/makefs/makefs.c (revision 70e962f72e588a76ccc2d1efabbe00ff5a7203a5)
15978408cSSascha Wildner /*	$NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $	*/
25978408cSSascha Wildner 
35978408cSSascha Wildner /*-
45978408cSSascha Wildner  * SPDX-License-Identifier: BSD-4-Clause
55978408cSSascha Wildner  *
65978408cSSascha Wildner  * Copyright (c) 2001-2003 Wasabi Systems, Inc.
75978408cSSascha Wildner  * All rights reserved.
85978408cSSascha Wildner  *
95978408cSSascha Wildner  * Written by Luke Mewburn for Wasabi Systems, Inc.
105978408cSSascha Wildner  *
115978408cSSascha Wildner  * Redistribution and use in source and binary forms, with or without
125978408cSSascha Wildner  * modification, are permitted provided that the following conditions
135978408cSSascha Wildner  * are met:
145978408cSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
155978408cSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
165978408cSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
175978408cSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
185978408cSSascha Wildner  *    documentation and/or other materials provided with the distribution.
195978408cSSascha Wildner  * 3. All advertising materials mentioning features or use of this software
205978408cSSascha Wildner  *    must display the following acknowledgement:
215978408cSSascha Wildner  *      This product includes software developed for the NetBSD Project by
225978408cSSascha Wildner  *      Wasabi Systems, Inc.
235978408cSSascha Wildner  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
245978408cSSascha Wildner  *    or promote products derived from this software without specific prior
255978408cSSascha Wildner  *    written permission.
265978408cSSascha Wildner  *
275978408cSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
285978408cSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
295978408cSSascha Wildner  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
305978408cSSascha Wildner  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
315978408cSSascha Wildner  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
325978408cSSascha Wildner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
335978408cSSascha Wildner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
345978408cSSascha Wildner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
355978408cSSascha Wildner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
365978408cSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
375978408cSSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
38811c2036SSascha Wildner  *
39811c2036SSascha Wildner  * $FreeBSD: head/usr.sbin/makefs/makefs.c 326276 2017-11-27 15:37:16Z pfg $
405978408cSSascha Wildner  */
415978408cSSascha Wildner 
425978408cSSascha Wildner #include <sys/types.h>
435978408cSSascha Wildner #include <sys/stat.h>
445978408cSSascha Wildner #include <assert.h>
455978408cSSascha Wildner #include <ctype.h>
465978408cSSascha Wildner #include <errno.h>
475978408cSSascha Wildner #include <limits.h>
485978408cSSascha Wildner #include <stdio.h>
495978408cSSascha Wildner #include <stdlib.h>
505978408cSSascha Wildner #include <string.h>
515978408cSSascha Wildner #include <time.h>
525978408cSSascha Wildner #include <unistd.h>
535978408cSSascha Wildner #include <stdbool.h>
545978408cSSascha Wildner #include <util.h>
555978408cSSascha Wildner 
565978408cSSascha Wildner #include "makefs.h"
575978408cSSascha Wildner #include "mtree.h"
585978408cSSascha Wildner 
595978408cSSascha Wildner /*
605978408cSSascha Wildner  * list of supported file systems and dispatch functions
615978408cSSascha Wildner  */
625978408cSSascha Wildner typedef struct {
635978408cSSascha Wildner 	const char	*type;
645978408cSSascha Wildner 	void		(*prepare_options)(fsinfo_t *);
655978408cSSascha Wildner 	int		(*parse_options)(const char *, fsinfo_t *);
665978408cSSascha Wildner 	void		(*cleanup_options)(fsinfo_t *);
675978408cSSascha Wildner 	void		(*make_fs)(const char *, const char *, fsnode *,
685978408cSSascha Wildner 				fsinfo_t *);
695978408cSSascha Wildner } fstype_t;
705978408cSSascha Wildner 
715978408cSSascha Wildner static fstype_t fstypes[] = {
725978408cSSascha Wildner #define ENTRY(name) { \
735978408cSSascha Wildner 	# name, name ## _prep_opts, name ## _parse_opts, \
745978408cSSascha Wildner 	name ## _cleanup_opts, name ## _makefs  \
755978408cSSascha Wildner }
765978408cSSascha Wildner 	ENTRY(ffs),
775978408cSSascha Wildner 	ENTRY(cd9660),
7820f6ddd0STomohiro Kusumi 	ENTRY(msdos),
792d60b848STomohiro Kusumi 	ENTRY(hammer2),
805978408cSSascha Wildner 	{ .type = NULL	},
815978408cSSascha Wildner };
825978408cSSascha Wildner 
835978408cSSascha Wildner u_int		debug;
845978408cSSascha Wildner int		dupsok;
855978408cSSascha Wildner struct timespec	start_time;
865978408cSSascha Wildner struct stat stampst;
875978408cSSascha Wildner 
885978408cSSascha Wildner static	fstype_t *get_fstype(const char *);
895978408cSSascha Wildner static int get_tstamp(const char *, struct stat *);
905978408cSSascha Wildner static	void	usage(fstype_t *, fsinfo_t *);
915978408cSSascha Wildner 
925978408cSSascha Wildner int
main(int argc,char * argv[])935978408cSSascha Wildner main(int argc, char *argv[])
945978408cSSascha Wildner {
955978408cSSascha Wildner 	struct stat	 sb;
965978408cSSascha Wildner 	struct timeval	 start;
975978408cSSascha Wildner 	fstype_t	*fstype;
985978408cSSascha Wildner 	fsinfo_t	 fsoptions;
99a63188c8STomohiro Kusumi 	fsnode		*root = NULL;
1005978408cSSascha Wildner 	int		 ch, i, len;
101*70e962f7STomohiro Kusumi 	const char	*subtree = NULL;
1025978408cSSascha Wildner 	const char	*specfile;
1035978408cSSascha Wildner 
1045978408cSSascha Wildner 	setprogname(argv[0]);
1055978408cSSascha Wildner 
1065978408cSSascha Wildner 	debug = 0;
1075978408cSSascha Wildner 	if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
1085978408cSSascha Wildner 		errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
1095978408cSSascha Wildner 
1105978408cSSascha Wildner 		/* set default fsoptions */
1115978408cSSascha Wildner 	(void)memset(&fsoptions, 0, sizeof(fsoptions));
1125978408cSSascha Wildner 	fsoptions.fd = -1;
1135978408cSSascha Wildner 	fsoptions.sectorsize = -1;
1145978408cSSascha Wildner 
1155978408cSSascha Wildner 	if (fstype->prepare_options)
1165978408cSSascha Wildner 		fstype->prepare_options(&fsoptions);
1175978408cSSascha Wildner 
1185978408cSSascha Wildner 	specfile = NULL;
1195978408cSSascha Wildner #ifdef CLOCK_REALTIME
1205978408cSSascha Wildner 	ch = clock_gettime(CLOCK_REALTIME, &start_time);
1215978408cSSascha Wildner #else
1225978408cSSascha Wildner 	ch = gettimeofday(&start, NULL);
1235978408cSSascha Wildner 	start_time.tv_sec = start.tv_sec;
1245978408cSSascha Wildner 	start_time.tv_nsec = start.tv_usec * 1000;
1255978408cSSascha Wildner #endif
1265978408cSSascha Wildner 	if (ch == -1)
1275978408cSSascha Wildner 		err(1, "Unable to get system time");
1285978408cSSascha Wildner 
1295978408cSSascha Wildner 
1305978408cSSascha Wildner 	while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:O:o:pR:s:S:t:T:xZ")) != -1) {
1315978408cSSascha Wildner 		switch (ch) {
1325978408cSSascha Wildner 
1335978408cSSascha Wildner 		case 'B':
1345978408cSSascha Wildner 			if (strcmp(optarg, "be") == 0 ||
1355978408cSSascha Wildner 			    strcmp(optarg, "4321") == 0 ||
1365978408cSSascha Wildner 			    strcmp(optarg, "big") == 0) {
1375978408cSSascha Wildner #if BYTE_ORDER == LITTLE_ENDIAN
1385978408cSSascha Wildner 				fsoptions.needswap = 1;
1395978408cSSascha Wildner #endif
1405978408cSSascha Wildner 			} else if (strcmp(optarg, "le") == 0 ||
1415978408cSSascha Wildner 			    strcmp(optarg, "1234") == 0 ||
1425978408cSSascha Wildner 			    strcmp(optarg, "little") == 0) {
1435978408cSSascha Wildner #if BYTE_ORDER == BIG_ENDIAN
1445978408cSSascha Wildner 				fsoptions.needswap = 1;
1455978408cSSascha Wildner #endif
1465978408cSSascha Wildner 			} else {
1475978408cSSascha Wildner 				warnx("Invalid endian `%s'.", optarg);
1485978408cSSascha Wildner 				usage(fstype, &fsoptions);
1495978408cSSascha Wildner 			}
1505978408cSSascha Wildner 			break;
1515978408cSSascha Wildner 
1525978408cSSascha Wildner 		case 'b':
1535978408cSSascha Wildner 			len = strlen(optarg) - 1;
1545978408cSSascha Wildner 			if (optarg[len] == '%') {
1555978408cSSascha Wildner 				optarg[len] = '\0';
1565978408cSSascha Wildner 				fsoptions.freeblockpc =
1575978408cSSascha Wildner 				    strsuftoll("free block percentage",
1585978408cSSascha Wildner 					optarg, 0, 99);
1595978408cSSascha Wildner 			} else {
1605978408cSSascha Wildner 				fsoptions.freeblocks =
1615978408cSSascha Wildner 				    strsuftoll("free blocks",
1625978408cSSascha Wildner 					optarg, 0, LLONG_MAX);
1635978408cSSascha Wildner 			}
1645978408cSSascha Wildner 			break;
1655978408cSSascha Wildner 
1665978408cSSascha Wildner 		case 'D':
1675978408cSSascha Wildner 			dupsok = 1;
1685978408cSSascha Wildner 			break;
1695978408cSSascha Wildner 
1705978408cSSascha Wildner 		case 'd':
1715978408cSSascha Wildner 			debug = strtoll(optarg, NULL, 0);
1725978408cSSascha Wildner 			break;
1735978408cSSascha Wildner 
1745978408cSSascha Wildner 		case 'f':
1755978408cSSascha Wildner 			len = strlen(optarg) - 1;
1765978408cSSascha Wildner 			if (optarg[len] == '%') {
1775978408cSSascha Wildner 				optarg[len] = '\0';
1785978408cSSascha Wildner 				fsoptions.freefilepc =
1795978408cSSascha Wildner 				    strsuftoll("free file percentage",
1805978408cSSascha Wildner 					optarg, 0, 99);
1815978408cSSascha Wildner 			} else {
1825978408cSSascha Wildner 				fsoptions.freefiles =
1835978408cSSascha Wildner 				    strsuftoll("free files",
1845978408cSSascha Wildner 					optarg, 0, LLONG_MAX);
1855978408cSSascha Wildner 			}
1865978408cSSascha Wildner 			break;
1875978408cSSascha Wildner 
1885978408cSSascha Wildner 		case 'F':
1895978408cSSascha Wildner 			specfile = optarg;
1905978408cSSascha Wildner 			break;
1915978408cSSascha Wildner 
1925978408cSSascha Wildner 		case 'M':
1935978408cSSascha Wildner 			fsoptions.minsize =
1945978408cSSascha Wildner 			    strsuftoll("minimum size", optarg, 1LL, LLONG_MAX);
1955978408cSSascha Wildner 			break;
1965978408cSSascha Wildner 
1975978408cSSascha Wildner 		case 'N':
1985978408cSSascha Wildner 			if (! setup_getid(optarg))
1995978408cSSascha Wildner 				errx(1,
2005978408cSSascha Wildner 			    "Unable to use user and group databases in `%s'",
2015978408cSSascha Wildner 				    optarg);
2025978408cSSascha Wildner 			break;
2035978408cSSascha Wildner 
2045978408cSSascha Wildner 		case 'm':
2055978408cSSascha Wildner 			fsoptions.maxsize =
2065978408cSSascha Wildner 			    strsuftoll("maximum size", optarg, 1LL, LLONG_MAX);
2075978408cSSascha Wildner 			break;
2085978408cSSascha Wildner 
2095978408cSSascha Wildner 		case 'O':
2105978408cSSascha Wildner 			fsoptions.offset =
2115978408cSSascha Wildner 			    strsuftoll("offset", optarg, 0LL, LLONG_MAX);
2125978408cSSascha Wildner 			break;
2135978408cSSascha Wildner 
2145978408cSSascha Wildner 		case 'o':
2155978408cSSascha Wildner 		{
2165978408cSSascha Wildner 			char *p;
2175978408cSSascha Wildner 
2185978408cSSascha Wildner 			while ((p = strsep(&optarg, ",")) != NULL) {
2195978408cSSascha Wildner 				if (*p == '\0')
2205978408cSSascha Wildner 					errx(1, "Empty option");
2215978408cSSascha Wildner 				if (! fstype->parse_options(p, &fsoptions))
2225978408cSSascha Wildner 					usage(fstype, &fsoptions);
2235978408cSSascha Wildner 			}
2245978408cSSascha Wildner 			break;
2255978408cSSascha Wildner 		}
2265978408cSSascha Wildner 		case 'p':
2275978408cSSascha Wildner 			/* Deprecated in favor of 'Z' */
2285978408cSSascha Wildner 			fsoptions.sparse = 1;
2295978408cSSascha Wildner 			break;
2305978408cSSascha Wildner 
2315978408cSSascha Wildner 		case 'R':
2325978408cSSascha Wildner 			/* Round image size up to specified block size */
2335978408cSSascha Wildner 			fsoptions.roundup =
2345978408cSSascha Wildner 			    strsuftoll("roundup-size", optarg, 0, LLONG_MAX);
2355978408cSSascha Wildner 			break;
2365978408cSSascha Wildner 
2375978408cSSascha Wildner 		case 's':
2385978408cSSascha Wildner 			fsoptions.minsize = fsoptions.maxsize =
2395978408cSSascha Wildner 			    strsuftoll("size", optarg, 1LL, LLONG_MAX);
2405978408cSSascha Wildner 			break;
2415978408cSSascha Wildner 
2425978408cSSascha Wildner 		case 'S':
2435978408cSSascha Wildner 			fsoptions.sectorsize =
2445978408cSSascha Wildner 			    (int)strsuftoll("sector size", optarg,
2455978408cSSascha Wildner 				1LL, INT_MAX);
2465978408cSSascha Wildner 			break;
2475978408cSSascha Wildner 
2485978408cSSascha Wildner 		case 't':
2495978408cSSascha Wildner 			/* Check current one and cleanup if necessary. */
2505978408cSSascha Wildner 			if (fstype->cleanup_options)
2515978408cSSascha Wildner 				fstype->cleanup_options(&fsoptions);
2525978408cSSascha Wildner 			fsoptions.fs_specific = NULL;
2535978408cSSascha Wildner 			if ((fstype = get_fstype(optarg)) == NULL)
2545978408cSSascha Wildner 				errx(1, "Unknown fs type `%s'.", optarg);
2555978408cSSascha Wildner 			fstype->prepare_options(&fsoptions);
2565978408cSSascha Wildner 			break;
2575978408cSSascha Wildner 
2585978408cSSascha Wildner 		case 'T':
2595978408cSSascha Wildner 			if (get_tstamp(optarg, &stampst) == -1)
2605978408cSSascha Wildner 				errx(1, "Cannot get timestamp from `%s'",
2615978408cSSascha Wildner 				    optarg);
2625978408cSSascha Wildner 			break;
2635978408cSSascha Wildner 
2645978408cSSascha Wildner 		case 'x':
2655978408cSSascha Wildner 			fsoptions.onlyspec = 1;
2665978408cSSascha Wildner 			break;
2675978408cSSascha Wildner 
2685978408cSSascha Wildner 		case 'Z':
2695978408cSSascha Wildner 			/* Superscedes 'p' for compatibility with NetBSD makefs(8) */
2705978408cSSascha Wildner 			fsoptions.sparse = 1;
2715978408cSSascha Wildner 			break;
2725978408cSSascha Wildner 
2735978408cSSascha Wildner 		case '?':
2745978408cSSascha Wildner 		default:
2755978408cSSascha Wildner 			usage(fstype, &fsoptions);
2765978408cSSascha Wildner 			/* NOTREACHED */
2775978408cSSascha Wildner 
2785978408cSSascha Wildner 		}
2795978408cSSascha Wildner 	}
2805978408cSSascha Wildner 	if (debug) {
2815978408cSSascha Wildner 		printf("debug mask: 0x%08x\n", debug);
2825978408cSSascha Wildner 		printf("start time: %ld.%ld, %s",
2835978408cSSascha Wildner 		    (long)start_time.tv_sec, (long)start_time.tv_nsec,
2845978408cSSascha Wildner 		    ctime(&start_time.tv_sec));
2855978408cSSascha Wildner 	}
2865978408cSSascha Wildner 	argc -= optind;
2875978408cSSascha Wildner 	argv += optind;
2885978408cSSascha Wildner 
2895978408cSSascha Wildner 	if (argc < 2)
2905978408cSSascha Wildner 		usage(fstype, &fsoptions);
2915978408cSSascha Wildner 
2925978408cSSascha Wildner 	/* -x must be accompanied by -F */
2935978408cSSascha Wildner 	if (fsoptions.onlyspec != 0 && specfile == NULL)
2945978408cSSascha Wildner 		errx(1, "-x requires -F mtree-specfile.");
2955978408cSSascha Wildner 
2965978408cSSascha Wildner 	/* Accept '-' as meaning "read from standard input". */
297917508cdSTomohiro Kusumi 	/* DragonFly: Accept '--' as meaning none for HAMMER2 ioctl commands. */
298a63188c8STomohiro Kusumi 	if (strcmp(argv[1], "--") == 0) {
299a63188c8STomohiro Kusumi 		if (!strcmp(fstype->type, "hammer2"))
300a63188c8STomohiro Kusumi 			goto ignore_walk_dir;
301a63188c8STomohiro Kusumi 		else
302a63188c8STomohiro Kusumi 			errx(1, "%s: invalid argument", argv[1]);
303a63188c8STomohiro Kusumi 	} else if (strcmp(argv[1], "-") == 0) {
3045978408cSSascha Wildner 		sb.st_mode = S_IFREG;
305a63188c8STomohiro Kusumi 	} else {
3065978408cSSascha Wildner 		if (stat(argv[1], &sb) == -1)
3075978408cSSascha Wildner 			err(1, "Can't stat `%s'", argv[1]);
3085978408cSSascha Wildner 	}
3095978408cSSascha Wildner 
3105978408cSSascha Wildner 	switch (sb.st_mode & S_IFMT) {
3115978408cSSascha Wildner 	case S_IFDIR:		/* walk the tree */
3125978408cSSascha Wildner 		subtree = argv[1];
3135978408cSSascha Wildner 		TIMER_START(start);
3145978408cSSascha Wildner 		root = walk_dir(subtree, ".", NULL, NULL);
3155978408cSSascha Wildner 		TIMER_RESULTS(start, "walk_dir");
3165978408cSSascha Wildner 		break;
3175978408cSSascha Wildner 	case S_IFREG:		/* read the manifest file */
3185978408cSSascha Wildner 		subtree = ".";
3195978408cSSascha Wildner 		TIMER_START(start);
3205978408cSSascha Wildner 		root = read_mtree(argv[1], NULL);
3215978408cSSascha Wildner 		TIMER_RESULTS(start, "manifest");
3225978408cSSascha Wildner 		break;
3235978408cSSascha Wildner 	default:
3245978408cSSascha Wildner 		errx(1, "%s: not a file or directory", argv[1]);
3255978408cSSascha Wildner 		/* NOTREACHED */
3265978408cSSascha Wildner 	}
3275978408cSSascha Wildner 
3285978408cSSascha Wildner 	/* append extra directory */
3295978408cSSascha Wildner 	for (i = 2; i < argc; i++) {
3305978408cSSascha Wildner 		if (stat(argv[i], &sb) == -1)
3315978408cSSascha Wildner 			err(1, "Can't stat `%s'", argv[i]);
3325978408cSSascha Wildner 		if (!S_ISDIR(sb.st_mode))
3335978408cSSascha Wildner 			errx(1, "%s: not a directory", argv[i]);
3345978408cSSascha Wildner 		TIMER_START(start);
3355978408cSSascha Wildner 		root = walk_dir(argv[i], ".", NULL, root);
3365978408cSSascha Wildner 		TIMER_RESULTS(start, "walk_dir2");
3375978408cSSascha Wildner 	}
3385978408cSSascha Wildner 
3395978408cSSascha Wildner 	if (specfile) {		/* apply a specfile */
3405978408cSSascha Wildner 		TIMER_START(start);
3415978408cSSascha Wildner 		apply_specfile(specfile, subtree, root, fsoptions.onlyspec);
3425978408cSSascha Wildner 		TIMER_RESULTS(start, "apply_specfile");
3435978408cSSascha Wildner 	}
3445978408cSSascha Wildner 
3455978408cSSascha Wildner 	if (debug & DEBUG_DUMP_FSNODES) {
3465978408cSSascha Wildner 		printf("\nparent: %s\n", subtree);
3475978408cSSascha Wildner 		dump_fsnodes(root);
3485978408cSSascha Wildner 		putchar('\n');
3495978408cSSascha Wildner 	}
350a63188c8STomohiro Kusumi ignore_walk_dir:
3515978408cSSascha Wildner 				/* build the file system */
3525978408cSSascha Wildner 	TIMER_START(start);
3535978408cSSascha Wildner 	fstype->make_fs(argv[0], subtree, root, &fsoptions);
3545978408cSSascha Wildner 	TIMER_RESULTS(start, "make_fs");
3555978408cSSascha Wildner 
3565978408cSSascha Wildner 	free_fsnodes(root);
3575978408cSSascha Wildner 
3585978408cSSascha Wildner 	exit(0);
3595978408cSSascha Wildner 	/* NOTREACHED */
3605978408cSSascha Wildner }
3615978408cSSascha Wildner 
3625978408cSSascha Wildner int
set_option(const option_t * options,const char * option,char * buf,size_t len)3635978408cSSascha Wildner set_option(const option_t *options, const char *option, char *buf, size_t len)
3645978408cSSascha Wildner {
3655978408cSSascha Wildner 	char *var, *val;
3665978408cSSascha Wildner 	int retval;
3675978408cSSascha Wildner 
3685978408cSSascha Wildner 	assert(option != NULL);
3695978408cSSascha Wildner 
3705978408cSSascha Wildner 	var = estrdup(option);
3715978408cSSascha Wildner 	for (val = var; *val; val++)
3725978408cSSascha Wildner 		if (*val == '=') {
3735978408cSSascha Wildner 			*val++ = '\0';
3745978408cSSascha Wildner 			break;
3755978408cSSascha Wildner 		}
3765978408cSSascha Wildner 	retval = set_option_var(options, var, val, buf, len);
3775978408cSSascha Wildner 	free(var);
3785978408cSSascha Wildner 	return retval;
3795978408cSSascha Wildner }
3805978408cSSascha Wildner 
3815978408cSSascha Wildner int
set_option_var(const option_t * options,const char * var,const char * val,char * buf,size_t len)3825978408cSSascha Wildner set_option_var(const option_t *options, const char *var, const char *val,
3835978408cSSascha Wildner     char *buf, size_t len)
3845978408cSSascha Wildner {
3855978408cSSascha Wildner 	char *s;
3865978408cSSascha Wildner 	size_t i;
3875978408cSSascha Wildner 
3885978408cSSascha Wildner #define NUM(type) \
3895978408cSSascha Wildner 	if (!*val) { \
3905978408cSSascha Wildner 		*(type *)options[i].value = 1; \
3915978408cSSascha Wildner 		break; \
3925978408cSSascha Wildner 	} \
3935978408cSSascha Wildner 	*(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \
3945978408cSSascha Wildner 	    options[i].minimum, options[i].maximum); break
3955978408cSSascha Wildner 
3965978408cSSascha Wildner 	for (i = 0; options[i].name != NULL; i++) {
3975978408cSSascha Wildner 		if (var[1] == '\0') {
3985978408cSSascha Wildner 			if (options[i].letter != var[0])
3995978408cSSascha Wildner 				continue;
4005978408cSSascha Wildner 		} else if (strcmp(options[i].name, var) != 0)
4015978408cSSascha Wildner 			continue;
4025978408cSSascha Wildner 		switch (options[i].type) {
4035978408cSSascha Wildner 		case OPT_BOOL:
4045978408cSSascha Wildner 			*(bool *)options[i].value = 1;
4055978408cSSascha Wildner 			break;
4065978408cSSascha Wildner 		case OPT_STRARRAY:
4075978408cSSascha Wildner 			strlcpy((void *)options[i].value, val, (size_t)
4085978408cSSascha Wildner 			    options[i].maximum);
4095978408cSSascha Wildner 			break;
4105978408cSSascha Wildner 		case OPT_STRPTR:
4115978408cSSascha Wildner 			s = estrdup(val);
4125978408cSSascha Wildner 			*(char **)options[i].value = s;
4135978408cSSascha Wildner 			break;
4145978408cSSascha Wildner 		case OPT_STRBUF:
4155978408cSSascha Wildner 			if (buf == NULL)
4165978408cSSascha Wildner 				abort();
4175978408cSSascha Wildner 			strlcpy(buf, val, len);
4185978408cSSascha Wildner 			break;
4195978408cSSascha Wildner 		case OPT_INT64:
4205978408cSSascha Wildner 			NUM(uint64_t);
4215978408cSSascha Wildner 		case OPT_INT32:
4225978408cSSascha Wildner 			NUM(uint32_t);
4235978408cSSascha Wildner 		case OPT_INT16:
4245978408cSSascha Wildner 			NUM(uint16_t);
4255978408cSSascha Wildner 		case OPT_INT8:
4265978408cSSascha Wildner 			NUM(uint8_t);
4275978408cSSascha Wildner 		default:
4285978408cSSascha Wildner 			warnx("Unknown type %d in option %s", options[i].type,
4295978408cSSascha Wildner 			    val);
4305978408cSSascha Wildner 			return 0;
4315978408cSSascha Wildner 		}
4325978408cSSascha Wildner 		return i;
4335978408cSSascha Wildner 	}
4345978408cSSascha Wildner 	warnx("Unknown option `%s'", var);
4355978408cSSascha Wildner 	return -1;
4365978408cSSascha Wildner }
4375978408cSSascha Wildner 
4385978408cSSascha Wildner 
4395978408cSSascha Wildner static fstype_t *
get_fstype(const char * type)4405978408cSSascha Wildner get_fstype(const char *type)
4415978408cSSascha Wildner {
4425978408cSSascha Wildner 	int i;
4435978408cSSascha Wildner 
4445978408cSSascha Wildner 	for (i = 0; fstypes[i].type != NULL; i++)
4455978408cSSascha Wildner 		if (strcmp(fstypes[i].type, type) == 0)
4465978408cSSascha Wildner 			return (&fstypes[i]);
4475978408cSSascha Wildner 	return (NULL);
4485978408cSSascha Wildner }
4495978408cSSascha Wildner 
4505978408cSSascha Wildner option_t *
copy_opts(const option_t * o)4515978408cSSascha Wildner copy_opts(const option_t *o)
4525978408cSSascha Wildner {
4535978408cSSascha Wildner 	size_t i;
4545978408cSSascha Wildner 
4555978408cSSascha Wildner 	for (i = 0; o[i].name; i++)
4565978408cSSascha Wildner 		continue;
4575978408cSSascha Wildner 	i++;
4585978408cSSascha Wildner 	return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o));
4595978408cSSascha Wildner }
4605978408cSSascha Wildner 
4615978408cSSascha Wildner static int
get_tstamp(const char * b,struct stat * st)4625978408cSSascha Wildner get_tstamp(const char *b, struct stat *st)
4635978408cSSascha Wildner {
4645978408cSSascha Wildner 	time_t when;
4655978408cSSascha Wildner 	char *eb;
4665978408cSSascha Wildner 	long long l;
4675978408cSSascha Wildner 
4685978408cSSascha Wildner 	if (stat(b, st) != -1)
4695978408cSSascha Wildner 		return 0;
4705978408cSSascha Wildner 
4715978408cSSascha Wildner 	{
4725978408cSSascha Wildner 		errno = 0;
4735978408cSSascha Wildner 		l = strtoll(b, &eb, 0);
4745978408cSSascha Wildner 		if (b == eb || *eb || errno)
4755978408cSSascha Wildner 			return -1;
4765978408cSSascha Wildner 		when = (time_t)l;
4775978408cSSascha Wildner 	}
4785978408cSSascha Wildner 
4795978408cSSascha Wildner 	st->st_ino = 1;
480cdfb6d44SSascha Wildner #if HAVE_STRUCT_STAT_BIRTHTIME
4815978408cSSascha Wildner 	st->st_birthtime =
4825978408cSSascha Wildner #endif
4835978408cSSascha Wildner 	st->st_mtime = st->st_ctime = st->st_atime = when;
4845978408cSSascha Wildner 	return 0;
4855978408cSSascha Wildner }
4865978408cSSascha Wildner 
4875978408cSSascha Wildner static void
usage(fstype_t * fstype,fsinfo_t * fsoptions)4885978408cSSascha Wildner usage(fstype_t *fstype, fsinfo_t *fsoptions)
4895978408cSSascha Wildner {
4905978408cSSascha Wildner 	const char *prog;
4915978408cSSascha Wildner 
4925978408cSSascha Wildner 	prog = getprogname();
4935978408cSSascha Wildner 	fprintf(stderr,
4945978408cSSascha Wildner "Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n"
4955978408cSSascha Wildner "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n"
4965978408cSSascha Wildner "\t[-N userdb-dir] [-O offset] [-o fs-options] [-R roundup-size]\n"
4975978408cSSascha Wildner "\t[-S sector-size] [-s image-size] [-T <timestamp/file>] [-t fs-type]\n"
4985978408cSSascha Wildner "\timage-file directory | manifest [extra-directory ...]\n",
4995978408cSSascha Wildner 	    prog);
5005978408cSSascha Wildner 
5015978408cSSascha Wildner 	if (fstype) {
5025978408cSSascha Wildner 		size_t i;
5035978408cSSascha Wildner 		option_t *o = fsoptions->fs_options;
5045978408cSSascha Wildner 
5055978408cSSascha Wildner 		fprintf(stderr, "\n%s specific options:\n", fstype->type);
5065978408cSSascha Wildner 		for (i = 0; o[i].name != NULL; i++)
5075978408cSSascha Wildner 			fprintf(stderr, "\t%c%c%20.20s\t%s\n",
5085978408cSSascha Wildner 			    o[i].letter ? o[i].letter : ' ',
5095978408cSSascha Wildner 			    o[i].letter ? ',' : ' ',
5105978408cSSascha Wildner 			    o[i].name, o[i].desc);
5115978408cSSascha Wildner 	}
5125978408cSSascha Wildner 	exit(1);
5135978408cSSascha Wildner }
514