1 /* $NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $ */
4 * Copyright (c) 2001-2003 Wasabi Systems, Inc.
7 * Written by Luke Mewburn for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
41 #include <sys/types.h>
59 * list of supported file systems and dispatch functions
63 void (*prepare_options)(fsinfo_t *);
64 int (*parse_options)(const char *, fsinfo_t *);
65 void (*cleanup_options)(fsinfo_t *);
66 void (*make_fs)(const char *, const char *, fsnode *,
70 static fstype_t fstypes[] = {
71 #define ENTRY(name) { \
72 # name, name ## _prep_opts, name ## _parse_opts, \
73 name ## _cleanup_opts, name ## _makefs \
82 struct timespec start_time;
85 static fstype_t *get_fstype(const char *);
86 static int get_tstamp(const char *, struct stat *);
87 static void usage(fstype_t *, fsinfo_t *);
90 main(int argc, char *argv[])
101 setprogname(argv[0]);
104 if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
105 errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
107 /* set default fsoptions */
108 (void)memset(&fsoptions, 0, sizeof(fsoptions));
110 fsoptions.sectorsize = -1;
112 if (fstype->prepare_options)
113 fstype->prepare_options(&fsoptions);
116 #ifdef CLOCK_REALTIME
117 ch = clock_gettime(CLOCK_REALTIME, &start_time);
119 ch = gettimeofday(&start, NULL);
120 start_time.tv_sec = start.tv_sec;
121 start_time.tv_nsec = start.tv_usec * 1000;
124 err(1, "Unable to get system time");
127 while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:T:xZ")) != -1) {
131 if (strcmp(optarg, "be") == 0 ||
132 strcmp(optarg, "4321") == 0 ||
133 strcmp(optarg, "big") == 0) {
134 #if BYTE_ORDER == LITTLE_ENDIAN
135 fsoptions.needswap = 1;
137 } else if (strcmp(optarg, "le") == 0 ||
138 strcmp(optarg, "1234") == 0 ||
139 strcmp(optarg, "little") == 0) {
140 #if BYTE_ORDER == BIG_ENDIAN
141 fsoptions.needswap = 1;
144 warnx("Invalid endian `%s'.", optarg);
145 usage(fstype, &fsoptions);
150 len = strlen(optarg) - 1;
151 if (optarg[len] == '%') {
153 fsoptions.freeblockpc =
154 strsuftoll("free block percentage",
157 fsoptions.freeblocks =
158 strsuftoll("free blocks",
159 optarg, 0, LLONG_MAX);
168 debug = strtoll(optarg, NULL, 0);
172 len = strlen(optarg) - 1;
173 if (optarg[len] == '%') {
175 fsoptions.freefilepc =
176 strsuftoll("free file percentage",
179 fsoptions.freefiles =
180 strsuftoll("free files",
181 optarg, 0, LLONG_MAX);
191 strsuftoll("minimum size", optarg, 1LL, LLONG_MAX);
195 if (! setup_getid(optarg))
197 "Unable to use user and group databases in `%s'",
203 strsuftoll("maximum size", optarg, 1LL, LLONG_MAX);
210 while ((p = strsep(&optarg, ",")) != NULL) {
212 errx(1, "Empty option");
213 if (! fstype->parse_options(p, &fsoptions))
214 usage(fstype, &fsoptions);
219 /* Deprecated in favor of 'Z' */
220 fsoptions.sparse = 1;
224 /* Round image size up to specified block size */
226 strsuftoll("roundup-size", optarg, 0, LLONG_MAX);
230 fsoptions.minsize = fsoptions.maxsize =
231 strsuftoll("size", optarg, 1LL, LLONG_MAX);
235 fsoptions.sectorsize =
236 (int)strsuftoll("sector size", optarg,
241 /* Check current one and cleanup if necessary. */
242 if (fstype->cleanup_options)
243 fstype->cleanup_options(&fsoptions);
244 fsoptions.fs_specific = NULL;
245 if ((fstype = get_fstype(optarg)) == NULL)
246 errx(1, "Unknown fs type `%s'.", optarg);
247 fstype->prepare_options(&fsoptions);
251 if (get_tstamp(optarg, &stampst) == -1)
252 errx(1, "Cannot get timestamp from `%s'",
257 fsoptions.onlyspec = 1;
261 /* Superscedes 'p' for compatibility with NetBSD makefs(8) */
262 fsoptions.sparse = 1;
267 usage(fstype, &fsoptions);
273 printf("debug mask: 0x%08x\n", debug);
274 printf("start time: %ld.%ld, %s",
275 (long)start_time.tv_sec, (long)start_time.tv_nsec,
276 ctime(&start_time.tv_sec));
282 usage(fstype, &fsoptions);
284 /* -x must be accompanied by -F */
285 if (fsoptions.onlyspec != 0 && specfile == NULL)
286 errx(1, "-x requires -F mtree-specfile.");
288 /* Accept '-' as meaning "read from standard input". */
289 if (strcmp(argv[1], "-") == 0)
290 sb.st_mode = S_IFREG;
292 if (stat(argv[1], &sb) == -1)
293 err(1, "Can't stat `%s'", argv[1]);
296 switch (sb.st_mode & S_IFMT) {
297 case S_IFDIR: /* walk the tree */
300 root = walk_dir(subtree, ".", NULL, NULL);
301 TIMER_RESULTS(start, "walk_dir");
303 case S_IFREG: /* read the manifest file */
306 root = read_mtree(argv[1], NULL);
307 TIMER_RESULTS(start, "manifest");
310 errx(1, "%s: not a file or directory", argv[1]);
314 /* append extra directory */
315 for (i = 2; i < argc; i++) {
316 if (stat(argv[i], &sb) == -1)
317 err(1, "Can't stat `%s'", argv[i]);
318 if (!S_ISDIR(sb.st_mode))
319 errx(1, "%s: not a directory", argv[i]);
321 root = walk_dir(argv[i], ".", NULL, root);
322 TIMER_RESULTS(start, "walk_dir2");
325 if (specfile) { /* apply a specfile */
327 apply_specfile(specfile, subtree, root, fsoptions.onlyspec);
328 TIMER_RESULTS(start, "apply_specfile");
331 if (debug & DEBUG_DUMP_FSNODES) {
332 printf("\nparent: %s\n", subtree);
337 /* build the file system */
339 fstype->make_fs(argv[0], subtree, root, &fsoptions);
340 TIMER_RESULTS(start, "make_fs");
349 set_option(const option_t *options, const char *option, char *buf, size_t len)
354 assert(option != NULL);
356 var = estrdup(option);
357 for (val = var; *val; val++)
362 retval = set_option_var(options, var, val, buf, len);
368 set_option_var(const option_t *options, const char *var, const char *val,
369 char *buf, size_t len)
376 *(type *)options[i].value = 1; \
379 *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \
380 options[i].minimum, options[i].maximum); break
382 for (i = 0; options[i].name != NULL; i++) {
383 if (var[1] == '\0') {
384 if (options[i].letter != var[0])
386 } else if (strcmp(options[i].name, var) != 0)
388 switch (options[i].type) {
390 *(bool *)options[i].value = 1;
393 strlcpy((void *)options[i].value, val, (size_t)
398 *(char **)options[i].value = s;
403 strlcpy(buf, val, len);
414 warnx("Unknown type %d in option %s", options[i].type,
420 warnx("Unknown option `%s'", var);
426 get_fstype(const char *type)
430 for (i = 0; fstypes[i].type != NULL; i++)
431 if (strcmp(fstypes[i].type, type) == 0)
432 return (&fstypes[i]);
437 copy_opts(const option_t *o)
441 for (i = 0; o[i].name; i++)
444 return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o));
448 get_tstamp(const char *b, struct stat *st)
454 if (stat(b, st) != -1)
459 l = strtoll(b, &eb, 0);
460 if (b == eb || *eb || errno)
466 #ifdef HAVE_STRUCT_STAT_BIRTHTIME
469 st->st_mtime = st->st_ctime = st->st_atime = when;
474 usage(fstype_t *fstype, fsinfo_t *fsoptions)
478 prog = getprogname();
480 "Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n"
481 "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n"
482 "\t[-N userdb-dir] [-o fs-options] [-R roundup-size] [-S sector-size]\n"
483 "\t[-s image-size] [-T <timestamp/file>] [-t fs-type]\n"
484 "\timage-file directory | manifest [extra-directory ...]\n",
489 option_t *o = fsoptions->fs_options;
491 fprintf(stderr, "\n%s specific options:\n", fstype->type);
492 for (i = 0; o[i].name != NULL; i++)
493 fprintf(stderr, "\t%c%c%20.20s\t%s\n",
494 o[i].letter ? o[i].letter : ' ',
495 o[i].letter ? ',' : ' ',
496 o[i].name, o[i].desc);