makefs.c revision 1.2 1 /* $NetBSD: makefs.c,v 1.2 2001/10/28 13:14:05 lukem Exp $ */
2
3 /*
4 * Copyright 2001 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 #ifndef __lint
40 __RCSID("$NetBSD: makefs.c,v 1.2 2001/10/28 13:14:05 lukem Exp $");
41 #endif /* !__lint */
42
43 #include <assert.h>
44 #include <ctype.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include "makefs.h"
53
54
55 /*
56 * list of supported file systems and dispatch functions
57 */
58 typedef struct {
59 const char *type;
60 int (*parse_options)(const char *, fsinfo_t *);
61 void (*make_fs)(const char *, const char *, fsnode *,
62 fsinfo_t *);
63 } fstype_t;
64
65 static fstype_t fstypes[] = {
66 { "ffs", ffs_parse_opts, ffs_makefs },
67 { NULL },
68 };
69
70 int debug;
71 struct timespec start_time;
72
73
74 static fstype_t *get_fstype(const char *);
75 static long long strsuftoll(const char *, const char *, long long, long long);
76 static void usage(void);
77 int main(int, char *[]);
78
79 int
80 main(int argc, char *argv[])
81 {
82 struct timeval start;
83 fstype_t *fstype;
84 fsinfo_t fsoptions;
85 fsnode *root;
86 int ch, len;
87 char *specfile;
88
89 debug = 0;
90 if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL)
91 errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE);
92 (void)memset(&fsoptions, 0, sizeof(fsoptions));
93 fsoptions.fd = -1;
94 specfile = NULL;
95 if (gettimeofday(&start, NULL) == -1)
96 err(1, "Unable to get system time");
97 TIMEVAL_TO_TIMESPEC(&start, &start_time);
98
99 while ((ch = getopt(argc, argv, "B:b:d:f:F:M:m:o:s:S:t:")) != -1) {
100 switch (ch) {
101
102 case 'B':
103 if (strcmp(optarg, "be") == 0 ||
104 strcmp(optarg, "big") == 0) {
105 #if BYTE_ORDER == LITTLE_ENDIAN
106 fsoptions.needswap = 1;
107 #endif
108 } else if (strcmp(optarg, "le") == 0 ||
109 strcmp(optarg, "little") == 0) {
110 #if BYTE_ORDER == BIG_ENDIAN
111 fsoptions.needswap = 1;
112 #endif
113 } else {
114 warnx("Invalid endian `%s'.", optarg);
115 usage();
116 }
117 break;
118
119 case 'b':
120 len = strlen(optarg) - 1;
121 if (optarg[len] == '%') {
122 optarg[len] = '\0';
123 fsoptions.freeblockpc =
124 strsuftoll("free block percentage",
125 optarg, 0, LLONG_MAX);
126 } else {
127 fsoptions.freeblocks = strsuftoll("free blocks",
128 optarg, 0, LLONG_MAX);
129 }
130 break;
131
132 case 'd':
133 debug = (int)strsuftoll("debug mask", optarg,
134 0, LLONG_MAX);
135 break;
136
137 case 'f':
138 len = strlen(optarg) - 1;
139 if (optarg[len] == '%') {
140 optarg[len] = '\0';
141 fsoptions.freefilepc =
142 strsuftoll("free file percentage",
143 optarg, 0, LLONG_MAX);
144 } else {
145 fsoptions.freefiles = strsuftoll("free files",
146 optarg, 0, LLONG_MAX);
147 }
148 break;
149
150 case 'F':
151 specfile = optarg;
152 break;
153
154 case 'M':
155 fsoptions.minsize = strsuftoll("minimum size",
156 optarg, 1LL, LLONG_MAX);
157 break;
158
159 case 'm':
160 fsoptions.maxsize = strsuftoll("maximum size",
161 optarg, 1LL, LLONG_MAX);
162 break;
163
164 case 'o':
165 {
166 char *p;
167
168 while ((p = strsep(&optarg, ",")) != NULL) {
169 if (*p == '\0')
170 errx(1, "Empty option");
171 if (! fstype->parse_options(p, &fsoptions))
172 usage();
173 }
174 break;
175 }
176
177 case 's':
178 fsoptions.minsize = fsoptions.maxsize =
179 strsuftoll("size", optarg, 1LL, LLONG_MAX);
180 break;
181
182 case 'S':
183 fsoptions.sectorsize = strsuftoll("sector size",
184 optarg, 1LL, LLONG_MAX);
185 break;
186
187 case 't':
188 if ((fstype = get_fstype(optarg)) == NULL)
189 errx(1, "Unknown fs type `%s'.", optarg);
190 break;
191
192 case '?':
193 default:
194 usage();
195 /* NOTREACHED */
196
197 }
198 }
199 if (debug) {
200 printf("debug mask: 0x%08x\n", debug);
201 printf("start time: %ld.%ld, %s",
202 start_time.tv_sec, start_time.tv_nsec,
203 ctime(&start_time.tv_sec));
204 }
205 argc -= optind;
206 argv += optind;
207
208 if (argc != 2)
209 usage();
210
211 /* walk the tree */
212 TIMER_START(start);
213 root = walk_dir(argv[1], NULL);
214 TIMER_RESULTS(start, "walk_dir");
215
216 if (specfile) { /* apply a specfile */
217 TIMER_START(start);
218 apply_specfile(specfile, argv[1], root);
219 TIMER_RESULTS(start, "apply_specfile");
220 }
221
222 if (debug & DEBUG_DUMP_FSNODES) {
223 putchar('\n');
224 dump_fsnodes(argv[1], root);
225 putchar('\n');
226 }
227
228 /* build the file system */
229 TIMER_START(start);
230 fstype->make_fs(argv[0], argv[1], root, &fsoptions);
231 TIMER_RESULTS(start, "make_fs");
232
233 exit(0);
234 /* NOTREACHED */
235 }
236
237
238 int
239 set_option(option_t *options, const char *var, const char *val)
240 {
241 int i;
242
243 for (i = 0; options[i].name != NULL; i++) {
244 if (strcmp(options[i].name, var) != 0)
245 continue;
246 *options[i].value = (int)strsuftoll(options[i].desc, val,
247 options[i].minimum, options[i].maximum);
248 return (1);
249 }
250 warnx("Unknown option `%s'", var);
251 return (0);
252 }
253
254
255 static fstype_t *
256 get_fstype(const char *type)
257 {
258 int i;
259
260 for (i = 0; fstypes[i].type != NULL; i++)
261 if (strcmp(fstypes[i].type, type) == 0)
262 return (&fstypes[i]);
263 return (NULL);
264 }
265
266
267 static long long
268 strsuftoll(const char *desc, const char *arg, long long min, long long max)
269 {
270 long long result;
271 char *ep;
272
273 assert(desc != NULL);
274 assert(arg != NULL);
275
276 errno = 0;
277 result = strtoll(arg, &ep, 0);
278 if ((result == LLONG_MIN || result == LLONG_MAX) && errno == ERANGE) {
279 warn("%s `%s'", desc, arg);
280 usage();
281 }
282 if (ep[0] != '\0' && ep[1] != '\0') {
283 warnx("`%s' is not a valid number for %s.", optarg, desc);
284 usage();
285 }
286 switch (tolower((unsigned char)ep[0])) {
287 case '\0':
288 case 'b':
289 break;
290 case 'k':
291 result <<= 10;
292 break;
293 case 'm':
294 result <<= 20;
295 break;
296 case 'g':
297 result <<= 30;
298 break;
299 default:
300 warnx("`%s' is not a valid suffix for %s.", ep, desc);
301 usage();
302 }
303
304 if (result < min) {
305 warnx("%s `%s' (%lld) is less than %lld.",
306 desc, optarg, result, min);
307 usage();
308 }
309 if (result > max) {
310 warnx("%s `%s' (%lld) is greater than %lld.",
311 desc, optarg, result, max);
312 usage();
313 }
314 if (debug & DEBUG_STRSUFTOLL)
315 printf("strsuftoll: got %lld for %s %s\n",
316 result, desc, arg);
317 return (result);
318 }
319
320
321 static void
322 usage(void)
323 {
324 const char *prog;
325
326 prog = getprogname();
327 fprintf(stderr,
328 "Usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n"
329 "\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-s image-size]\n"
330 "\t[-b free-blocks] [-f free-files] [-F mtree-specfile]\n"
331 "\timage-file directory\n",
332 prog);
333 exit(1);
334 }
335