1 /* $NetBSD: makefs.c,v 1.18 2003/04/02 10:39:48 fvdl 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 #if defined(__RCSID) && !defined(__lint) 40 __RCSID("$NetBSD: makefs.c,v 1.18 2003/04/02 10:39:48 fvdl Exp $"); 41 #endif /* !__lint */ 42 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 <unistd.h> 51 52 #include "makefs.h" 53 #include "mtree.h" 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 uint debug; 71 struct timespec start_time; 72 73 static fstype_t *get_fstype(const char *); 74 static void usage(void); 75 int main(int, char *[]); 76 77 int 78 main(int argc, char *argv[]) 79 { 80 struct timeval start; 81 fstype_t *fstype; 82 fsinfo_t fsoptions; 83 fsnode *root; 84 int ch, len; 85 char *specfile; 86 87 setprogname(argv[0]); 88 89 debug = 0; 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 fsoptions.bsize= -1; 98 fsoptions.fsize= -1; 99 fsoptions.cpg= -1; 100 fsoptions.density= -1; 101 fsoptions.minfree= -1; 102 fsoptions.optimization= -1; 103 fsoptions.maxcontig= -1; 104 fsoptions.maxbpg= -1; 105 fsoptions.avgfilesize= -1; 106 fsoptions.avgfpdir= -1; 107 fsoptions.version = 1; 108 109 specfile = NULL; 110 if (gettimeofday(&start, NULL) == -1) 111 err(1, "Unable to get system time"); 112 113 start_time.tv_sec = start.tv_sec; 114 start_time.tv_nsec = start.tv_usec * 1000; 115 116 while ((ch = getopt(argc, argv, "B:b:d:f:F:M:m:N:o:s:S:t:x")) != -1) { 117 switch (ch) { 118 119 case 'B': 120 if (strcmp(optarg, "be") == 0 || 121 strcmp(optarg, "4321") == 0 || 122 strcmp(optarg, "big") == 0) { 123 #if BYTE_ORDER == LITTLE_ENDIAN 124 fsoptions.needswap = 1; 125 #endif 126 } else if (strcmp(optarg, "le") == 0 || 127 strcmp(optarg, "1234") == 0 || 128 strcmp(optarg, "little") == 0) { 129 #if BYTE_ORDER == BIG_ENDIAN 130 fsoptions.needswap = 1; 131 #endif 132 } else { 133 warnx("Invalid endian `%s'.", optarg); 134 usage(); 135 } 136 break; 137 138 case 'b': 139 len = strlen(optarg) - 1; 140 if (optarg[len] == '%') { 141 optarg[len] = '\0'; 142 fsoptions.freeblockpc = 143 strsuftoll("free block percentage", 144 optarg, 0, 99); 145 } else { 146 fsoptions.freeblocks = 147 strsuftoll("free blocks", 148 optarg, 0, LLONG_MAX); 149 } 150 break; 151 152 case 'd': 153 debug = 154 (int)strsuftoll("debug mask", optarg, 0, UINT_MAX); 155 break; 156 157 case 'f': 158 len = strlen(optarg) - 1; 159 if (optarg[len] == '%') { 160 optarg[len] = '\0'; 161 fsoptions.freefilepc = 162 strsuftoll("free file percentage", 163 optarg, 0, 99); 164 } else { 165 fsoptions.freefiles = 166 strsuftoll("free files", 167 optarg, 0, LLONG_MAX); 168 } 169 break; 170 171 case 'F': 172 specfile = optarg; 173 break; 174 175 case 'M': 176 fsoptions.minsize = 177 strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); 178 break; 179 180 case 'N': 181 if (! setup_getid(optarg)) 182 errx(1, 183 "Unable to use user and group databases in `%s'", 184 optarg); 185 break; 186 187 case 'm': 188 fsoptions.maxsize = 189 strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); 190 break; 191 192 case 'o': 193 { 194 char *p; 195 196 while ((p = strsep(&optarg, ",")) != NULL) { 197 if (*p == '\0') 198 errx(1, "Empty option"); 199 if (! fstype->parse_options(p, &fsoptions)) 200 usage(); 201 } 202 break; 203 } 204 205 case 's': 206 fsoptions.minsize = fsoptions.maxsize = 207 strsuftoll("size", optarg, 1LL, LLONG_MAX); 208 break; 209 210 case 'S': 211 fsoptions.sectorsize = 212 (int)strsuftoll("sector size", optarg, 213 1LL, INT_MAX); 214 break; 215 216 case 't': 217 if ((fstype = get_fstype(optarg)) == NULL) 218 errx(1, "Unknown fs type `%s'.", optarg); 219 break; 220 221 case 'x': 222 fsoptions.onlyspec = 1; 223 break; 224 225 case '?': 226 default: 227 usage(); 228 /* NOTREACHED */ 229 230 } 231 } 232 if (debug) { 233 printf("debug mask: 0x%08x\n", debug); 234 printf("start time: %ld.%ld, %s", 235 (long)start_time.tv_sec, (long)start_time.tv_nsec, 236 ctime(&start_time.tv_sec)); 237 } 238 argc -= optind; 239 argv += optind; 240 241 if (argc != 2) 242 usage(); 243 244 /* -x must be accompanied by -F */ 245 if (fsoptions.onlyspec != 0 && specfile == NULL) 246 errx(1, "-x requires -F mtree-specfile."); 247 248 /* walk the tree */ 249 TIMER_START(start); 250 root = walk_dir(argv[1], NULL); 251 TIMER_RESULTS(start, "walk_dir"); 252 253 if (specfile) { /* apply a specfile */ 254 TIMER_START(start); 255 apply_specfile(specfile, argv[1], root); 256 TIMER_RESULTS(start, "apply_specfile"); 257 } 258 259 if (debug & DEBUG_DUMP_FSNODES) { 260 printf("\nparent: %s\n", argv[1]); 261 dump_fsnodes(".", root); 262 putchar('\n'); 263 } 264 265 /* build the file system */ 266 TIMER_START(start); 267 fstype->make_fs(argv[0], argv[1], root, &fsoptions); 268 TIMER_RESULTS(start, "make_fs"); 269 270 exit(0); 271 /* NOTREACHED */ 272 } 273 274 275 int 276 set_option(option_t *options, const char *var, const char *val) 277 { 278 int i; 279 280 for (i = 0; options[i].name != NULL; i++) { 281 if (strcmp(options[i].name, var) != 0) 282 continue; 283 *options[i].value = (int)strsuftoll(options[i].desc, val, 284 options[i].minimum, options[i].maximum); 285 return (1); 286 } 287 warnx("Unknown option `%s'", var); 288 return (0); 289 } 290 291 292 static fstype_t * 293 get_fstype(const char *type) 294 { 295 int i; 296 297 for (i = 0; fstypes[i].type != NULL; i++) 298 if (strcmp(fstypes[i].type, type) == 0) 299 return (&fstypes[i]); 300 return (NULL); 301 } 302 303 static void 304 usage(void) 305 { 306 const char *prog; 307 308 prog = getprogname(); 309 fprintf(stderr, 310 "Usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n" 311 "\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-s image-size]\n" 312 "\t[-b free-blocks] [-f free-files] [-F mtree-specfile] [-x]\n" 313 "\t[-N userdb-dir] image-file directory\n", 314 prog); 315 exit(1); 316 } 317