]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/makefs/makefs.c
Copy ^/vendor/NetBSD/tests/dist to contrib/netbsd-tests
[FreeBSD/FreeBSD.git] / usr.sbin / makefs / makefs.c
1 /*      $NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $     */
2
3 /*
4  * Copyright (c) 2001-2003 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Luke Mewburn for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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
23  *    written permission.
24  *
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.
36  */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <assert.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <limits.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51 #include <unistd.h>
52
53 #include "makefs.h"
54 #include "mtree.h"
55
56 /*
57  * list of supported file systems and dispatch functions
58  */
59 typedef struct {
60         const char      *type;
61         void            (*prepare_options)(fsinfo_t *);
62         int             (*parse_options)(const char *, fsinfo_t *);
63         void            (*cleanup_options)(fsinfo_t *);
64         void            (*make_fs)(const char *, const char *, fsnode *,
65                                 fsinfo_t *);
66 } fstype_t;
67
68 static fstype_t fstypes[] = {
69 #define ENTRY(name) { \
70         # name, name ## _prep_opts, name ## _parse_opts, \
71         name ## _cleanup_opts, name ## _makefs  \
72 }
73         ENTRY(ffs),
74         ENTRY(cd9660),
75         { .type = NULL  },
76 };
77
78 u_int           debug;
79 int             dupsok;
80 struct timespec start_time;
81 struct stat stampst;
82
83 static  fstype_t *get_fstype(const char *);
84 static int get_tstamp(const char *, struct stat *);
85 static  void    usage(void);
86 int             main(int, char *[]);
87
88 int
89 main(int argc, char *argv[])
90 {
91         struct stat      sb;
92         struct timeval   start;
93         fstype_t        *fstype;
94         fsinfo_t         fsoptions;
95         fsnode          *root;
96         int              ch, i, len;
97         char            *subtree;
98         char            *specfile;
99
100         setprogname(argv[0]);
101
102         debug = 0;
103         if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
104                 errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
105
106                 /* set default fsoptions */
107         (void)memset(&fsoptions, 0, sizeof(fsoptions));
108         fsoptions.fd = -1;
109         fsoptions.sectorsize = -1;
110
111         if (fstype->prepare_options)
112                 fstype->prepare_options(&fsoptions);
113
114         specfile = NULL;
115         ch = gettimeofday(&start, NULL);
116         start_time.tv_sec = start.tv_sec;
117         start_time.tv_nsec = start.tv_usec * 1000;
118
119         if (ch == -1)
120                 err(1, "Unable to get system time");
121
122
123         while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:T:xZ")) != -1) {
124                 switch (ch) {
125
126                 case 'B':
127                         if (strcmp(optarg, "be") == 0 ||
128                             strcmp(optarg, "4321") == 0 ||
129                             strcmp(optarg, "big") == 0) {
130 #if BYTE_ORDER == LITTLE_ENDIAN
131                                 fsoptions.needswap = 1;
132 #endif
133                         } else if (strcmp(optarg, "le") == 0 ||
134                             strcmp(optarg, "1234") == 0 ||
135                             strcmp(optarg, "little") == 0) {
136 #if BYTE_ORDER == BIG_ENDIAN
137                                 fsoptions.needswap = 1;
138 #endif
139                         } else {
140                                 warnx("Invalid endian `%s'.", optarg);
141                                 usage();
142                         }
143                         break;
144
145                 case 'b':
146                         len = strlen(optarg) - 1;
147                         if (optarg[len] == '%') {
148                                 optarg[len] = '\0';
149                                 fsoptions.freeblockpc =
150                                     strsuftoll("free block percentage",
151                                         optarg, 0, 99);
152                         } else {
153                                 fsoptions.freeblocks =
154                                     strsuftoll("free blocks",
155                                         optarg, 0, LLONG_MAX);
156                         }
157                         break;
158
159                 case 'D':
160                         dupsok = 1;
161                         break;
162
163                 case 'd':
164                         debug = strtoll(optarg, NULL, 0);
165                         break;
166
167                 case 'f':
168                         len = strlen(optarg) - 1;
169                         if (optarg[len] == '%') {
170                                 optarg[len] = '\0';
171                                 fsoptions.freefilepc =
172                                     strsuftoll("free file percentage",
173                                         optarg, 0, 99);
174                         } else {
175                                 fsoptions.freefiles =
176                                     strsuftoll("free files",
177                                         optarg, 0, LLONG_MAX);
178                         }
179                         break;
180
181                 case 'F':
182                         specfile = optarg;
183                         break;
184
185                 case 'M':
186                         fsoptions.minsize =
187                             strsuftoll("minimum size", optarg, 1LL, LLONG_MAX);
188                         break;
189
190                 case 'N':
191                         if (! setup_getid(optarg))
192                                 errx(1,
193                             "Unable to use user and group databases in `%s'",
194                                     optarg);
195                         break;
196
197                 case 'm':
198                         fsoptions.maxsize =
199                             strsuftoll("maximum size", optarg, 1LL, LLONG_MAX);
200                         break;
201                         
202                 case 'o':
203                 {
204                         char *p;
205
206                         while ((p = strsep(&optarg, ",")) != NULL) {
207                                 if (*p == '\0')
208                                         errx(1, "Empty option");
209                                 if (! fstype->parse_options(p, &fsoptions))
210                                         usage();
211                         }
212                         break;
213                 }
214                 case 'p':
215                         /* Deprecated in favor of 'Z' */
216                         fsoptions.sparse = 1;
217                         break;
218
219                 case 'R':
220                         /* Round image size up to specified block size */
221                         fsoptions.roundup =
222                             strsuftoll("roundup-size", optarg, 0, LLONG_MAX);
223                         break;
224
225                 case 's':
226                         fsoptions.minsize = fsoptions.maxsize =
227                             strsuftoll("size", optarg, 1LL, LLONG_MAX);
228                         break;
229
230                 case 'S':
231                         fsoptions.sectorsize =
232                             (int)strsuftoll("sector size", optarg,
233                                 1LL, INT_MAX);
234                         break;
235
236                 case 't':
237                         /* Check current one and cleanup if necessary. */
238                         if (fstype->cleanup_options)
239                                 fstype->cleanup_options(&fsoptions);
240                         fsoptions.fs_specific = NULL;
241                         if ((fstype = get_fstype(optarg)) == NULL)
242                                 errx(1, "Unknown fs type `%s'.", optarg);
243                         fstype->prepare_options(&fsoptions);
244                         break;
245
246                 case 'T':
247                         if (get_tstamp(optarg, &stampst) == -1)
248                                 errx(1, "Cannot get timestamp from `%s'",
249                                     optarg);
250                         break;
251
252                 case 'x':
253                         fsoptions.onlyspec = 1;
254                         break;
255
256                 case 'Z':
257                         /* Superscedes 'p' for compatibility with NetBSD makefs(8) */
258                         fsoptions.sparse = 1;
259                         break;
260
261                 case '?':
262                 default:
263                         usage();
264                         /* NOTREACHED */
265
266                 }
267         }
268         if (debug) {
269                 printf("debug mask: 0x%08x\n", debug);
270                 printf("start time: %ld.%ld, %s",
271                     (long)start_time.tv_sec, (long)start_time.tv_nsec,
272                     ctime(&start_time.tv_sec));
273         }
274         argc -= optind;
275         argv += optind;
276
277         if (argc < 2)
278                 usage();
279
280         /* -x must be accompanied by -F */
281         if (fsoptions.onlyspec != 0 && specfile == NULL)
282                 errx(1, "-x requires -F mtree-specfile.");
283
284         /* Accept '-' as meaning "read from standard input". */
285         if (strcmp(argv[1], "-") == 0)
286                 sb.st_mode = S_IFREG;
287         else {
288                 if (stat(argv[1], &sb) == -1)
289                         err(1, "Can't stat `%s'", argv[1]);
290         }
291
292         switch (sb.st_mode & S_IFMT) {
293         case S_IFDIR:           /* walk the tree */
294                 subtree = argv[1];
295                 TIMER_START(start);
296                 root = walk_dir(subtree, ".", NULL, NULL);
297                 TIMER_RESULTS(start, "walk_dir");
298                 break;
299         case S_IFREG:           /* read the manifest file */
300                 subtree = ".";
301                 TIMER_START(start);
302                 root = read_mtree(argv[1], NULL);
303                 TIMER_RESULTS(start, "manifest");
304                 break;
305         default:
306                 errx(1, "%s: not a file or directory", argv[1]);
307                 /* NOTREACHED */
308         }
309
310         /* append extra directory */
311         for (i = 2; i < argc; i++) {
312                 if (stat(argv[i], &sb) == -1)
313                         err(1, "Can't stat `%s'", argv[i]);
314                 if (!S_ISDIR(sb.st_mode))
315                         errx(1, "%s: not a directory", argv[i]);
316                 TIMER_START(start);
317                 root = walk_dir(argv[i], ".", NULL, root);
318                 TIMER_RESULTS(start, "walk_dir2");
319         }
320
321         if (specfile) {         /* apply a specfile */
322                 TIMER_START(start);
323                 apply_specfile(specfile, subtree, root, fsoptions.onlyspec);
324                 TIMER_RESULTS(start, "apply_specfile");
325         }
326
327         if (debug & DEBUG_DUMP_FSNODES) {
328                 printf("\nparent: %s\n", subtree);
329                 dump_fsnodes(root);
330                 putchar('\n');
331         }
332
333                                 /* build the file system */
334         TIMER_START(start);
335         fstype->make_fs(argv[0], subtree, root, &fsoptions);
336         TIMER_RESULTS(start, "make_fs");
337
338         free_fsnodes(root);
339
340         exit(0);
341         /* NOTREACHED */
342 }
343
344
345 int
346 set_option(option_t *options, const char *var, const char *val)
347 {
348         int     i;
349
350         for (i = 0; options[i].name != NULL; i++) {
351                 if (strcmp(options[i].name, var) != 0)
352                         continue;
353                 *options[i].value = (int)strsuftoll(options[i].desc, val,
354                     options[i].minimum, options[i].maximum);
355                 return (1);
356         }
357         warnx("Unknown option `%s'", var);
358         return (0);
359 }
360
361
362 static fstype_t *
363 get_fstype(const char *type)
364 {
365         int i;
366         
367         for (i = 0; fstypes[i].type != NULL; i++)
368                 if (strcmp(fstypes[i].type, type) == 0)
369                         return (&fstypes[i]);
370         return (NULL);
371 }
372
373 static int
374 get_tstamp(const char *b, struct stat *st)
375 {
376         time_t when;
377         char *eb;
378         long long l;
379
380         if (stat(b, st) != -1)
381                 return 0;
382
383         {
384                 errno = 0;
385                 l = strtoll(b, &eb, 0);
386                 if (b == eb || *eb || errno)
387                         return -1;
388                 when = (time_t)l;
389         }
390
391         st->st_ino = 1;
392 #ifdef HAVE_STRUCT_STAT_BIRTHTIME
393         st->st_birthtime =
394 #endif
395         st->st_mtime = st->st_ctime = st->st_atime = when;
396         return 0;
397 }
398
399 static void
400 usage(void)
401 {
402         const char *prog;
403
404         prog = getprogname();
405         fprintf(stderr,
406 "usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n"
407 "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n"
408 "\t[-N userdb-dir] [-o fs-options] [-R roundup-size] [-S sector-size]\n"
409 "\t[-s image-size] [-T <timestamp/file>] [-t fs-type]\n"
410 "\timage-file directory | manifest [extra-directory ...]\n",
411             prog);
412         exit(1);
413 }