understand and allow for union mounts
[unix-history] / usr / src / sbin / newlfs / newfs.c
CommitLineData
3c62472a
KB
1/*-
2 * Copyright (c) 1989, 1992 The Regents of the University of California.
2a5c97d5
KB
3 * All rights reserved.
4 *
3c62472a 5 * %sccs.include.redist.c%
2a5c97d5
KB
6 */
7
8#ifndef lint
3c62472a
KB
9char copyright[] =
10"@(#) Copyright (c) 1989, 1992 The Regents of the University of California.\n\
11 All rights reserved.\n";
2a5c97d5
KB
12#endif /* not lint */
13
14#ifndef lint
3c62472a 15static char sccsid[] = "@(#)newfs.c 5.6 (Berkeley) %G%";
2a5c97d5
KB
16#endif /* not lint */
17
18/*
19 * newfs: friendly front end to mkfs
20 */
21#include <sys/param.h>
be25f164 22#include <sys/ucred.h>
2a5c97d5 23#include <sys/stat.h>
2a5c97d5
KB
24#include <sys/ioctl.h>
25#include <sys/disklabel.h>
26#include <sys/file.h>
27#include <sys/mount.h>
28
5f4034eb
KB
29#include <ufs/ufs/dir.h>
30#include <ufs/ufs/dinode.h>
31#include <ufs/ffs/fs.h>
32
2a5c97d5
KB
33#include <errno.h>
34#include <unistd.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <ctype.h>
38#include <string.h>
39#include <paths.h>
40#include "config.h"
41#include "extern.h"
42
43#define COMPAT /* allow non-labeled disks */
44
45int mfs; /* run as the memory based filesystem */
46int Nflag; /* run without writing file system */
47int fssize; /* file system size */
48int ntracks; /* # tracks/cylinder */
49int nsectors; /* # sectors/track */
50int nphyssectors; /* # sectors/track including spares */
51int secpercyl; /* sectors per cylinder */
52int trackspares = -1; /* spare sectors per track */
53int cylspares = -1; /* spare sectors per cylinder */
54int sectorsize; /* bytes/sector */
55#ifdef tahoe
56int realsectorsize; /* bytes/sector in hardware */
57#endif
58int rpm; /* revolutions/minute of drive */
59int interleave; /* hardware sector interleave */
60int trackskew = -1; /* sector 0 skew, per track */
61int headswitch; /* head switch time, usec */
62int trackseek; /* track-to-track seek, usec */
63int fsize = 0; /* fragment size */
64int bsize = 0; /* block size */
65int cpg = DESCPG; /* cylinders/cylinder group */
66int cpgflg; /* cylinders/cylinder group flag was given */
67int minfree = MINFREE; /* free space threshold */
68int opt = DEFAULTOPT; /* optimization preference (space or time) */
69int density; /* number of bytes per inode */
70int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */
71int rotdelay = ROTDELAY; /* rotational delay between blocks */
72int maxbpg; /* maximum blocks per file in a cyl group */
73int nrpos = NRPOS; /* # of distinguished rotational positions */
74int bbsize = BBSIZE; /* boot block size */
75int sbsize = SBSIZE; /* superblock size */
76int mntflags; /* flags to be passed to mount */
77u_long memleft; /* virtual memory available */
78caddr_t membase; /* start address of memory based filesystem */
79#ifdef COMPAT
80char *disktype;
81int unlabeled;
82#endif
83
84char device[MAXPATHLEN];
85char *progname, *special;
86
87static struct disklabel *getdisklabel __P((char *, int));
88static struct disklabel *debug_readlabel __P((int));
89static void rewritelabel __P((char *, int, struct disklabel *));
90static void usage __P((void));
91
92int
93main(argc, argv)
94 int argc;
95 char *argv[];
96{
97 register int ch;
98 register struct partition *pp;
99 register struct disklabel *lp;
100 struct partition oldpartition;
101 struct stat st;
102 int debug, lfs, fsi, fso, segsize;
103 char *cp, *opstring;
104
105 if (progname = rindex(*argv, '/'))
106 ++progname;
107 else
108 progname = *argv;
109
110 if (strstr(progname, "mfs")) {
111 mfs = 1;
112 Nflag++;
113 }
114
115 /* -F is mfs only and MUST come first! */
116 opstring = "F:B:DLNS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:";
117 if (!mfs)
118 opstring += 2;
119
120 debug = lfs = segsize = 0;
121 while ((ch = getopt(argc, argv, opstring)) != EOF)
122 switch(ch) {
123 case 'B': /* LFS segment size */
124 if ((segsize = atoi(optarg)) < LFS_MINSEGSIZE)
125 fatal("%s: bad segment size", optarg);
126 break;
127 case 'D':
128 debug = 1;
129 break;
130 case 'F':
131 if ((mntflags = atoi(optarg)) == 0)
132 fatal("%s: bad mount flags", optarg);
133 break;
134 case 'L': /* Create lfs */
135 lfs = 1;
136 break;
137 case 'N':
138 Nflag++;
139 break;
140 case 'S':
141 if ((sectorsize = atoi(optarg)) <= 0)
142 fatal("%s: bad sector size", optarg);
143 break;
144#ifdef COMPAT
145 case 'T':
146 disktype = optarg;
147 break;
148#endif
149 case 'a':
150 if ((maxcontig = atoi(optarg)) <= 0)
151 fatal("%s: bad max contiguous blocks\n",
152 optarg);
153 break;
154 case 'b': /* used for LFS */
155 if ((bsize = atoi(optarg)) < MINBSIZE)
156 fatal("%s: bad block size", optarg);
157 break;
158 case 'c':
159 if ((cpg = atoi(optarg)) <= 0)
160 fatal("%s: bad cylinders/group", optarg);
161 cpgflg++;
162 break;
163 case 'd':
164 if ((rotdelay = atoi(optarg)) < 0)
165 fatal("%s: bad rotational delay\n", optarg);
166 break;
167 case 'e':
168 if ((maxbpg = atoi(optarg)) <= 0)
169 fatal("%s: bad blocks per file in a cyl group\n",
170 optarg);
171 break;
172 case 'f':
173 if ((fsize = atoi(optarg)) <= 0)
174 fatal("%s: bad frag size", optarg);
175 break;
176 case 'i':
177 if ((density = atoi(optarg)) <= 0)
178 fatal("%s: bad bytes per inode\n", optarg);
179 break;
180 case 'k':
181 if ((trackskew = atoi(optarg)) < 0)
182 fatal("%s: bad track skew", optarg);
183 break;
184 case 'l':
185 if ((interleave = atoi(optarg)) <= 0)
186 fatal("%s: bad interleave", optarg);
187 break;
188 case 'm': /* used for LFS */
189 if ((minfree = atoi(optarg)) < 0 || minfree > 99)
190 fatal("%s: bad free space %%\n", optarg);
191 break;
192 case 'n':
193 if ((nrpos = atoi(optarg)) <= 0)
194 fatal("%s: bad rotational layout count\n",
195 optarg);
196 break;
197 case 'o':
198 if (strcmp(optarg, "space") == 0)
199 opt = FS_OPTSPACE;
200 else if (strcmp(optarg, "time") == 0)
201 opt = FS_OPTTIME;
202 else
203 fatal("%s: bad optimization preference %s",
204 optarg, "(options are `space' or `time')");
205 break;
206 case 'p':
207 if ((trackspares = atoi(optarg)) < 0)
208 fatal("%s: bad spare sectors per track",
209 optarg);
210 break;
211 case 'r':
212 if ((rpm = atoi(optarg)) <= 0)
213 fatal("%s: bad revs/minute\n", optarg);
214 break;
215 case 's': /* used for LFS */
216 if ((fssize = atoi(optarg)) <= 0)
217 fatal("%s: bad file system size", optarg);
218 break;
219 case 't':
220 if ((ntracks = atoi(optarg)) <= 0)
221 fatal("%s: bad total tracks", optarg);
222 break;
223 case 'u':
224 if ((nsectors = atoi(optarg)) <= 0)
225 fatal("%s: bad sectors/track", optarg);
226 break;
227 case 'x':
228 if ((cylspares = atoi(optarg)) < 0)
229 fatal("%s: bad spare sectors per cylinder",
230 optarg);
231 break;
232 case '?':
233 default:
234 usage();
235 }
236 argc -= optind;
237 argv += optind;
238
239 if (argc != 2 && (mfs || argc != 1))
240 usage();
241
242 /*
243 * If the -N flag isn't specified, open the output file. If no path
244 * prefix, try /dev/r%s and then /dev/%s.
245 */
246 special = argv[0];
247 if (index(special, '/') == NULL) {
248 (void)sprintf(device, "%sr%s", _PATH_DEV, special);
249 if (stat(device, &st) == -1)
250 (void)sprintf(device, "%s%s", _PATH_DEV, special);
251 special = device;
252 }
253 if (!Nflag) {
254 fso = open(special,
255 (debug ? O_CREAT : 0) | O_WRONLY, DEFFILEMODE);
256 if (fso < 0)
257 fatal("%s: %s", special, strerror(errno));
258 } else
259 fso = -1;
260
261 /* Open the input file. */
262 fsi = open(special, O_RDONLY);
263 if (fsi < 0)
264 fatal("%s: %s", special, strerror(errno));
265 if (fstat(fsi, &st) < 0)
266 fatal("%s: %s", special, strerror(errno));
267
9ef376b4 268 if (!debug && !mfs && !S_ISCHR(st.st_mode))
2a5c97d5
KB
269 (void)printf("%s: %s: not a character-special device\n",
270 progname, special);
271 cp = index(argv[0], '\0') - 1;
272 if (!debug && (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)))
273 fatal("%s: can't figure out file system partition", argv[0]);
274
275#ifdef COMPAT
276 if (!mfs && disktype == NULL)
277 disktype = argv[1];
278#endif
279 if (debug)
280 lp = debug_readlabel(fsi);
281 else
282 lp = getdisklabel(special, fsi);
283
284 if (isdigit(*cp))
285 pp = &lp->d_partitions[0];
286 else
287 pp = &lp->d_partitions[*cp - 'a'];
288 if (pp->p_size == 0)
289 fatal("%s: `%c' partition is unavailable", argv[0], *cp);
290
291 /* If we're making a LFS, we break out here */
0f68007b 292 exit(make_lfs(fso, lp, pp, minfree, bsize, segsize));
2a5c97d5
KB
293}
294
295#ifdef COMPAT
296char lmsg[] = "%s: can't read disk label; disk type must be specified";
297#else
298char lmsg[] = "%s: can't read disk label";
299#endif
300
301static struct disklabel *
302getdisklabel(s, fd)
303 char *s;
304 int fd;
305{
306 static struct disklabel lab;
307
308 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
309#ifdef COMPAT
310 if (disktype) {
311 struct disklabel *lp, *getdiskbyname();
312
313 unlabeled++;
314 lp = getdiskbyname(disktype);
315 if (lp == NULL)
316 fatal("%s: unknown disk type", disktype);
317 return (lp);
318 }
319#endif
320 (void)fprintf(stderr,
321 "%s: ioctl (GDINFO): %s\n", progname, strerror(errno));
322 fatal(lmsg, s);
323 }
324 return (&lab);
325}
326
327
328static struct disklabel *
329debug_readlabel(fd)
330 int fd;
331{
332 static struct disklabel lab;
333 int n;
334
335 if ((n = read(fd, &lab, sizeof(struct disklabel))) < 0)
336 fatal("unable to read disk label: %s", strerror(errno));
337 else if (n < sizeof(struct disklabel))
338 fatal("short read of disklabel: %d of %d bytes", n,
339 sizeof(struct disklabel));
340 return(&lab);
341}
342
343static void
344rewritelabel(s, fd, lp)
345 char *s;
346 int fd;
347 register struct disklabel *lp;
348{
349#ifdef COMPAT
350 if (unlabeled)
351 return;
352#endif
353 lp->d_checksum = 0;
354 lp->d_checksum = dkcksum(lp);
355 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
356 (void)fprintf(stderr,
357 "%s: ioctl (WDINFO): %s\n", progname, strerror(errno));
358 fatal("%s: can't rewrite disk label", s);
359 }
360#if vax
361 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
362 register i;
363 int cfd;
364 daddr_t alt;
365 char specname[64];
366 char blk[1024];
367 char *cp;
368
369 /*
370 * Make name for 'c' partition.
371 */
372 strcpy(specname, s);
373 cp = specname + strlen(specname) - 1;
374 if (!isdigit(*cp))
375 *cp = 'c';
376 cfd = open(specname, O_WRONLY);
377 if (cfd < 0)
378 fatal("%s: %s", specname, strerror(errno));
379 bzero(blk, sizeof(blk));
380 *(struct disklabel *)(blk + LABELOFFSET) = *lp;
381 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
382 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
383 if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize,
384 L_SET) == -1)
385 fatal("lseek to badsector area: %s",
386 strerror(errno));
387 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
388 fprintf(stderr,
389 "%s: alternate label %d write: %s\n",
390 progname, i/2, strerror(errno));
391 }
392 close(cfd);
393 }
394#endif
395}
396
397void
398usage()
399{
400 if (mfs) {
401 fprintf(stderr,
402 "usage: mfs [ -fsoptions ] special-device mount-point\n");
403 } else
404 fprintf(stderr,
405 "usage: newfs [ -fsoptions ] special-device%s\n",
406#ifdef COMPAT
407 " [device-type]");
408#else
409 "");
410#endif
411 fprintf(stderr, "where fsoptions are:\n");
412 fprintf(stderr, "\t-B LFS segment size\n");
413 fprintf(stderr, "\t-D debug\n");
414 fprintf(stderr, "\t-F mount flags\n");
415 fprintf(stderr, "\t-L create LFS file system\n");
416 fprintf(stderr,
417 "\t-N do not create file system, just print out parameters\n");
418 fprintf(stderr, "\t-S sector size\n");
419#ifdef COMPAT
420 fprintf(stderr, "\t-T disktype\n");
421#endif
422 fprintf(stderr, "\t-a maximum contiguous blocks\n");
423 fprintf(stderr, "\t-b block size\n");
424 fprintf(stderr, "\t-c cylinders/group\n");
425 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
426 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
427 fprintf(stderr, "\t-f frag size\n");
428 fprintf(stderr, "\t-i number of bytes per inode\n");
429 fprintf(stderr, "\t-k sector 0 skew, per track\n");
430 fprintf(stderr, "\t-l hardware sector interleave\n");
431 fprintf(stderr, "\t-m minimum free space %%\n");
432 fprintf(stderr, "\t-n number of distinguished rotational positions\n");
433 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
434 fprintf(stderr, "\t-p spare sectors per track\n");
435 fprintf(stderr, "\t-r revolutions/minute\n");
436 fprintf(stderr, "\t-s file system size (sectors)\n");
437 fprintf(stderr, "\t-t tracks/cylinder\n");
438 fprintf(stderr, "\t-u sectors/track\n");
439 fprintf(stderr, "\t-x spare sectors per cylinder\n");
440 exit(1);
441}