Annotation of src/sbin/newfs/newfs.c, Revision 1.95
1.95 ! christos 1: /* $NetBSD: newfs.c,v 1.94 2006/08/27 18:49:08 christos Exp $ */
1.67 agc 2:
3: /*
4: * Copyright (c) 1983, 1989, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. Neither the name of the University nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
1.18 cgd 31:
1.1 cgd 32: /*
1.64 fvdl 33: * Copyright (c) 2002 Networks Associates Technology, Inc.
34: * All rights reserved.
35: *
36: * This software was developed for the FreeBSD Project by Marshall
37: * Kirk McKusick and Network Associates Laboratories, the Security
38: * Research Division of Network Associates, Inc. under DARPA/SPAWAR
39: * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
40: * research program
41: *
1.1 cgd 42: * Redistribution and use in source and binary forms, with or without
43: * modification, are permitted provided that the following conditions
44: * are met:
45: * 1. Redistributions of source code must retain the above copyright
46: * notice, this list of conditions and the following disclaimer.
47: * 2. Redistributions in binary form must reproduce the above copyright
48: * notice, this list of conditions and the following disclaimer in the
49: * documentation and/or other materials provided with the distribution.
50: * 3. All advertising materials mentioning features or use of this software
51: * must display the following acknowledgement:
52: * This product includes software developed by the University of
53: * California, Berkeley and its contributors.
54: * 4. Neither the name of the University nor the names of its contributors
55: * may be used to endorse or promote products derived from this software
56: * without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68: * SUCH DAMAGE.
69: */
70:
1.25 christos 71: #include <sys/cdefs.h>
1.1 cgd 72: #ifndef lint
1.25 christos 73: __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\n\
74: The Regents of the University of California. All rights reserved.\n");
1.1 cgd 75: #endif /* not lint */
76:
77: #ifndef lint
1.18 cgd 78: #if 0
1.27 lukem 79: static char sccsid[] = "@(#)newfs.c 8.13 (Berkeley) 5/1/95";
1.18 cgd 80: #else
1.95 ! christos 81: __RCSID("$NetBSD: newfs.c,v 1.94 2006/08/27 18:49:08 christos Exp $");
1.18 cgd 82: #endif
1.1 cgd 83: #endif /* not lint */
84:
85: /*
86: * newfs: friendly front end to mkfs
87: */
88: #include <sys/param.h>
89: #include <sys/ioctl.h>
90: #include <sys/disklabel.h>
1.92 christos 91: #include <sys/disk.h>
1.1 cgd 92: #include <sys/file.h>
93: #include <sys/mount.h>
1.19 thorpej 94: #include <sys/sysctl.h>
1.30 drochner 95: #include <sys/wait.h>
1.1 cgd 96:
1.10 mycroft 97: #include <ufs/ufs/dir.h>
1.27 lukem 98: #include <ufs/ufs/dinode.h>
1.32 fvdl 99: #include <ufs/ufs/ufsmount.h>
1.10 mycroft 100: #include <ufs/ffs/fs.h>
101:
102: #include <ctype.h>
1.37 tron 103: #include <disktab.h>
1.54 simonb 104: #include <err.h>
1.1 cgd 105: #include <errno.h>
1.54 simonb 106: #include <grp.h>
1.76 wiz 107: #include <limits.h>
1.10 mycroft 108: #include <paths.h>
1.54 simonb 109: #include <pwd.h>
110: #include <signal.h>
1.76 wiz 111: #include <stdint.h>
1.1 cgd 112: #include <stdio.h>
1.10 mycroft 113: #include <stdlib.h>
1.1 cgd 114: #include <string.h>
1.10 mycroft 115: #include <syslog.h>
116: #include <unistd.h>
1.20 thorpej 117: #include <util.h>
1.95 ! christos 118: #include <mntopts.h>
1.10 mycroft 119:
1.25 christos 120: #include "dkcksum.h"
121: #include "extern.h"
1.92 christos 122: #include "partutil.h"
1.10 mycroft 123:
124: struct mntopt mopts[] = {
125: MOPT_STDOPTS,
126: MOPT_ASYNC,
1.22 cgd 127: MOPT_UPDATE,
1.60 christos 128: MOPT_GETARGS,
1.23 tls 129: MOPT_NOATIME,
1.95 ! christos 130: { .m_option = NULL },
1.10 mycroft 131: };
132:
1.54 simonb 133: static gid_t mfs_group(const char *);
134: static uid_t mfs_user(const char *);
1.75 dsl 135: static int64_t strsuftoi64(const char *, const char *, int64_t, int64_t, int *);
1.92 christos 136: static void usage(void) __attribute__((__noreturn__));
1.1 cgd 137:
138: #define COMPAT /* allow non-labeled disks */
139:
1.92 christos 140: #ifdef COMPAT
141: const char lmsg[] = "%s: can't read disk label; disk type must be specified";
142: #else
143: const char lmsg[] = "%s: can't read disk label";
144: #endif
145:
1.1 cgd 146: /*
147: * The following two constants set the default block and fragment sizes.
148: * Both constants must be a power of 2 and meet the following constraints:
149: * MINBSIZE <= DESBLKSIZE <= MAXBSIZE
150: * sectorsize <= DESFRAGSIZE <= DESBLKSIZE
151: * DESBLKSIZE / DESFRAGSIZE <= 8
152: */
1.53 augustss 153: /*
154: * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults,
155: * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use
156: * L_DFL_*.
157: */
1.54 simonb 158: #define SMALL_FSSIZE (20*1024*2)
1.53 augustss 159: #define S_DFL_FRAGSIZE 512
1.54 simonb 160: #define MEDIUM_FSSIZE (1000*1024*2)
1.53 augustss 161: #define M_DFL_FRAGSIZE 1024
162: #define L_DFL_FRAGSIZE 2048
1.75 dsl 163: #define DFL_FRAG_BLK 8
1.1 cgd 164:
1.65 dbj 165: /* Apple requires the fragment size to be at least APPLEUFS_DIRBLKSIZ
166: * but the block size cannot be larger than Darwin's PAGE_SIZE. See
167: * the mount check in Darwin's ffs_mountfs for an explanation.
168: */
169: #define APPLEUFS_DFL_FRAGSIZE APPLEUFS_DIRBLKSIZ /* 1024 */
170: #define APPLEUFS_DFL_BLKSIZE 4096 /* default Darwin PAGE_SIZE */
171:
1.1 cgd 172: /*
1.43 lukem 173: * Default sector size.
174: */
1.54 simonb 175: #define DFL_SECSIZE 512
1.43 lukem 176:
177: /*
1.1 cgd 178: * MAXBLKPG determines the maximum number of data blocks which are
179: * placed in a single cylinder group. The default is one indirect
180: * block worth of data blocks.
181: */
1.64 fvdl 182: #define MAXBLKPG_UFS1(bsize) ((bsize) / sizeof(int32_t))
183: #define MAXBLKPG_UFS2(bsize) ((bsize) / sizeof(int64_t))
1.1 cgd 184:
185: /*
186: * Each file system has a number of inodes statically allocated.
187: * We allocate one inode slot per NFPI fragments, expecting this
188: * to be far more than we will ever need.
189: */
190: #define NFPI 4
191:
192:
193: int mfs; /* run as the memory based filesystem */
194: int Nflag; /* run without writing file system */
1.64 fvdl 195: int Oflag = 1; /* format as an 4.3BSD file system */
1.88 dsl 196: int verbosity; /* amount of printf() output */
1.94 christos 197: #define DEFAULT_VERBOSITY 3 /* 4 is traditional behavior */
1.64 fvdl 198: int64_t fssize; /* file system size */
1.1 cgd 199: int sectorsize; /* bytes/sector */
200: int fsize = 0; /* fragment size */
201: int bsize = 0; /* block size */
1.64 fvdl 202: int maxbsize = 0; /* maximum clustering */
1.1 cgd 203: int minfree = MINFREE; /* free space threshold */
204: int opt = DEFAULTOPT; /* optimization preference (space or time) */
205: int density; /* number of bytes per inode */
1.84 lukem 206: int num_inodes; /* number of inodes (overrides density) */
1.36 mycroft 207: int maxcontig = 0; /* max contiguous blocks to allocate */
1.1 cgd 208: int maxbpg; /* maximum blocks per file in a cyl group */
1.47 lukem 209: int avgfilesize = AVFILESIZ;/* expected average file size */
210: int avgfpdir = AFPDIR; /* expected number of files per directory */
1.91 christos 211: int mntflags = 0; /* flags to be passed to mount */
1.1 cgd 212: u_long memleft; /* virtual memory available */
213: caddr_t membase; /* start address of memory based filesystem */
1.43 lukem 214: int needswap; /* Filesystem not in native byte order */
1.92 christos 215: char *disktype = NULL;
1.1 cgd 216: int unlabeled;
1.61 dbj 217: char *appleufs_volname = 0; /* Apple UFS volume name */
218: int isappleufs = 0;
1.1 cgd 219:
220: char device[MAXPATHLEN];
221:
1.10 mycroft 222: int
1.40 simonb 223: main(int argc, char *argv[])
1.1 cgd 224: {
1.92 christos 225: struct disk_geom geo;
226: struct dkwedge_info dkw;
1.82 christos 227: struct statvfs *mp;
1.75 dsl 228: struct stat sb;
229: int ch, fsi, fso, len, n, Fflag, Iflag, Zflag;
230: char *cp, *s1, *s2, *special;
1.43 lukem 231: const char *opstring;
1.75 dsl 232: int byte_sized = 0;
1.30 drochner 233: #ifdef MFS
1.79 dsl 234: struct mfs_args args;
1.30 drochner 235: char mountfromname[100];
236: pid_t pid, res;
1.82 christos 237: struct statvfs sf;
1.56 lukem 238: int status;
239: #endif
1.75 dsl 240: mode_t mfsmode = 01777; /* default mode for a /tmp-type directory */
241: uid_t mfsuid = 0; /* user root */
242: gid_t mfsgid = 0; /* group wheel */
1.90 christos 243: mntoptparse_t mo;
1.1 cgd 244:
1.43 lukem 245: cp = NULL;
246: fsi = fso = -1;
1.58 lukem 247: Fflag = Iflag = Zflag = 0;
1.88 dsl 248: verbosity = -1;
1.42 cgd 249: if (strstr(getprogname(), "mfs")) {
1.1 cgd 250: mfs = 1;
1.80 dsl 251: } else {
252: /* Undocumented, for ease of testing */
1.81 dsl 253: if (argv[1] != NULL && !strcmp(argv[1], "-mfs")) {
1.80 dsl 254: argv++;
255: argc--;
256: mfs = 1;
257: }
1.1 cgd 258: }
259:
1.10 mycroft 260: opstring = mfs ?
1.88 dsl 261: "NT:V:a:b:d:e:f:g:h:i:m:n:o:p:s:u:" :
262: "B:FINO:S:T:V:Za:b:d:e:f:g:h:i:l:m:n:o:r:s:v:";
1.26 lukem 263: while ((ch = getopt(argc, argv, opstring)) != -1)
1.10 mycroft 264: switch (ch) {
1.33 bouyer 265: case 'B':
266: if (strcmp(optarg, "be") == 0) {
267: #if BYTE_ORDER == LITTLE_ENDIAN
268: needswap = 1;
269: #endif
270: } else if (strcmp(optarg, "le") == 0) {
271: #if BYTE_ORDER == BIG_ENDIAN
272: needswap = 1;
273: #endif
274: } else
275: usage();
276: break;
1.43 lukem 277: case 'F':
278: Fflag = 1;
279: break;
1.58 lukem 280: case 'I':
281: Iflag = 1;
282: break;
1.10 mycroft 283: case 'N':
284: Nflag = 1;
1.88 dsl 285: if (verbosity == -1)
1.93 christos 286: verbosity = DEFAULT_VERBOSITY;
1.1 cgd 287: break;
1.10 mycroft 288: case 'O':
1.75 dsl 289: Oflag = strsuftoi64("format", optarg, 0, 2, NULL);
1.1 cgd 290: break;
291: case 'S':
1.89 dsl 292: /* XXX: non-512 byte sectors almost certainly don't work. */
1.75 dsl 293: sectorsize = strsuftoi64("sector size",
1.88 dsl 294: optarg, 512, 65536, NULL);
295: if (sectorsize & (sectorsize - 1))
296: errx(1, "sector size `%s' is not a power of 2.",
297: optarg);
1.1 cgd 298: break;
299: #ifdef COMPAT
300: case 'T':
301: disktype = optarg;
302: break;
303: #endif
1.88 dsl 304: case 'V':
305: verbosity = strsuftoi64("verbose", optarg, 0, 4, NULL);
306: break;
1.43 lukem 307: case 'Z':
308: Zflag = 1;
309: break;
1.1 cgd 310: case 'a':
1.75 dsl 311: maxcontig = strsuftoi64("maximum contiguous blocks",
312: optarg, 1, INT_MAX, NULL);
1.1 cgd 313: break;
314: case 'b':
1.75 dsl 315: bsize = strsuftoi64("block size",
316: optarg, MINBSIZE, MAXBSIZE, NULL);
1.1 cgd 317: break;
318: case 'd':
1.75 dsl 319: maxbsize = strsuftoi64("maximum extent size",
320: optarg, 0, INT_MAX, NULL);
1.1 cgd 321: break;
322: case 'e':
1.75 dsl 323: maxbpg = strsuftoi64(
1.43 lukem 324: "blocks per file in a cylinder group",
1.75 dsl 325: optarg, 1, INT_MAX, NULL);
1.1 cgd 326: break;
327: case 'f':
1.75 dsl 328: fsize = strsuftoi64("fragment size",
329: optarg, 1, MAXBSIZE, NULL);
1.1 cgd 330: break;
1.47 lukem 331: case 'g':
1.54 simonb 332: if (mfs)
333: mfsgid = mfs_group(optarg);
334: else {
1.75 dsl 335: avgfilesize = strsuftoi64("average file size",
336: optarg, 1, INT_MAX, NULL);
1.54 simonb 337: }
1.47 lukem 338: break;
339: case 'h':
1.75 dsl 340: avgfpdir = strsuftoi64("expected files per directory",
341: optarg, 1, INT_MAX, NULL);
1.47 lukem 342: break;
1.1 cgd 343: case 'i':
1.75 dsl 344: density = strsuftoi64("bytes per inode",
345: optarg, 1, INT_MAX, NULL);
1.1 cgd 346: break;
347: case 'm':
1.75 dsl 348: minfree = strsuftoi64("free space %",
349: optarg, 0, 99, NULL);
1.1 cgd 350: break;
1.70 dsl 351: case 'n':
1.75 dsl 352: num_inodes = strsuftoi64("number of inodes",
353: optarg, 1, INT_MAX, NULL);
1.70 dsl 354: break;
1.1 cgd 355: case 'o':
1.90 christos 356: if (mfs) {
357: mo = getmntopts(optarg, mopts, &mntflags, 0);
358: if (mo == NULL)
359: err(1, "getmntopts");
360: freemntopts(mo);
361: } else {
1.10 mycroft 362: if (strcmp(optarg, "space") == 0)
363: opt = FS_OPTSPACE;
364: else if (strcmp(optarg, "time") == 0)
365: opt = FS_OPTTIME;
366: else
1.25 christos 367: errx(1, "%s %s",
368: "unknown optimization preference: ",
369: "use `space' or `time'.");
1.10 mycroft 370: }
1.1 cgd 371: break;
372: case 'p':
1.88 dsl 373: /* mfs only */
374: if ((mfsmode = strtol(optarg, NULL, 8)) <= 0)
375: errx(1, "bad mode `%s'", optarg);
1.1 cgd 376: break;
377: case 's':
1.75 dsl 378: fssize = strsuftoi64("file system size",
379: optarg, INT64_MIN, INT64_MAX, &byte_sized);
1.1 cgd 380: break;
381: case 'u':
1.88 dsl 382: /* mfs only */
383: mfsuid = mfs_user(optarg);
1.1 cgd 384: break;
1.61 dbj 385: case 'v':
386: appleufs_volname = optarg;
387: if (strchr(appleufs_volname, ':') || strchr(appleufs_volname, '/'))
388: errx(1,"Apple UFS volume name cannot contain ':' or '/'");
389: if (appleufs_volname[0] == '\0')
390: errx(1,"Apple UFS volume name cannot be zero length");
391: isappleufs = 1;
392: break;
1.1 cgd 393: case '?':
394: default:
395: usage();
396: }
397: argc -= optind;
398: argv += optind;
1.79 dsl 399:
1.88 dsl 400: if (verbosity == -1)
401: /* Default to not showing CG info if mfs */
1.93 christos 402: verbosity = mfs ? 0 : DEFAULT_VERBOSITY;
1.88 dsl 403:
1.79 dsl 404: #ifdef MFS
405: /* This is enough to get through the correct kernel code paths */
406: memset(&args, 0, sizeof args);
407: args.fspec = mountfromname;
1.81 dsl 408: if (mntflags & (MNT_GETARGS | MNT_UPDATE)) {
1.91 christos 409: if ((mntflags & MNT_GETARGS) == 0)
410: mntflags |= MNT_ASYNC;
1.81 dsl 411: if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0)
412: err(1, "mount `%s' failed", argv[1]);
413: if (mntflags & MNT_GETARGS)
414: printf("base=%p, size=%ld\n", args.base, args.size);
415: exit(0);
416: }
1.79 dsl 417: #endif
1.1 cgd 418:
419: if (argc != 2 && (mfs || argc != 1))
420: usage();
421:
1.75 dsl 422: memset(&sb, 0, sizeof sb);
1.1 cgd 423: special = argv[0];
1.49 lukem 424: if (Fflag || mfs) {
1.14 cgd 425: /*
1.75 dsl 426: * It's a file system image or an MFS,
427: * no label, use fixed default for sectorsize.
1.14 cgd 428: */
1.75 dsl 429: if (sectorsize == 0)
1.43 lukem 430: sectorsize = DFL_SECSIZE;
431:
1.80 dsl 432: if (mfs) {
433: /* Default filesystem size to that of supplied device */
434: if (fssize == 0)
435: stat(special, &sb);
436: } else {
437: /* creating image in a regular file */
1.75 dsl 438: int fl;
439: if (Nflag)
440: fl = O_RDONLY;
441: else {
442: if (fssize > 0)
443: fl = O_RDWR | O_CREAT;
444: else
445: fl = O_RDWR;
446: }
447: fsi = open(special, fl, 0777);
448: if (fsi == -1)
1.43 lukem 449: err(1, "can't open file %s", special);
1.75 dsl 450: if (fstat(fsi, &sb) == -1)
451: err(1, "can't fstat opened %s", special);
452: if (!Nflag)
453: fso = fsi;
1.43 lukem 454: }
1.49 lukem 455: } else { /* !Fflag && !mfs */
456: fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0);
457: special = device;
1.75 dsl 458: if (fsi < 0 || fstat(fsi, &sb) == -1)
1.49 lukem 459: err(1, "%s: open for read", special);
460:
1.75 dsl 461: if (!Nflag) {
462: fso = open(special, O_WRONLY, 0);
1.49 lukem 463: if (fso < 0)
464: err(1, "%s: open for write", special);
465:
466: /* Bail if target special is mounted */
467: n = getmntinfo(&mp, MNT_NOWAIT);
468: if (n == 0)
469: err(1, "%s: getmntinfo", special);
470:
471: len = sizeof(_PATH_DEV) - 1;
472: s1 = special;
473: if (strncmp(_PATH_DEV, s1, len) == 0)
474: s1 += len;
475:
476: while (--n >= 0) {
477: s2 = mp->f_mntfromname;
478: if (strncmp(_PATH_DEV, s2, len) == 0) {
479: s2 += len - 1;
480: *s2 = 'r';
481: }
482: if (strcmp(s1, s2) == 0 ||
483: strcmp(s1, &s2[1]) == 0)
484: errx(1, "%s is mounted on %s",
485: special, mp->f_mntonname);
486: ++mp;
1.10 mycroft 487: }
488: }
1.75 dsl 489:
1.1 cgd 490: #ifdef COMPAT
1.49 lukem 491: if (disktype == NULL)
1.10 mycroft 492: disktype = argv[1];
1.1 cgd 493: #endif
1.92 christos 494: if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1)
495: errx(1, lmsg, special);
496: unlabeled = disktype != NULL;
497:
1.75 dsl 498: if (sectorsize == 0) {
1.92 christos 499: sectorsize = geo.dg_secsize;
1.75 dsl 500: if (sectorsize <= 0)
501: errx(1, "no default sector size");
502: }
503:
1.92 christos 504: if (dkw.dkw_parent[0]) {
505: if (dkw.dkw_size == 0)
506: errx(1, "%s partition is unavailable", special);
507:
508: if (strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0)
1.75 dsl 509: isappleufs = 1;
1.92 christos 510:
1.75 dsl 511: if (!Iflag) {
1.92 christos 512: static const char m[] =
513: "%s partition type is not `%s'";
1.75 dsl 514: if (isappleufs) {
1.92 christos 515: if (strcmp(dkw.dkw_ptype,
516: DKW_PTYPE_APPLEUFS))
517: errx(1, m,
518: special, "Apple UFS");
1.75 dsl 519: } else {
1.92 christos 520: if (strcmp(dkw.dkw_ptype,
521: DKW_PTYPE_FFS))
522: errx(1, m, special, "4.2BSD");
1.75 dsl 523: }
524: }
1.92 christos 525: } /* !Fflag && !mfs */
526: }
1.43 lukem 527:
1.75 dsl 528: if (byte_sized)
529: fssize /= sectorsize;
530: if (fssize <= 0) {
531: if (sb.st_size != 0)
532: fssize += sb.st_size / sectorsize;
533: else
1.92 christos 534: fssize += dkw.dkw_size;
1.75 dsl 535: if (fssize <= 0)
536: errx(1, "Unable to determine file system size");
537: }
538:
1.92 christos 539: if (dkw.dkw_parent[0] && fssize > dkw.dkw_size)
1.87 dsl 540: errx(1, "size %" PRIu64 " exceeds maximum file system size on "
1.92 christos 541: "`%s' of %" PRIu64 " sectors",
542: fssize, special, dkw.dkw_size);
1.75 dsl 543:
544: /* XXXLUKEM: only ftruncate() regular files ? (dsl: or at all?) */
545: if (Fflag && fso != -1
546: && ftruncate(fso, (off_t)fssize * sectorsize) == -1)
547: err(1, "can't ftruncate %s to %" PRId64, special, fssize);
548:
549: if (Zflag && fso != -1) { /* pre-zero (and de-sparce) the file */
550: char *buf;
551: int bufsize, i;
552: off_t bufrem;
1.82 christos 553: struct statvfs sfs;
1.75 dsl 554:
1.82 christos 555: if (fstatvfs(fso, &sfs) == -1) {
556: warn("can't fstatvfs `%s'", special);
1.75 dsl 557: bufsize = 8192;
558: } else
559: bufsize = sfs.f_iosize;
560:
561: if ((buf = calloc(1, bufsize)) == NULL)
562: err(1, "can't malloc buffer of %d",
563: bufsize);
564: bufrem = fssize * sectorsize;
1.88 dsl 565: if (verbosity > 0)
566: printf( "Creating file system image in `%s', "
567: "size %lld bytes, in %d byte chunks.\n",
568: special, (long long)bufrem, bufsize);
1.75 dsl 569: while (bufrem > 0) {
570: i = write(fso, buf, MIN(bufsize, bufrem));
571: if (i == -1)
572: err(1, "writing image");
573: bufrem -= i;
574: }
575: free(buf);
1.53 augustss 576: }
577:
1.75 dsl 578: /* Sort out fragment and block sizes */
1.1 cgd 579: if (fsize == 0) {
1.75 dsl 580: fsize = bsize / DFL_FRAG_BLK;
581: if (fsize <= 0) {
582: if (isappleufs) {
583: fsize = APPLEUFS_DFL_FRAGSIZE;
584: } else {
585: if (fssize < SMALL_FSSIZE)
586: fsize = S_DFL_FRAGSIZE;
587: else if (fssize < MEDIUM_FSSIZE)
588: fsize = M_DFL_FRAGSIZE;
589: else
590: fsize = L_DFL_FRAGSIZE;
591: if (fsize < sectorsize)
592: fsize = sectorsize;
593: }
594: }
1.1 cgd 595: }
1.92 christos 596: if (bsize <= 0) {
597: if (isappleufs)
598: bsize = APPLEUFS_DFL_BLKSIZE;
599: else
600: bsize = DFL_FRAG_BLK * fsize;
1.1 cgd 601: }
1.65 dbj 602:
603: if (isappleufs && (fsize < APPLEUFS_DFL_FRAGSIZE)) {
604: warnx("Warning: chosen fsize of %d is less than Apple UFS minimum of %d",
1.75 dsl 605: fsize, APPLEUFS_DFL_FRAGSIZE);
1.65 dbj 606: }
607: if (isappleufs && (bsize > APPLEUFS_DFL_BLKSIZE)) {
608: warnx("Warning: chosen bsize of %d is greater than Apple UFS maximum of %d",
1.75 dsl 609: bsize, APPLEUFS_DFL_BLKSIZE);
1.65 dbj 610: }
611:
1.10 mycroft 612: /*
613: * Maxcontig sets the default for the maximum number of blocks
614: * that may be allocated sequentially. With filesystem clustering
615: * it is possible to allocate contiguous blocks up to the maximum
616: * transfer size permitted by the controller or buffering.
617: */
618: if (maxcontig == 0)
1.27 lukem 619: maxcontig = MAX(1, MIN(MAXPHYS, MAXBSIZE) / bsize);
1.1 cgd 620: if (density == 0)
621: density = NFPI * fsize;
1.8 cgd 622: if (minfree < MINFREE && opt != FS_OPTSPACE) {
1.25 christos 623: warnx("%s %s %d%%", "Warning: changing optimization to space",
624: "because minfree is less than", MINFREE);
1.1 cgd 625: opt = FS_OPTSPACE;
626: }
1.64 fvdl 627: if (maxbpg == 0) {
628: if (Oflag <= 1)
629: maxbpg = MAXBLKPG_UFS1(bsize);
630: else
631: maxbpg = MAXBLKPG_UFS2(bsize);
632: }
1.92 christos 633: mkfs(special, fsi, fso, mfsmode, mfsuid, mfsgid);
1.75 dsl 634: if (fsi != -1 && fsi != fso)
635: close(fsi);
636: if (fso != -1)
1.1 cgd 637: close(fso);
638: #ifdef MFS
639: if (mfs) {
640:
1.30 drochner 641: switch (pid = fork()) {
642: case -1:
643: perror("mfs");
644: exit(10);
645: case 0:
1.34 mycroft 646: (void)snprintf(mountfromname, sizeof(mountfromname),
647: "mfs:%d", getpid());
1.30 drochner 648: break;
649: default:
1.34 mycroft 650: (void)snprintf(mountfromname, sizeof(mountfromname),
651: "mfs:%d", pid);
1.30 drochner 652: for (;;) {
653: /*
654: * spin until the mount succeeds
655: * or the child exits
656: */
657: usleep(1);
658:
659: /*
660: * XXX Here is a race condition: another process
661: * can mount a filesystem which hides our
662: * ramdisk before we see the success.
663: */
1.82 christos 664: if (statvfs(argv[1], &sf) < 0)
665: err(88, "statvfs %s", argv[1]);
1.30 drochner 666: if (!strcmp(sf.f_mntfromname, mountfromname) &&
667: !strncmp(sf.f_mntonname, argv[1],
668: MNAMELEN) &&
669: !strcmp(sf.f_fstypename, "mfs"))
670: exit(0);
671:
672: res = waitpid(pid, &status, WNOHANG);
673: if (res == -1)
674: err(11, "waitpid");
675: if (res != pid)
676: continue;
1.31 drochner 677: if (WIFEXITED(status)) {
678: if (WEXITSTATUS(status) == 0)
679: exit(0);
1.30 drochner 680: errx(1, "%s: mount: %s", argv[1],
681: strerror(WEXITSTATUS(status)));
1.31 drochner 682: } else
1.30 drochner 683: errx(11, "abnormal termination");
684: }
685: /* NOTREACHED */
686: }
687:
688: (void) setsid();
689: (void) close(0);
690: (void) close(1);
691: (void) close(2);
692: (void) chdir("/");
693:
1.1 cgd 694: args.base = membase;
695: args.size = fssize * sectorsize;
1.91 christos 696: if (mount(MOUNT_MFS, argv[1], mntflags | MNT_ASYNC, &args) < 0)
1.30 drochner 697: exit(errno); /* parent prints message */
1.1 cgd 698: }
699: #endif
700: exit(0);
701: }
702:
1.54 simonb 703: static gid_t
704: mfs_group(const char *gname)
705: {
706: struct group *gp;
707:
708: if (!(gp = getgrnam(gname)) && !isdigit((unsigned char)*gname))
709: errx(1, "unknown gname %s", gname);
710: return gp ? gp->gr_gid : atoi(gname);
711: }
712:
713: static uid_t
714: mfs_user(const char *uname)
715: {
716: struct passwd *pp;
717:
718: if (!(pp = getpwnam(uname)) && !isdigit((unsigned char)*uname))
719: errx(1, "unknown user %s", uname);
720: return pp ? pp->pw_uid : atoi(uname);
721: }
722:
1.75 dsl 723: static int64_t
724: strsuftoi64(const char *desc, const char *arg, int64_t min, int64_t max, int *num_suffix)
1.43 lukem 725: {
1.75 dsl 726: int64_t result, r1;
727: int shift = 0;
1.43 lukem 728: char *ep;
729:
730: errno = 0;
1.75 dsl 731: r1 = strtoll(arg, &ep, 10);
1.43 lukem 732: if (ep[0] != '\0' && ep[1] != '\0')
733: errx(1, "%s `%s' is not a valid number.", desc, arg);
1.75 dsl 734: switch (ep[0]) {
1.43 lukem 735: case '\0':
1.75 dsl 736: case 's': case 'S':
737: if (num_suffix != NULL)
738: *num_suffix = 0;
1.43 lukem 739: break;
1.75 dsl 740: case 'g': case 'G':
741: shift += 10;
742: /* FALLTHROUGH */
743: case 'm': case 'M':
744: shift += 10;
745: /* FALLTHROUGH */
746: case 'k': case 'K':
747: shift += 10;
748: /* FALLTHROUGH */
749: case 'b': case 'B':
750: if (num_suffix != NULL)
751: *num_suffix = 1;
1.43 lukem 752: break;
753: default:
754: errx(1, "`%s' is not a valid suffix for %s.", ep, desc);
755: }
1.75 dsl 756: result = r1 << shift;
757: if (errno == ERANGE || result >> shift != r1)
758: errx(1, "%s `%s' is too large to convert.", desc, arg);
1.43 lukem 759: if (result < min)
1.75 dsl 760: errx(1, "%s `%s' (%" PRId64 ") is less than the minimum (%" PRId64 ").",
1.43 lukem 761: desc, arg, result, min);
762: if (result > max)
1.75 dsl 763: errx(1, "%s `%s' (%" PRId64 ") is greater than the maximum (%" PRId64 ").",
1.43 lukem 764: desc, arg, result, max);
1.75 dsl 765: return result;
1.43 lukem 766: }
767:
1.54 simonb 768: #define NEWFS 1
769: #define MFS_MOUNT 2
770: #define BOTH NEWFS | MFS_MOUNT
771:
772: struct help_strings {
773: int flags;
774: const char *str;
775: } const help_strings[] = {
776: { NEWFS, "-B byteorder\tbyte order (`be' or `le')" },
777: { NEWFS, "-F \t\tcreate file system image in regular file" },
1.58 lukem 778: { NEWFS, "-I \t\tdo not check that the file system type is '4.2BSD'" },
1.54 simonb 779: { BOTH, "-N \t\tdo not create file system, just print out "
780: "parameters" },
1.75 dsl 781: { NEWFS, "-O N\t\tfilesystem format: 0 ==> 4.3BSD, 1 ==> FFS, 2 ==> UFS2" },
1.54 simonb 782: { NEWFS, "-S secsize\tsector size" },
783: #ifdef COMPAT
784: { NEWFS, "-T disktype\tdisk type" },
785: #endif
1.89 dsl 786: { BOTH, "-V verbose\toutput verbosity: 0 ==> none, 4 ==> max" },
1.75 dsl 787: { NEWFS, "-Z \t\tpre-zero the image file" },
1.54 simonb 788: { BOTH, "-a maxcontig\tmaximum contiguous blocks" },
789: { BOTH, "-b bsize\tblock size" },
1.75 dsl 790: { BOTH, "-d maxbsize\tmaximum extent size" },
1.54 simonb 791: { BOTH, "-e maxbpg\tmaximum blocks per file in a cylinder group"
792: },
793: { BOTH, "-f fsize\tfrag size" },
794: { NEWFS, "-g avgfilesize\taverage file size" },
795: { MFS_MOUNT, "-g groupname\tgroup name of mount point" },
796: { BOTH, "-h avgfpdir\taverage files per directory" },
797: { BOTH, "-i density\tnumber of bytes per inode" },
798: { BOTH, "-m minfree\tminimum free space %%" },
1.78 jmmv 799: { BOTH, "-n inodes\tnumber of inodes (overrides -i density)" },
1.54 simonb 800: { BOTH, "-o optim\toptimization preference (`space' or `time')"
801: },
802: { MFS_MOUNT, "-p perm\t\tpermissions (in octal)" },
803: { BOTH, "-s fssize\tfile system size (sectors)" },
804: { MFS_MOUNT, "-u username\tuser name of mount point" },
1.61 dbj 805: { NEWFS, "-v volname\tApple UFS volume name" },
1.54 simonb 806: { 0, NULL }
807: };
808:
1.25 christos 809: static void
1.40 simonb 810: usage(void)
1.1 cgd 811: {
1.54 simonb 812: int match;
813: const struct help_strings *hs;
1.43 lukem 814:
1.1 cgd 815: if (mfs) {
816: fprintf(stderr,
1.43 lukem 817: "usage: %s [ fsoptions ] special-device mount-point\n",
1.42 cgd 818: getprogname());
1.1 cgd 819: } else
820: fprintf(stderr,
1.43 lukem 821: "usage: %s [ fsoptions ] special-device%s\n",
1.42 cgd 822: getprogname(),
1.1 cgd 823: #ifdef COMPAT
1.75 dsl 824: " [disk-type]");
1.1 cgd 825: #else
826: "");
827: #endif
828: fprintf(stderr, "where fsoptions are:\n");
1.54 simonb 829:
830: match = mfs ? MFS_MOUNT : NEWFS;
831: for (hs = help_strings; hs->flags != 0; hs++)
832: if (hs->flags & match)
833: fprintf(stderr, "\t%s\n", hs->str);
1.1 cgd 834: exit(1);
835: }
CVSweb <webmaster@jp.NetBSD.org>