1*da5362d5Sguenther /* $OpenBSD: newfs.c,v 1.118 2024/01/09 03:16:00 guenther Exp $ */
24b826ba8Sderaadt /* $NetBSD: newfs.c,v 1.20 1996/05/16 07:13:03 thorpej Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5992d7f77Smillert * Copyright (c) 2002 Networks Associates Technology, Inc.
6992d7f77Smillert * All rights reserved.
7992d7f77Smillert *
8992d7f77Smillert * This software was developed for the FreeBSD Project by Marshall
9992d7f77Smillert * Kirk McKusick and Network Associates Laboratories, the Security
10992d7f77Smillert * Research Division of Network Associates, Inc. under DARPA/SPAWAR
11992d7f77Smillert * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
12992d7f77Smillert * research program.
13992d7f77Smillert *
14df930be7Sderaadt * Copyright (c) 1983, 1989, 1993, 1994
15df930be7Sderaadt * The Regents of the University of California. All rights reserved.
16df930be7Sderaadt *
17df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
18df930be7Sderaadt * modification, are permitted provided that the following conditions
19df930be7Sderaadt * are met:
20df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
21df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
22df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
23df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
24df930be7Sderaadt * documentation and/or other materials provided with the distribution.
251ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
26df930be7Sderaadt * may be used to endorse or promote products derived from this software
27df930be7Sderaadt * without specific prior written permission.
28df930be7Sderaadt *
29df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39df930be7Sderaadt * SUCH DAMAGE.
40df930be7Sderaadt */
41df930be7Sderaadt
4278eb0b7eSderaadt #include <sys/param.h> /* DEV_BSIZE MAXBSIZE */
4309758f56Sotto #include <sys/types.h>
44df930be7Sderaadt #include <sys/stat.h>
45df930be7Sderaadt #include <sys/ioctl.h>
4691f4f7d8Sdlg #include <sys/dkio.h>
47df930be7Sderaadt #include <sys/disklabel.h>
48df930be7Sderaadt #include <sys/mount.h>
4984990f89Smillert #include <sys/resource.h>
50df930be7Sderaadt #include <sys/sysctl.h>
51379bc20eSmarkus #include <sys/wait.h>
52df930be7Sderaadt
53992d7f77Smillert #include <ufs/ufs/dinode.h>
54df930be7Sderaadt #include <ufs/ufs/dir.h>
55df930be7Sderaadt #include <ufs/ffs/fs.h>
56df930be7Sderaadt
57df930be7Sderaadt #include <ctype.h>
5809758f56Sotto #include <err.h>
59df930be7Sderaadt #include <errno.h>
6001a83688Smillert #include <fcntl.h>
61df930be7Sderaadt #include <paths.h>
62e7beb4a7Smillert #include <stdarg.h>
63df930be7Sderaadt #include <stdio.h>
64df930be7Sderaadt #include <stdlib.h>
65df930be7Sderaadt #include <string.h>
66df930be7Sderaadt #include <syslog.h>
67df930be7Sderaadt #include <unistd.h>
68b9fc9a72Sderaadt #include <limits.h>
69379bc20eSmarkus #include <signal.h>
704b826ba8Sderaadt #include <util.h>
71df930be7Sderaadt
72df930be7Sderaadt #include "mntopts.h"
73212ed4daSderaadt #include "pathnames.h"
74df930be7Sderaadt
75b9fc9a72Sderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
76b9fc9a72Sderaadt #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
77b9fc9a72Sderaadt
78df930be7Sderaadt struct mntopt mopts[] = {
79df930be7Sderaadt MOPT_STDOPTS,
80646b1d5bSderaadt MOPT_WXALLOWED,
812fadc172Snatano MOPT_NOPERM,
82df930be7Sderaadt MOPT_ASYNC,
835b76cadbSmillert MOPT_UPDATE,
84d3eb3845Stedu MOPT_FORCE,
85df930be7Sderaadt { NULL },
86df930be7Sderaadt };
87df930be7Sderaadt
88688df7cfSguenther void fatal(const char *fmt, ...)
89688df7cfSguenther __attribute__((__format__ (printf, 1, 2)))
90688df7cfSguenther __attribute__((__nonnull__ (1)));
91bb33d2d4Sthib __dead void usage(void);
9209758f56Sotto void mkfs(struct partition *, char *, int, int, mode_t, uid_t, gid_t);
93e384f6efSderaadt void getphysmem(void);
94c72b5b24Smillert void rewritelabel(char *, int, struct disklabel *);
95c72b5b24Smillert u_short dkcksum(struct disklabel *);
96df930be7Sderaadt
97df930be7Sderaadt /*
98df930be7Sderaadt * The following two constants set the default block and fragment sizes.
99df930be7Sderaadt * Both constants must be a power of 2 and meet the following constraints:
100df930be7Sderaadt * MINBSIZE <= DESBLKSIZE <= MAXBSIZE
101df930be7Sderaadt * sectorsize <= DESFRAGSIZE <= DESBLKSIZE
102df930be7Sderaadt * DESBLKSIZE / DESFRAGSIZE <= 8
103df930be7Sderaadt */
104f02d0dacStedu #define DFL_FRAGSIZE 2048
105f02d0dacStedu #define DFL_BLKSIZE 16384
106df930be7Sderaadt
107df930be7Sderaadt /*
108df930be7Sderaadt * MAXBLKPG determines the maximum number of data blocks which are
109df930be7Sderaadt * placed in a single cylinder group. The default is one indirect
110df930be7Sderaadt * block worth of data blocks.
111df930be7Sderaadt */
112c29211cfSpedro #define MAXBLKPG_FFS1(bsize) ((bsize) / sizeof(int32_t))
113c29211cfSpedro #define MAXBLKPG_FFS2(bsize) ((bsize) / sizeof(int64_t))
114df930be7Sderaadt
115df930be7Sderaadt /*
116df930be7Sderaadt * Each file system has a number of inodes statically allocated.
117df930be7Sderaadt * We allocate one inode slot per NFPI fragments, expecting this
118df930be7Sderaadt * to be far more than we will ever need.
119df930be7Sderaadt */
120df930be7Sderaadt #define NFPI 4
121df930be7Sderaadt
122df930be7Sderaadt int mfs; /* run as the memory based filesystem */
123df930be7Sderaadt int Nflag; /* run without writing file system */
124*da5362d5Sguenther int Oflag = 2; /* 1 = 4.4BSD ffs, 2 = ffs2 */
1257d3d8764Skrw daddr_t fssize; /* file system size in 512-byte blocks */
126f3095649Sdcoppa long long sectorsize; /* bytes/sector */
127df930be7Sderaadt int fsize = 0; /* fragment size */
128df930be7Sderaadt int bsize = 0; /* block size */
1295d5f5f99Sotto int maxfrgspercg = INT_MAX; /* maximum fragments per cylinder group */
130df930be7Sderaadt int minfree = MINFREE; /* free space threshold */
131df930be7Sderaadt int opt = DEFAULTOPT; /* optimization preference (space or time) */
1321c6dacc2Sderaadt int reqopt = -1; /* opt preference has not been specified */
133df930be7Sderaadt int density; /* number of bytes per inode */
134df930be7Sderaadt int maxbpg; /* maximum blocks per file in a cyl group */
135be7bc953Sgluk int avgfilesize = AVFILESIZ;/* expected average file size */
136be7bc953Sgluk int avgfilesperdir = AFPDIR;/* expected number of files per directory */
137df930be7Sderaadt int mntflags = MNT_ASYNC; /* flags to be passed to mount */
138a342ea92Smillert int quiet = 0; /* quiet flag */
139df930be7Sderaadt caddr_t membase; /* start address of memory based filesystem */
140df930be7Sderaadt char *disktype;
141df930be7Sderaadt int unlabeled;
1427ff490a9Smillert
1437ff490a9Smillert extern char *__progname;
144b884d431Sderaadt struct disklabel *getdisklabel(char *, int);
145df930be7Sderaadt
146cb48e966Sotto #ifdef MFS
14757f202e1Sotto static void waitformount(char *, pid_t);
14809758f56Sotto static int do_exec(const char *, const char *, char *const[]);
14909758f56Sotto static int isdir(const char *);
15057f202e1Sotto static void copy(char *, char *);
15109758f56Sotto static int gettmpmnt(char *, size_t);
152cb48e966Sotto #endif
15309758f56Sotto
154e384f6efSderaadt int64_t physmem;
155e384f6efSderaadt
156e384f6efSderaadt void
getphysmem(void)157e384f6efSderaadt getphysmem(void)
158e384f6efSderaadt {
159e384f6efSderaadt int mib[] = { CTL_HW, HW_PHYSMEM64 };
160e384f6efSderaadt size_t len = sizeof(physmem);
161e384f6efSderaadt
162e384f6efSderaadt if (sysctl(mib, 2, &physmem, &len, NULL, 0) != 0)
163e384f6efSderaadt err(1, "can't get physmem");
164e384f6efSderaadt }
165e384f6efSderaadt
166df930be7Sderaadt int
main(int argc,char * argv[])1678809fabbSderaadt main(int argc, char *argv[])
168df930be7Sderaadt {
169e073c79dSmpech int ch;
170e073c79dSmpech struct partition *pp;
171e073c79dSmpech struct disklabel *lp;
172df930be7Sderaadt struct disklabel mfsfakelabel;
173df930be7Sderaadt struct partition oldpartition;
174df930be7Sderaadt struct stat st;
175df930be7Sderaadt struct statfs *mp;
17684990f89Smillert struct rlimit rl;
17746d12c8bSkrw int fsi = -1, oflagset = 0, fso, len, n, maxpartitions;
1784171005eSjsing char *cp = NULL, *s1, *s2, *special, *opstring, *realdev;
179379bc20eSmarkus #ifdef MFS
180379bc20eSmarkus char mountfromname[BUFSIZ];
181b9fc9a72Sderaadt char *pop = NULL, node[PATH_MAX];
18257f202e1Sotto pid_t pid;
18309758f56Sotto struct stat mountpoint;
184379bc20eSmarkus #endif
185aaee66d3Smillert uid_t mfsuid = 0;
186aaee66d3Smillert gid_t mfsgid = 0;
187aaee66d3Smillert mode_t mfsmode = 0;
188212ed4daSderaadt char *fstype = NULL;
189212ed4daSderaadt char **saveargv = argv;
190ddfcbf38Sotto int ffsflag = 1;
1912a1e93e1Smillert const char *errstr;
192f3095649Sdcoppa long long fssize_input = 0;
193f3095649Sdcoppa int fssize_usebytes = 0;
19483d1f402Sotto int defaultfsize;
1957d3d8764Skrw u_int64_t nsecs;
196df930be7Sderaadt
1977ff490a9Smillert if (strstr(__progname, "mfs"))
1981a758a47Ssthen mfs = Nflag = quiet = Oflag = 1;
199df930be7Sderaadt
200e384f6efSderaadt getphysmem();
201df930be7Sderaadt maxpartitions = getmaxpartitions();
202df930be7Sderaadt if (maxpartitions > 26)
203df930be7Sderaadt fatal("insane maxpartitions value %d", maxpartitions);
204df930be7Sderaadt
205df930be7Sderaadt opstring = mfs ?
2069320ea12Ssthen "O:P:T:b:c:e:f:i:m:o:s:" :
207135ffea9Smillert "NO:S:T:b:c:e:f:g:h:i:m:o:qs:t:";
20872799b18Smillert while ((ch = getopt(argc, argv, opstring)) != -1) {
209df930be7Sderaadt switch (ch) {
210df930be7Sderaadt case 'N':
211df930be7Sderaadt Nflag = 1;
212df930be7Sderaadt break;
213df930be7Sderaadt case 'O':
214*da5362d5Sguenther Oflag = strtonum(optarg, 1, 2, &errstr);
215992d7f77Smillert if (errstr)
216992d7f77Smillert fatal("%s: invalid ffs version", optarg);
21746d12c8bSkrw oflagset = 1;
218df930be7Sderaadt break;
219df930be7Sderaadt case 'S':
220f3095649Sdcoppa if (scan_scaled(optarg, §orsize) == -1 ||
221f3095649Sdcoppa sectorsize <= 0 || (sectorsize % DEV_BSIZE))
222f3095649Sdcoppa fatal("sector size invalid: %s", optarg);
223df930be7Sderaadt break;
224df930be7Sderaadt case 'T':
225df930be7Sderaadt disktype = optarg;
226df930be7Sderaadt break;
227df930be7Sderaadt case 'b':
2282a1e93e1Smillert bsize = strtonum(optarg, MINBSIZE, MAXBSIZE, &errstr);
2292a1e93e1Smillert if (errstr)
2302a1e93e1Smillert fatal("block size is %s: %s", errstr, optarg);
231df930be7Sderaadt break;
232df930be7Sderaadt case 'c':
2335d5f5f99Sotto maxfrgspercg = strtonum(optarg, 1, INT_MAX, &errstr);
2342a1e93e1Smillert if (errstr)
2355d5f5f99Sotto fatal("fragments per cylinder group is %s: %s",
2362a1e93e1Smillert errstr, optarg);
237df930be7Sderaadt break;
238df930be7Sderaadt case 'e':
2392a1e93e1Smillert maxbpg = strtonum(optarg, 1, INT_MAX, &errstr);
2402a1e93e1Smillert if (errstr)
2412a1e93e1Smillert fatal("blocks per file in a cylinder group is"
2422a1e93e1Smillert " %s: %s", errstr, optarg);
243df930be7Sderaadt break;
244df930be7Sderaadt case 'f':
2452a1e93e1Smillert fsize = strtonum(optarg, MINBSIZE / MAXFRAG, MAXBSIZE,
2462a1e93e1Smillert &errstr);
2472a1e93e1Smillert if (errstr)
2482a1e93e1Smillert fatal("fragment size is %s: %s",
2492a1e93e1Smillert errstr, optarg);
250df930be7Sderaadt break;
251be7bc953Sgluk case 'g':
2522a1e93e1Smillert avgfilesize = strtonum(optarg, 1, INT_MAX, &errstr);
2532a1e93e1Smillert if (errstr)
2542a1e93e1Smillert fatal("average file size is %s: %s",
2552a1e93e1Smillert errstr, optarg);
256be7bc953Sgluk break;
257be7bc953Sgluk case 'h':
2582a1e93e1Smillert avgfilesperdir = strtonum(optarg, 1, INT_MAX, &errstr);
2592a1e93e1Smillert if (errstr)
2602a1e93e1Smillert fatal("average files per dir is %s: %s",
2612a1e93e1Smillert errstr, optarg);
262be7bc953Sgluk break;
263df930be7Sderaadt case 'i':
2642a1e93e1Smillert density = strtonum(optarg, 1, INT_MAX, &errstr);
2652a1e93e1Smillert if (errstr)
2662a1e93e1Smillert fatal("bytes per inode is %s: %s",
2672a1e93e1Smillert errstr, optarg);
268df930be7Sderaadt break;
269df930be7Sderaadt case 'm':
2702a1e93e1Smillert minfree = strtonum(optarg, 0, 99, &errstr);
2712a1e93e1Smillert if (errstr)
2722a1e93e1Smillert fatal("free space %% is %s: %s",
2732a1e93e1Smillert errstr, optarg);
274df930be7Sderaadt break;
275df930be7Sderaadt case 'o':
276df930be7Sderaadt if (mfs)
277df930be7Sderaadt getmntopts(optarg, mopts, &mntflags);
278df930be7Sderaadt else {
279df930be7Sderaadt if (strcmp(optarg, "space") == 0)
2801c6dacc2Sderaadt reqopt = opt = FS_OPTSPACE;
281df930be7Sderaadt else if (strcmp(optarg, "time") == 0)
2821c6dacc2Sderaadt reqopt = opt = FS_OPTTIME;
283df930be7Sderaadt else
2848809fabbSderaadt fatal("%s: unknown optimization "
2855bf09c74Sotto "preference: use `space' or `time'.",
2865bf09c74Sotto optarg);
287df930be7Sderaadt }
288df930be7Sderaadt break;
289a342ea92Smillert case 'q':
290a342ea92Smillert quiet = 1;
291a342ea92Smillert break;
292df930be7Sderaadt case 's':
293f3095649Sdcoppa if (scan_scaled(optarg, &fssize_input) == -1 ||
294f3095649Sdcoppa fssize_input <= 0)
295f3095649Sdcoppa fatal("file system size invalid: %s", optarg);
296f3095649Sdcoppa fssize_usebytes = 0; /* in case of multiple -s */
297f3095649Sdcoppa for (s1 = optarg; *s1 != '\0'; s1++)
298025f5691Sderaadt if (isalpha((unsigned char)*s1)) {
299f3095649Sdcoppa fssize_usebytes = 1;
300f3095649Sdcoppa break;
301f3095649Sdcoppa }
302df930be7Sderaadt break;
303212ed4daSderaadt case 't':
304212ed4daSderaadt fstype = optarg;
305212ed4daSderaadt if (strcmp(fstype, "ffs"))
306ddfcbf38Sotto ffsflag = 0;
307df930be7Sderaadt break;
30809758f56Sotto #ifdef MFS
30909758f56Sotto case 'P':
31009758f56Sotto pop = optarg;
31109758f56Sotto break;
31209758f56Sotto #endif
313df930be7Sderaadt default:
314df930be7Sderaadt usage();
315df930be7Sderaadt }
316ddfcbf38Sotto if (!ffsflag)
317212ed4daSderaadt break;
318212ed4daSderaadt }
319df930be7Sderaadt argc -= optind;
320df930be7Sderaadt argv += optind;
321df930be7Sderaadt
322ddfcbf38Sotto if (ffsflag && argc - mfs != 1)
323df930be7Sderaadt usage();
324df930be7Sderaadt
32564da5382Sotto if (mfs) {
32684990f89Smillert /* Increase our data size to the max */
32784990f89Smillert if (getrlimit(RLIMIT_DATA, &rl) == 0) {
32884990f89Smillert rl.rlim_cur = rl.rlim_max;
32984990f89Smillert (void)setrlimit(RLIMIT_DATA, &rl);
33084990f89Smillert }
33164da5382Sotto }
33284990f89Smillert
333df930be7Sderaadt special = argv[0];
33461a439ceStedu
335212ed4daSderaadt if (!mfs) {
336b9fc9a72Sderaadt char execname[PATH_MAX], name[PATH_MAX];
337212ed4daSderaadt
338212ed4daSderaadt if (fstype == NULL)
33957bc3e67Sdownsj fstype = readlabelfs(special, 0);
34004d18058Smillert if (fstype != NULL && strcmp(fstype, "ffs")) {
341db6880e2Sderaadt snprintf(name, sizeof name, "newfs_%s", fstype);
342212ed4daSderaadt saveargv[0] = name;
343db6880e2Sderaadt snprintf(execname, sizeof execname, "%s/newfs_%s",
344db6880e2Sderaadt _PATH_SBIN, fstype);
345db6880e2Sderaadt (void)execv(execname, saveargv);
346db6880e2Sderaadt snprintf(execname, sizeof execname, "%s/newfs_%s",
347db6880e2Sderaadt _PATH_USRSBIN, fstype);
348db6880e2Sderaadt (void)execv(execname, saveargv);
349212ed4daSderaadt err(1, "%s not found", name);
350212ed4daSderaadt }
351212ed4daSderaadt }
352212ed4daSderaadt
353df930be7Sderaadt if (mfs && !strcmp(special, "swap")) {
354df930be7Sderaadt /*
355df930be7Sderaadt * it's an MFS, mounted on "swap." fake up a label.
356df930be7Sderaadt * XXX XXX XXX
357df930be7Sderaadt */
358df930be7Sderaadt fso = -1; /* XXX; normally done below. */
359df930be7Sderaadt
360df930be7Sderaadt memset(&mfsfakelabel, 0, sizeof(mfsfakelabel));
361df930be7Sderaadt mfsfakelabel.d_secsize = 512;
362df930be7Sderaadt mfsfakelabel.d_nsectors = 64;
363df930be7Sderaadt mfsfakelabel.d_ntracks = 16;
364df930be7Sderaadt mfsfakelabel.d_ncylinders = 16;
365df930be7Sderaadt mfsfakelabel.d_secpercyl = 1024;
366862ef960Skrw DL_SETDSIZE(&mfsfakelabel, 16384);
367df930be7Sderaadt mfsfakelabel.d_npartitions = 1;
368a76c6fffSotto mfsfakelabel.d_version = 1;
369a76c6fffSotto DL_SETPSIZE(&mfsfakelabel.d_partitions[0], 16384);
370ddfcbf38Sotto mfsfakelabel.d_partitions[0].p_fragblock =
371ddfcbf38Sotto DISKLABELV1_FFS_FRAGBLOCK(1024, 8);
372df930be7Sderaadt mfsfakelabel.d_partitions[0].p_cpg = 16;
373df930be7Sderaadt
374df930be7Sderaadt lp = &mfsfakelabel;
375df930be7Sderaadt pp = &mfsfakelabel.d_partitions[0];
376df930be7Sderaadt
377df930be7Sderaadt goto havelabel;
378df930be7Sderaadt }
379df930be7Sderaadt if (Nflag) {
380df930be7Sderaadt fso = -1;
381df930be7Sderaadt } else {
3824171005eSjsing fso = opendev(special, O_WRONLY, 0, &realdev);
383df69c215Sderaadt if (fso == -1)
384df930be7Sderaadt fatal("%s: %s", special, strerror(errno));
3854171005eSjsing special = realdev;
386df930be7Sderaadt
387df930be7Sderaadt /* Bail if target special is mounted */
388df930be7Sderaadt n = getmntinfo(&mp, MNT_NOWAIT);
389df930be7Sderaadt if (n == 0)
390df930be7Sderaadt fatal("%s: getmntinfo: %s", special, strerror(errno));
391df930be7Sderaadt
392df930be7Sderaadt len = sizeof(_PATH_DEV) - 1;
393df930be7Sderaadt s1 = special;
394df930be7Sderaadt if (strncmp(_PATH_DEV, s1, len) == 0)
395df930be7Sderaadt s1 += len;
396df930be7Sderaadt
397df930be7Sderaadt while (--n >= 0) {
398df930be7Sderaadt s2 = mp->f_mntfromname;
399df930be7Sderaadt if (strncmp(_PATH_DEV, s2, len) == 0) {
400df930be7Sderaadt s2 += len - 1;
401df930be7Sderaadt *s2 = 'r';
402df930be7Sderaadt }
403df930be7Sderaadt if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0)
404df930be7Sderaadt fatal("%s is mounted on %s",
405df930be7Sderaadt special, mp->f_mntonname);
406df930be7Sderaadt ++mp;
407df930be7Sderaadt }
408df930be7Sderaadt }
409df930be7Sderaadt if (mfs && disktype != NULL) {
410df930be7Sderaadt lp = (struct disklabel *)getdiskbyname(disktype);
411df930be7Sderaadt if (lp == NULL)
412df930be7Sderaadt fatal("%s: unknown disk type", disktype);
413df930be7Sderaadt pp = &lp->d_partitions[1];
414aaee66d3Smillert } else {
4154171005eSjsing fsi = opendev(special, O_RDONLY, 0, NULL);
416df69c215Sderaadt if (fsi == -1)
417df930be7Sderaadt fatal("%s: %s", special, strerror(errno));
418df69c215Sderaadt if (fstat(fsi, &st) == -1)
419df930be7Sderaadt fatal("%s: %s", special, strerror(errno));
420e0b2f5c5Sotto if (!mfs) {
421e0b2f5c5Sotto if (S_ISBLK(st.st_mode))
422e0b2f5c5Sotto fatal("%s: block device", special);
423e0b2f5c5Sotto if (!S_ISCHR(st.st_mode))
424e0b2f5c5Sotto warnx("%s: not a character-special device",
425992d7f77Smillert special);
426e0b2f5c5Sotto }
4274d4ccfdfStobias if (*argv[0] == '\0')
4284d4ccfdfStobias fatal("empty partition name supplied");
4294d4ccfdfStobias cp = argv[0] + strlen(argv[0]) - 1;
4304d4ccfdfStobias if ((*cp < 'a' || *cp > ('a' + maxpartitions - 1))
4314d4ccfdfStobias && !isdigit((unsigned char)*cp))
432df930be7Sderaadt fatal("%s: can't figure out file system partition",
433df930be7Sderaadt argv[0]);
434df930be7Sderaadt lp = getdisklabel(special, fsi);
4350586998eSkettenis if (!mfs) {
436e384f6efSderaadt if (pledge("stdio disklabel tty", NULL) == -1)
437e384f6efSderaadt err(1, "pledge");
4380586998eSkettenis }
439025f5691Sderaadt if (isdigit((unsigned char)*cp))
440df930be7Sderaadt pp = &lp->d_partitions[0];
441df930be7Sderaadt else
442df930be7Sderaadt pp = &lp->d_partitions[*cp - 'a'];
443a76c6fffSotto if (DL_GETPSIZE(pp) == 0)
444df930be7Sderaadt fatal("%s: `%c' partition is unavailable",
445df930be7Sderaadt argv[0], *cp);
446df930be7Sderaadt }
447df930be7Sderaadt havelabel:
448df930be7Sderaadt if (sectorsize == 0) {
449df930be7Sderaadt sectorsize = lp->d_secsize;
450df930be7Sderaadt if (sectorsize <= 0)
451df930be7Sderaadt fatal("%s: no default sector size", argv[0]);
452df930be7Sderaadt }
453f3095649Sdcoppa
454f3095649Sdcoppa if (fssize_usebytes) {
4557d3d8764Skrw nsecs = fssize_input / sectorsize;
4567d3d8764Skrw if (fssize_input % sectorsize != 0)
4577d3d8764Skrw nsecs++;
458f3095649Sdcoppa } else if (fssize_input == 0)
4597d3d8764Skrw nsecs = DL_GETPSIZE(pp);
460f3095649Sdcoppa else
4617d3d8764Skrw nsecs = fssize_input;
462f3095649Sdcoppa
4637d3d8764Skrw if (nsecs > DL_GETPSIZE(pp) && !mfs)
464f3095649Sdcoppa fatal("%s: maximum file system size on the `%c' partition is "
4657d3d8764Skrw "%llu sectors", argv[0], *cp, DL_GETPSIZE(pp));
466f3095649Sdcoppa
4678d8e23f9Skrw /* Can't use DL_SECTOBLK() because sectorsize may not be from label! */
4688d8e23f9Skrw fssize = nsecs * (sectorsize / DEV_BSIZE);
46946d12c8bSkrw if (oflagset == 0 && fssize >= INT_MAX)
47046d12c8bSkrw Oflag = 2; /* FFS2 */
47183d1f402Sotto defaultfsize = fsize == 0;
472df930be7Sderaadt if (fsize == 0) {
473ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
474df930be7Sderaadt if (fsize <= 0)
475b9fc9a72Sderaadt fsize = MAXIMUM(DFL_FRAGSIZE, lp->d_secsize);
476df930be7Sderaadt }
477df930be7Sderaadt if (bsize == 0) {
478ddfcbf38Sotto bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock);
479df930be7Sderaadt if (bsize <= 0)
480b9fc9a72Sderaadt bsize = MINIMUM(DFL_BLKSIZE, 8 * fsize);
481df930be7Sderaadt }
48283d1f402Sotto if (density == 0) {
4831f7812f8Skrw density = NFPI * fsize;
48483d1f402Sotto /* large sectors lead to fewer inodes due to large fsize,
48583d1f402Sotto compensate */
48683d1f402Sotto if (defaultfsize && sectorsize > DEV_BSIZE)
48783d1f402Sotto density /= 2;
48883d1f402Sotto }
4891c6dacc2Sderaadt if (minfree < MINFREE && opt != FS_OPTSPACE && reqopt == -1) {
490992d7f77Smillert warnx("warning: changing optimization to space "
491992d7f77Smillert "because minfree is less than %d%%\n", MINFREE);
492df930be7Sderaadt opt = FS_OPTSPACE;
493df930be7Sderaadt }
494992d7f77Smillert if (maxbpg == 0) {
495992d7f77Smillert if (Oflag <= 1)
496992d7f77Smillert maxbpg = MAXBLKPG_FFS1(bsize);
497992d7f77Smillert else
498992d7f77Smillert maxbpg = MAXBLKPG_FFS2(bsize);
499992d7f77Smillert }
500df930be7Sderaadt oldpartition = *pp;
50109758f56Sotto #ifdef MFS
50209758f56Sotto if (mfs) {
50361a439ceStedu if (realpath(argv[1], node) == NULL)
50461a439ceStedu err(1, "realpath %s", argv[1]);
505df69c215Sderaadt if (stat(node, &mountpoint) == -1)
50661a439ceStedu err(ECANCELED, "stat %s", node);
50709758f56Sotto mfsuid = mountpoint.st_uid;
50809758f56Sotto mfsgid = mountpoint.st_gid;
50909758f56Sotto mfsmode = mountpoint.st_mode & ALLPERMS;
51009758f56Sotto }
51109758f56Sotto #endif
51209758f56Sotto
51309758f56Sotto mkfs(pp, special, fsi, fso, mfsmode, mfsuid, mfsgid);
514df930be7Sderaadt if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition)))
515df930be7Sderaadt rewritelabel(special, fso, lp);
516df930be7Sderaadt if (!Nflag)
517df930be7Sderaadt close(fso);
51857f202e1Sotto if (fsi != -1)
519df930be7Sderaadt close(fsi);
520df930be7Sderaadt #ifdef MFS
521df930be7Sderaadt if (mfs) {
522df930be7Sderaadt struct mfs_args args;
52357f202e1Sotto char tmpnode[PATH_MAX];
52457f202e1Sotto
52557f202e1Sotto if (pop != NULL && gettmpmnt(tmpnode, sizeof(tmpnode)) == 0)
52657f202e1Sotto errx(1, "Cannot create tmp mountpoint for -P");
527cb48e966Sotto memset(&args, 0, sizeof(args));
528cb48e966Sotto args.base = membase;
529f576767cSkrw args.size = fssize * DEV_BSIZE;
530cb48e966Sotto args.export_info.ex_root = -2;
531cb48e966Sotto if (mntflags & MNT_RDONLY)
532cb48e966Sotto args.export_info.ex_flags = MNT_EXRDONLY;
5332fadc172Snatano if (mntflags & MNT_NOPERM)
5342fadc172Snatano mntflags |= MNT_NODEV | MNT_NOEXEC;
535df930be7Sderaadt
536379bc20eSmarkus switch (pid = fork()) {
537379bc20eSmarkus case -1:
5384967a721Stedu err(10, "mfs");
539379bc20eSmarkus case 0:
540379bc20eSmarkus snprintf(mountfromname, sizeof(mountfromname),
541379bc20eSmarkus "mfs:%d", getpid());
542379bc20eSmarkus break;
543379bc20eSmarkus default:
54457f202e1Sotto if (pop != NULL) {
54557f202e1Sotto waitformount(tmpnode, pid);
54657f202e1Sotto copy(pop, tmpnode);
54757f202e1Sotto unmount(tmpnode, 0);
54857f202e1Sotto rmdir(tmpnode);
54909758f56Sotto }
55057f202e1Sotto waitformount(node, pid);
551379bc20eSmarkus exit(0);
552379bc20eSmarkus /* NOTREACHED */
553379bc20eSmarkus }
554379bc20eSmarkus
555379bc20eSmarkus (void) setsid();
556379bc20eSmarkus (void) close(0);
557379bc20eSmarkus (void) close(1);
558379bc20eSmarkus (void) close(2);
559379bc20eSmarkus (void) chdir("/");
560379bc20eSmarkus
561379bc20eSmarkus args.fspec = mountfromname;
56257f202e1Sotto if (pop != NULL) {
56357f202e1Sotto int tmpflags = mntflags & ~MNT_RDONLY;
564df69c215Sderaadt if (mount(MOUNT_MFS, tmpnode, tmpflags, &args) == -1)
56557f202e1Sotto exit(errno); /* parent prints message */
56657f202e1Sotto }
567df69c215Sderaadt if (mount(MOUNT_MFS, node, mntflags, &args) == -1)
568379bc20eSmarkus exit(errno); /* parent prints message */
569df930be7Sderaadt }
570df930be7Sderaadt #endif
571df930be7Sderaadt exit(0);
572df930be7Sderaadt }
573df930be7Sderaadt
574df930be7Sderaadt struct disklabel *
getdisklabel(char * s,int fd)5758809fabbSderaadt getdisklabel(char *s, int fd)
576df930be7Sderaadt {
577df930be7Sderaadt static struct disklabel lab;
578df930be7Sderaadt
579df69c215Sderaadt if (ioctl(fd, DIOCGDINFO, (char *)&lab) == -1) {
580aaee66d3Smillert if (disktype != NULL) {
5818d1318c4Sderaadt struct disklabel *lp;
582df930be7Sderaadt
583df930be7Sderaadt unlabeled++;
584df930be7Sderaadt lp = getdiskbyname(disktype);
585df930be7Sderaadt if (lp == NULL)
586df930be7Sderaadt fatal("%s: unknown disk type", disktype);
587df930be7Sderaadt return (lp);
588df930be7Sderaadt }
589df930be7Sderaadt warn("ioctl (GDINFO)");
590688df7cfSguenther fatal("%s: can't read disk label; disk type must be specified",
591688df7cfSguenther s);
592df930be7Sderaadt }
593df930be7Sderaadt return (&lab);
594df930be7Sderaadt }
595df930be7Sderaadt
596a4df0321Sderaadt void
rewritelabel(char * s,int fd,struct disklabel * lp)5978809fabbSderaadt rewritelabel(char *s, int fd, struct disklabel *lp)
598df930be7Sderaadt {
599df930be7Sderaadt if (unlabeled)
600df930be7Sderaadt return;
601aaee66d3Smillert
602df930be7Sderaadt lp->d_checksum = 0;
603df930be7Sderaadt lp->d_checksum = dkcksum(lp);
604df69c215Sderaadt if (ioctl(fd, DIOCWDINFO, (char *)lp) == -1) {
605df930be7Sderaadt warn("ioctl (WDINFO)");
606df930be7Sderaadt fatal("%s: can't rewrite disk label", s);
607df930be7Sderaadt }
608df930be7Sderaadt }
609df930be7Sderaadt
610df930be7Sderaadt void
fatal(const char * fmt,...)611df930be7Sderaadt fatal(const char *fmt, ...)
612df930be7Sderaadt {
613df930be7Sderaadt va_list ap;
614df930be7Sderaadt
615df930be7Sderaadt va_start(ap, fmt);
616df69c215Sderaadt if (fcntl(STDERR_FILENO, F_GETFL) == -1) {
6177ff490a9Smillert openlog(__progname, LOG_CONS, LOG_DAEMON);
618df930be7Sderaadt vsyslog(LOG_ERR, fmt, ap);
619df930be7Sderaadt closelog();
620df930be7Sderaadt } else {
621df930be7Sderaadt vwarnx(fmt, ap);
622df930be7Sderaadt }
623df930be7Sderaadt va_end(ap);
624df930be7Sderaadt exit(1);
625df930be7Sderaadt /*NOTREACHED*/
626df930be7Sderaadt }
627df930be7Sderaadt
628bb33d2d4Sthib __dead void
usage(void)6298809fabbSderaadt usage(void)
630df930be7Sderaadt {
6318be5b41cSjmc extern char *__progname;
63268b6a2b6Smillert
633df930be7Sderaadt if (mfs) {
634df930be7Sderaadt fprintf(stderr,
6357157d296Ssthen "usage: %s [-b block-size] [-c fragments-per-cylinder-group] "
6368be5b41cSjmc "[-e maxbpg]\n"
637c24776e6Ssobrado "\t[-f frag-size] [-i bytes] [-m free-space] [-o options] "
6388be5b41cSjmc "[-P file]\n"
6398be5b41cSjmc "\t[-s size] special node\n",
6407ff490a9Smillert __progname);
6414c5d9d5eSmillert } else {
642df930be7Sderaadt fprintf(stderr,
6438be5b41cSjmc "usage: %s [-Nq] [-b block-size] "
6445d5f5f99Sotto "[-c fragments-per-cylinder-group] [-e maxbpg]\n"
6458be5b41cSjmc "\t[-f frag-size] [-g avgfilesize] [-h avgfpdir] [-i bytes]\n"
6468be5b41cSjmc "\t[-m free-space] [-O filesystem-format] [-o optimization]\n"
64762202a9dSjmc "\t[-S sector-size] [-s size] [-T disktype] [-t fstype] "
64862202a9dSjmc "special\n",
6498be5b41cSjmc __progname);
6504c5d9d5eSmillert }
6518be5b41cSjmc
652df930be7Sderaadt exit(1);
653df930be7Sderaadt }
65409758f56Sotto
65509758f56Sotto #ifdef MFS
65609758f56Sotto
65757f202e1Sotto static void
waitformount(char * node,pid_t pid)65857f202e1Sotto waitformount(char *node, pid_t pid)
65957f202e1Sotto {
66057f202e1Sotto char mountfromname[BUFSIZ];
66157f202e1Sotto struct statfs sf;
66257f202e1Sotto int status;
66357f202e1Sotto pid_t res;
66457f202e1Sotto
66557f202e1Sotto snprintf(mountfromname, sizeof(mountfromname), "mfs:%d", pid);
66657f202e1Sotto for (;;) {
66757f202e1Sotto /*
66857f202e1Sotto * spin until the mount succeeds
66957f202e1Sotto * or the child exits
67057f202e1Sotto */
67157f202e1Sotto usleep(1);
67257f202e1Sotto
67357f202e1Sotto /*
67457f202e1Sotto * XXX Here is a race condition: another process
67557f202e1Sotto * can mount a filesystem which hides our
67657f202e1Sotto * ramdisk before we see the success.
67757f202e1Sotto */
678df69c215Sderaadt if (statfs(node, &sf) == -1)
67957f202e1Sotto err(ECANCELED, "statfs %s", node);
68057f202e1Sotto if (!strcmp(sf.f_mntfromname, mountfromname) &&
68157f202e1Sotto !strncmp(sf.f_mntonname, node,
68257f202e1Sotto MNAMELEN) &&
68357f202e1Sotto !strcmp(sf.f_fstypename, "mfs")) {
68457f202e1Sotto return;
68557f202e1Sotto }
68657f202e1Sotto res = waitpid(pid, &status, WNOHANG);
68757f202e1Sotto if (res == -1)
68857f202e1Sotto err(EDEADLK, "waitpid");
68957f202e1Sotto if (res != pid)
69057f202e1Sotto continue;
69157f202e1Sotto if (WIFEXITED(status)) {
69257f202e1Sotto if (WEXITSTATUS(status) == 0)
69357f202e1Sotto exit(0);
69457f202e1Sotto errx(1, "%s: mount: %s", node,
69557f202e1Sotto strerror(WEXITSTATUS(status)));
69657f202e1Sotto } else
69757f202e1Sotto errx(EDEADLK, "abnormal termination");
69857f202e1Sotto }
69957f202e1Sotto }
70057f202e1Sotto
70109758f56Sotto static int
do_exec(const char * dir,const char * cmd,char * const argv[])70209758f56Sotto do_exec(const char *dir, const char *cmd, char *const argv[])
70309758f56Sotto {
70409758f56Sotto pid_t pid;
70509758f56Sotto int ret, status;
70609758f56Sotto sig_t intsave, quitsave;
70709758f56Sotto
70809758f56Sotto switch (pid = fork()) {
70909758f56Sotto case -1:
71009758f56Sotto err(1, "fork");
71109758f56Sotto case 0:
71209758f56Sotto if (dir != NULL && chdir(dir) != 0)
71309758f56Sotto err(1, "chdir");
71409758f56Sotto if (execv(cmd, argv) != 0)
71509758f56Sotto err(1, "%s", cmd);
71609758f56Sotto break;
71709758f56Sotto default:
71809758f56Sotto intsave = signal(SIGINT, SIG_IGN);
71909758f56Sotto quitsave = signal(SIGQUIT, SIG_IGN);
72009758f56Sotto for (;;) {
72109758f56Sotto ret = waitpid(pid, &status, 0);
72209758f56Sotto if (ret == -1)
72309758f56Sotto err(11, "waitpid");
72409758f56Sotto if (WIFEXITED(status)) {
72509758f56Sotto status = WEXITSTATUS(status);
72609758f56Sotto if (status != 0)
72709758f56Sotto warnx("%s: exited", cmd);
72809758f56Sotto break;
72909758f56Sotto } else if (WIFSIGNALED(status)) {
73009758f56Sotto warnx("%s: %s", cmd,
73109758f56Sotto strsignal(WTERMSIG(status)));
73209758f56Sotto status = 1;
73309758f56Sotto break;
73409758f56Sotto }
73509758f56Sotto }
73609758f56Sotto signal(SIGINT, intsave);
73709758f56Sotto signal(SIGQUIT, quitsave);
73809758f56Sotto return (status);
73909758f56Sotto }
74009758f56Sotto /* NOTREACHED */
74109758f56Sotto return (-1);
74209758f56Sotto }
74309758f56Sotto
74409758f56Sotto static int
isdir(const char * path)74509758f56Sotto isdir(const char *path)
74609758f56Sotto {
74709758f56Sotto struct stat st;
74809758f56Sotto
74909758f56Sotto if (stat(path, &st) != 0)
75009758f56Sotto err(1, "cannot stat %s", path);
75109758f56Sotto if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode))
75209758f56Sotto errx(1, "%s: not a dir or a block device", path);
75309758f56Sotto return (S_ISDIR(st.st_mode));
75409758f56Sotto }
75509758f56Sotto
75609758f56Sotto static void
copy(char * src,char * dst)75757f202e1Sotto copy(char *src, char *dst)
75809758f56Sotto {
75909758f56Sotto int ret, dir, created = 0;
76009758f56Sotto struct ufs_args mount_args;
76109758f56Sotto char mountpoint[MNAMELEN];
76209758f56Sotto char *const argv[] = { "pax", "-rw", "-pe", ".", dst, NULL } ;
76309758f56Sotto
76409758f56Sotto dir = isdir(src);
76509758f56Sotto if (dir)
76609758f56Sotto strlcpy(mountpoint, src, sizeof(mountpoint));
76709758f56Sotto else {
76809758f56Sotto created = gettmpmnt(mountpoint, sizeof(mountpoint));
76909758f56Sotto memset(&mount_args, 0, sizeof(mount_args));
77009758f56Sotto mount_args.fspec = src;
77109758f56Sotto ret = mount(MOUNT_FFS, mountpoint, MNT_RDONLY, &mount_args);
77209758f56Sotto if (ret != 0) {
773ffb4dd05Sguenther int saved_errno = errno;
77409758f56Sotto if (created && rmdir(mountpoint) != 0)
77509758f56Sotto warn("rmdir %s", mountpoint);
77609758f56Sotto if (unmount(dst, 0) != 0)
77709758f56Sotto warn("unmount %s", dst);
778ffb4dd05Sguenther errc(1, saved_errno, "mount %s %s", src, mountpoint);
77909758f56Sotto }
78009758f56Sotto }
78109758f56Sotto ret = do_exec(mountpoint, "/bin/pax", argv);
78209758f56Sotto if (!dir && unmount(mountpoint, 0) != 0)
78309758f56Sotto warn("unmount %s", mountpoint);
78409758f56Sotto if (created && rmdir(mountpoint) != 0)
78509758f56Sotto warn("rmdir %s", mountpoint);
78609758f56Sotto if (ret != 0) {
78709758f56Sotto if (unmount(dst, 0) != 0)
78809758f56Sotto warn("unmount %s", dst);
78909758f56Sotto errx(1, "copy %s to %s failed", mountpoint, dst);
79009758f56Sotto }
79109758f56Sotto }
79209758f56Sotto
79309758f56Sotto static int
gettmpmnt(char * mountpoint,size_t len)79409758f56Sotto gettmpmnt(char *mountpoint, size_t len)
79509758f56Sotto {
7962e573aefSderaadt const char *tmp = _PATH_TMP;
797177f8e25Sotto const char *mnt = _PATH_MNT;
79809758f56Sotto struct statfs fs;
799177f8e25Sotto size_t n;
80009758f56Sotto
801177f8e25Sotto if (statfs(tmp, &fs) != 0)
802177f8e25Sotto err(1, "statfs %s", tmp);
80309758f56Sotto if (fs.f_flags & MNT_RDONLY) {
804177f8e25Sotto if (statfs(mnt, &fs) != 0)
805177f8e25Sotto err(1, "statfs %s", mnt);
80609758f56Sotto if (strcmp(fs.f_mntonname, "/") != 0)
807177f8e25Sotto errx(1, "tmp mountpoint %s busy", mnt);
808177f8e25Sotto if (strlcpy(mountpoint, mnt, len) >= len)
809177f8e25Sotto errx(1, "tmp mountpoint %s too long", mnt);
81009758f56Sotto return (0);
81109758f56Sotto }
812177f8e25Sotto n = strlcpy(mountpoint, tmp, len);
813177f8e25Sotto if (n >= len)
814177f8e25Sotto errx(1, "tmp mount point too long");
815177f8e25Sotto if (mountpoint[n - 1] != '/')
816177f8e25Sotto strlcat(mountpoint, "/", len);
817177f8e25Sotto n = strlcat(mountpoint, "mntXXXXXXXXXX", len);
818177f8e25Sotto if (n >= len)
819177f8e25Sotto errx(1, "tmp mount point too long");
82009758f56Sotto if (mkdtemp(mountpoint) == NULL)
82109758f56Sotto err(1, "mkdtemp %s", mountpoint);
82209758f56Sotto return (1);
82309758f56Sotto }
82409758f56Sotto
82509758f56Sotto #endif /* MFS */
826