1 |
|
|
/* $OpenBSD: makefs.c,v 1.19 2016/12/17 16:12:15 krw Exp $ */ |
2 |
|
|
/* $NetBSD: makefs.c,v 1.53 2015/11/27 15:10:32 joerg Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 2001-2003 Wasabi Systems, Inc. |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Written by Luke Mewburn for Wasabi Systems, Inc. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* 3. All advertising materials mentioning features or use of this software |
19 |
|
|
* must display the following acknowledgement: |
20 |
|
|
* This product includes software developed for the NetBSD Project by |
21 |
|
|
* Wasabi Systems, Inc. |
22 |
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse |
23 |
|
|
* or promote products derived from this software without specific prior |
24 |
|
|
* written permission. |
25 |
|
|
* |
26 |
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
27 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
28 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
29 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
30 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
31 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
32 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
33 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
34 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
35 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
36 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
37 |
|
|
*/ |
38 |
|
|
|
39 |
|
|
#include <assert.h> |
40 |
|
|
#include <errno.h> |
41 |
|
|
#include <limits.h> |
42 |
|
|
#include <stdio.h> |
43 |
|
|
#include <stdlib.h> |
44 |
|
|
#include <string.h> |
45 |
|
|
#include <unistd.h> |
46 |
|
|
#include <util.h> |
47 |
|
|
|
48 |
|
|
#include "makefs.h" |
49 |
|
|
|
50 |
|
|
/* |
51 |
|
|
* list of supported file systems and dispatch functions |
52 |
|
|
*/ |
53 |
|
|
typedef struct { |
54 |
|
|
const char *type; |
55 |
|
|
void (*prepare_options)(fsinfo_t *); |
56 |
|
|
int (*parse_options)(const char *, fsinfo_t *); |
57 |
|
|
void (*cleanup_options)(fsinfo_t *); |
58 |
|
|
void (*make_fs)(const char *, const char *, fsnode *, |
59 |
|
|
fsinfo_t *); |
60 |
|
|
} fstype_t; |
61 |
|
|
|
62 |
|
|
static fstype_t fstypes[] = { |
63 |
|
|
#define ENTRY(name) { \ |
64 |
|
|
# name, name ## _prep_opts, name ## _parse_opts, \ |
65 |
|
|
name ## _cleanup_opts, name ## _makefs \ |
66 |
|
|
} |
67 |
|
|
ENTRY(ffs), |
68 |
|
|
ENTRY(cd9660), |
69 |
|
|
ENTRY(msdos), |
70 |
|
|
{ .type = NULL }, |
71 |
|
|
}; |
72 |
|
|
|
73 |
|
|
int Tflag; |
74 |
|
|
time_t stampts; |
75 |
|
|
struct timespec start_time; |
76 |
|
|
|
77 |
|
|
static fstype_t *get_fstype(const char *); |
78 |
|
|
static time_t get_tstamp(const char *); |
79 |
|
|
static long long strsuftoll(const char *, const char *, long long, long long); |
80 |
|
|
static __dead void usage(void); |
81 |
|
|
|
82 |
|
|
int |
83 |
|
|
main(int argc, char *argv[]) |
84 |
|
|
{ |
85 |
|
|
fstype_t *fstype; |
86 |
|
|
fsinfo_t fsoptions; |
87 |
|
|
fsnode *root; |
88 |
|
|
int ch, len; |
89 |
|
|
|
90 |
|
|
if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) |
91 |
|
|
errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE); |
92 |
|
|
|
93 |
|
|
/* set default fsoptions */ |
94 |
|
|
(void)memset(&fsoptions, 0, sizeof(fsoptions)); |
95 |
|
|
fsoptions.fd = -1; |
96 |
|
|
fsoptions.sectorsize = -1; |
97 |
|
|
|
98 |
|
|
if (fstype->prepare_options) |
99 |
|
|
fstype->prepare_options(&fsoptions); |
100 |
|
|
|
101 |
|
|
ch = clock_gettime(CLOCK_REALTIME, &start_time); |
102 |
|
|
if (ch == -1) |
103 |
|
|
err(1, "Unable to get system time"); |
104 |
|
|
|
105 |
|
|
|
106 |
|
|
while ((ch = getopt(argc, argv, "b:f:M:m:O:o:s:S:t:T:")) != -1) { |
107 |
|
|
switch (ch) { |
108 |
|
|
case 'b': |
109 |
|
|
len = strlen(optarg) - 1; |
110 |
|
|
if (optarg[len] == '%') { |
111 |
|
|
optarg[len] = '\0'; |
112 |
|
|
fsoptions.freeblockpc = |
113 |
|
|
strsuftoll("free block percentage", |
114 |
|
|
optarg, 0, 99); |
115 |
|
|
} else { |
116 |
|
|
fsoptions.freeblocks = |
117 |
|
|
strsuftoll("free blocks", |
118 |
|
|
optarg, 0, LLONG_MAX); |
119 |
|
|
} |
120 |
|
|
break; |
121 |
|
|
|
122 |
|
|
case 'f': |
123 |
|
|
len = strlen(optarg) - 1; |
124 |
|
|
if (optarg[len] == '%') { |
125 |
|
|
optarg[len] = '\0'; |
126 |
|
|
fsoptions.freefilepc = |
127 |
|
|
strsuftoll("free file percentage", |
128 |
|
|
optarg, 0, 99); |
129 |
|
|
} else { |
130 |
|
|
fsoptions.freefiles = |
131 |
|
|
strsuftoll("free files", |
132 |
|
|
optarg, 0, LLONG_MAX); |
133 |
|
|
} |
134 |
|
|
break; |
135 |
|
|
|
136 |
|
|
case 'M': |
137 |
|
|
fsoptions.minsize = |
138 |
|
|
strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); |
139 |
|
|
break; |
140 |
|
|
|
141 |
|
|
case 'm': |
142 |
|
|
fsoptions.maxsize = |
143 |
|
|
strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); |
144 |
|
|
break; |
145 |
|
|
|
146 |
|
|
case 'O': |
147 |
|
|
fsoptions.offset = |
148 |
|
|
strsuftoll("offset", optarg, 0LL, LLONG_MAX); |
149 |
|
|
break; |
150 |
|
|
|
151 |
|
|
case 'o': |
152 |
|
|
{ |
153 |
|
|
char *p; |
154 |
|
|
|
155 |
|
|
while ((p = strsep(&optarg, ",")) != NULL) { |
156 |
|
|
if (*p == '\0') |
157 |
|
|
errx(1, "Empty option"); |
158 |
|
|
if (! fstype->parse_options(p, &fsoptions)) |
159 |
|
|
usage(); |
160 |
|
|
} |
161 |
|
|
break; |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
case 's': |
165 |
|
|
fsoptions.minsize = fsoptions.maxsize = |
166 |
|
|
strsuftoll("size", optarg, 1LL, LLONG_MAX); |
167 |
|
|
break; |
168 |
|
|
|
169 |
|
|
case 'S': |
170 |
|
|
fsoptions.sectorsize = |
171 |
|
|
(int)strsuftoll("sector size", optarg, |
172 |
|
|
1LL, INT_MAX); |
173 |
|
|
break; |
174 |
|
|
|
175 |
|
|
case 't': |
176 |
|
|
/* Check current one and cleanup if necessary. */ |
177 |
|
|
if (fstype->cleanup_options) |
178 |
|
|
fstype->cleanup_options(&fsoptions); |
179 |
|
|
fsoptions.fs_specific = NULL; |
180 |
|
|
if ((fstype = get_fstype(optarg)) == NULL) |
181 |
|
|
errx(1, "Unknown fs type `%s'.", optarg); |
182 |
|
|
fstype->prepare_options(&fsoptions); |
183 |
|
|
break; |
184 |
|
|
|
185 |
|
|
case 'T': |
186 |
|
|
Tflag = 1; |
187 |
|
|
stampts = get_tstamp(optarg); |
188 |
|
|
break; |
189 |
|
|
|
190 |
|
|
case '?': |
191 |
|
|
default: |
192 |
|
|
usage(); |
193 |
|
|
} |
194 |
|
|
} |
195 |
|
|
argc -= optind; |
196 |
|
|
argv += optind; |
197 |
|
|
|
198 |
|
|
if (argc != 2) |
199 |
|
|
usage(); |
200 |
|
|
|
201 |
|
|
if (pledge("stdio rpath wpath cpath flock", NULL) == -1) |
202 |
|
|
err(1, "pledge"); |
203 |
|
|
|
204 |
|
|
/* walk the tree */ |
205 |
|
|
root = walk_dir(argv[1], ".", NULL, NULL); |
206 |
|
|
|
207 |
|
|
/* build the file system */ |
208 |
|
|
fstype->make_fs(argv[0], argv[1], root, &fsoptions); |
209 |
|
|
|
210 |
|
|
free_fsnodes(root); |
211 |
|
|
|
212 |
|
|
exit(0); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
int |
216 |
|
|
set_option(const option_t *options, const char *option, char *buf, size_t len) |
217 |
|
|
{ |
218 |
|
|
char *var, *val; |
219 |
|
|
int retval; |
220 |
|
|
|
221 |
|
|
assert(option != NULL); |
222 |
|
|
|
223 |
|
|
var = estrdup(option); |
224 |
|
|
for (val = var; *val; val++) |
225 |
|
|
if (*val == '=') { |
226 |
|
|
*val++ = '\0'; |
227 |
|
|
break; |
228 |
|
|
} |
229 |
|
|
retval = set_option_var(options, var, val, buf, len); |
230 |
|
|
free(var); |
231 |
|
|
return retval; |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
int |
235 |
|
|
set_option_var(const option_t *options, const char *var, const char *val, |
236 |
|
|
char *buf, size_t len) |
237 |
|
|
{ |
238 |
|
|
char *s; |
239 |
|
|
size_t i; |
240 |
|
|
|
241 |
|
|
#define NUM(type) \ |
242 |
|
|
if (!*val) { \ |
243 |
|
|
*(type *)options[i].value = 1; \ |
244 |
|
|
break; \ |
245 |
|
|
} \ |
246 |
|
|
*(type *)options[i].value = (type)strsuftoll(options[i].name, val, \ |
247 |
|
|
options[i].minimum, options[i].maximum); break |
248 |
|
|
|
249 |
|
|
for (i = 0; options[i].name != NULL; i++) { |
250 |
|
|
if (strcmp(options[i].name, var) != 0) |
251 |
|
|
continue; |
252 |
|
|
switch (options[i].type) { |
253 |
|
|
case OPT_BOOL: |
254 |
|
|
*(int *)options[i].value = 1; |
255 |
|
|
break; |
256 |
|
|
case OPT_STRARRAY: |
257 |
|
|
strlcpy((void *)options[i].value, val, (size_t) |
258 |
|
|
options[i].maximum); |
259 |
|
|
break; |
260 |
|
|
case OPT_STRPTR: |
261 |
|
|
s = estrdup(val); |
262 |
|
|
*(char **)options[i].value = s; |
263 |
|
|
break; |
264 |
|
|
case OPT_STRBUF: |
265 |
|
|
if (buf == NULL) |
266 |
|
|
abort(); |
267 |
|
|
strlcpy(buf, val, len); |
268 |
|
|
break; |
269 |
|
|
case OPT_INT64: |
270 |
|
|
NUM(uint64_t); |
271 |
|
|
case OPT_INT32: |
272 |
|
|
NUM(uint32_t); |
273 |
|
|
case OPT_INT16: |
274 |
|
|
NUM(uint16_t); |
275 |
|
|
case OPT_INT8: |
276 |
|
|
NUM(uint8_t); |
277 |
|
|
default: |
278 |
|
|
warnx("Unknown type %d in option %s", options[i].type, |
279 |
|
|
val); |
280 |
|
|
return 0; |
281 |
|
|
} |
282 |
|
|
return i; |
283 |
|
|
} |
284 |
|
|
warnx("Unknown option `%s'", var); |
285 |
|
|
return -1; |
286 |
|
|
} |
287 |
|
|
|
288 |
|
|
|
289 |
|
|
static fstype_t * |
290 |
|
|
get_fstype(const char *type) |
291 |
|
|
{ |
292 |
|
|
int i; |
293 |
|
|
|
294 |
|
|
for (i = 0; fstypes[i].type != NULL; i++) |
295 |
|
|
if (strcmp(fstypes[i].type, type) == 0) |
296 |
|
|
return (&fstypes[i]); |
297 |
|
|
return (NULL); |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
option_t * |
301 |
|
|
copy_opts(const option_t *o) |
302 |
|
|
{ |
303 |
|
|
size_t i; |
304 |
|
|
for (i = 0; o[i].name; i++) |
305 |
|
|
continue; |
306 |
|
|
i++; |
307 |
|
|
return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
static time_t |
311 |
|
|
get_tstamp(const char *b) |
312 |
|
|
{ |
313 |
|
|
time_t when; |
314 |
|
|
char *eb; |
315 |
|
|
|
316 |
|
|
errno = 0; |
317 |
|
|
when = strtoll(b, &eb, 0); |
318 |
|
|
if (b == eb || *eb || errno) { |
319 |
|
|
errx(1, "Cannot get timestamp from `%s'", |
320 |
|
|
optarg); |
321 |
|
|
} |
322 |
|
|
return when; |
323 |
|
|
} |
324 |
|
|
|
325 |
|
|
/* XXX */ |
326 |
|
|
static long long |
327 |
|
|
strsuftoll(const char *desc, const char *val, long long min, long long max) |
328 |
|
|
{ |
329 |
|
|
long long res; |
330 |
|
|
|
331 |
|
|
if (scan_scaled((char *)val, &res) == -1) |
332 |
|
|
err(1, "%s", desc); |
333 |
|
|
if (res < min || res > max) |
334 |
|
|
errc(1, ERANGE, "%s", desc); |
335 |
|
|
return res; |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
static void |
339 |
|
|
usage(void) |
340 |
|
|
{ |
341 |
|
|
extern char *__progname; |
342 |
|
|
|
343 |
|
|
fprintf(stderr, |
344 |
|
|
"usage: %s [-b free-blocks] [-f free-files] [-M minimum-size]\n" |
345 |
|
|
"\t[-m maximum-size] [-O offset] [-o fs-options] [-S sector-size]\n" |
346 |
|
|
"\t[-s image-size] [-T timestamp] [-t fs-type] image-file directory\n", |
347 |
|
|
__progname); |
348 |
|
|
|
349 |
|
|
exit(1); |
350 |
|
|
} |