checkpoint of hacking for mail.cs.berkeley.edu
[unix-history] / usr / src / sbin / newlfs / newfs.c
CommitLineData
2a5c97d5
KB
1/*
2 * Copyright (c) 1983, 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)newfs.c 6.28 (Berkeley) 8/6/91";
36#endif /* not lint */
37
38#ifndef lint
39char copyright[] =
40"@(#) Copyright (c) 1983, 1989 Regents of the University of California.\n\
41 All rights reserved.\n";
42#endif /* not lint */
43
44/*
45 * newfs: friendly front end to mkfs
46 */
47#include <sys/param.h>
be25f164 48#include <sys/ucred.h>
2a5c97d5 49#include <sys/stat.h>
2a5c97d5
KB
50#include <sys/ioctl.h>
51#include <sys/disklabel.h>
52#include <sys/file.h>
53#include <sys/mount.h>
54
5f4034eb
KB
55#include <ufs/ufs/dir.h>
56#include <ufs/ufs/dinode.h>
57#include <ufs/ffs/fs.h>
58
2a5c97d5
KB
59#include <errno.h>
60#include <unistd.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <ctype.h>
64#include <string.h>
65#include <paths.h>
66#include "config.h"
67#include "extern.h"
68
69#define COMPAT /* allow non-labeled disks */
70
71int mfs; /* run as the memory based filesystem */
72int Nflag; /* run without writing file system */
73int fssize; /* file system size */
74int ntracks; /* # tracks/cylinder */
75int nsectors; /* # sectors/track */
76int nphyssectors; /* # sectors/track including spares */
77int secpercyl; /* sectors per cylinder */
78int trackspares = -1; /* spare sectors per track */
79int cylspares = -1; /* spare sectors per cylinder */
80int sectorsize; /* bytes/sector */
81#ifdef tahoe
82int realsectorsize; /* bytes/sector in hardware */
83#endif
84int rpm; /* revolutions/minute of drive */
85int interleave; /* hardware sector interleave */
86int trackskew = -1; /* sector 0 skew, per track */
87int headswitch; /* head switch time, usec */
88int trackseek; /* track-to-track seek, usec */
89int fsize = 0; /* fragment size */
90int bsize = 0; /* block size */
91int cpg = DESCPG; /* cylinders/cylinder group */
92int cpgflg; /* cylinders/cylinder group flag was given */
93int minfree = MINFREE; /* free space threshold */
94int opt = DEFAULTOPT; /* optimization preference (space or time) */
95int density; /* number of bytes per inode */
96int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */
97int rotdelay = ROTDELAY; /* rotational delay between blocks */
98int maxbpg; /* maximum blocks per file in a cyl group */
99int nrpos = NRPOS; /* # of distinguished rotational positions */
100int bbsize = BBSIZE; /* boot block size */
101int sbsize = SBSIZE; /* superblock size */
102int mntflags; /* flags to be passed to mount */
103u_long memleft; /* virtual memory available */
104caddr_t membase; /* start address of memory based filesystem */
105#ifdef COMPAT
106char *disktype;
107int unlabeled;
108#endif
109
110char device[MAXPATHLEN];
111char *progname, *special;
112
113static struct disklabel *getdisklabel __P((char *, int));
114static struct disklabel *debug_readlabel __P((int));
115static void rewritelabel __P((char *, int, struct disklabel *));
116static void usage __P((void));
117
118int
119main(argc, argv)
120 int argc;
121 char *argv[];
122{
123 register int ch;
124 register struct partition *pp;
125 register struct disklabel *lp;
126 struct partition oldpartition;
127 struct stat st;
128 int debug, lfs, fsi, fso, segsize;
129 char *cp, *opstring;
130
131 if (progname = rindex(*argv, '/'))
132 ++progname;
133 else
134 progname = *argv;
135
136 if (strstr(progname, "mfs")) {
137 mfs = 1;
138 Nflag++;
139 }
140
141 /* -F is mfs only and MUST come first! */
142 opstring = "F:B:DLNS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:";
143 if (!mfs)
144 opstring += 2;
145
146 debug = lfs = segsize = 0;
147 while ((ch = getopt(argc, argv, opstring)) != EOF)
148 switch(ch) {
149 case 'B': /* LFS segment size */
150 if ((segsize = atoi(optarg)) < LFS_MINSEGSIZE)
151 fatal("%s: bad segment size", optarg);
152 break;
153 case 'D':
154 debug = 1;
155 break;
156 case 'F':
157 if ((mntflags = atoi(optarg)) == 0)
158 fatal("%s: bad mount flags", optarg);
159 break;
160 case 'L': /* Create lfs */
161 lfs = 1;
162 break;
163 case 'N':
164 Nflag++;
165 break;
166 case 'S':
167 if ((sectorsize = atoi(optarg)) <= 0)
168 fatal("%s: bad sector size", optarg);
169 break;
170#ifdef COMPAT
171 case 'T':
172 disktype = optarg;
173 break;
174#endif
175 case 'a':
176 if ((maxcontig = atoi(optarg)) <= 0)
177 fatal("%s: bad max contiguous blocks\n",
178 optarg);
179 break;
180 case 'b': /* used for LFS */
181 if ((bsize = atoi(optarg)) < MINBSIZE)
182 fatal("%s: bad block size", optarg);
183 break;
184 case 'c':
185 if ((cpg = atoi(optarg)) <= 0)
186 fatal("%s: bad cylinders/group", optarg);
187 cpgflg++;
188 break;
189 case 'd':
190 if ((rotdelay = atoi(optarg)) < 0)
191 fatal("%s: bad rotational delay\n", optarg);
192 break;
193 case 'e':
194 if ((maxbpg = atoi(optarg)) <= 0)
195 fatal("%s: bad blocks per file in a cyl group\n",
196 optarg);
197 break;
198 case 'f':
199 if ((fsize = atoi(optarg)) <= 0)
200 fatal("%s: bad frag size", optarg);
201 break;
202 case 'i':
203 if ((density = atoi(optarg)) <= 0)
204 fatal("%s: bad bytes per inode\n", optarg);
205 break;
206 case 'k':
207 if ((trackskew = atoi(optarg)) < 0)
208 fatal("%s: bad track skew", optarg);
209 break;
210 case 'l':
211 if ((interleave = atoi(optarg)) <= 0)
212 fatal("%s: bad interleave", optarg);
213 break;
214 case 'm': /* used for LFS */
215 if ((minfree = atoi(optarg)) < 0 || minfree > 99)
216 fatal("%s: bad free space %%\n", optarg);
217 break;
218 case 'n':
219 if ((nrpos = atoi(optarg)) <= 0)
220 fatal("%s: bad rotational layout count\n",
221 optarg);
222 break;
223 case 'o':
224 if (strcmp(optarg, "space") == 0)
225 opt = FS_OPTSPACE;
226 else if (strcmp(optarg, "time") == 0)
227 opt = FS_OPTTIME;
228 else
229 fatal("%s: bad optimization preference %s",
230 optarg, "(options are `space' or `time')");
231 break;
232 case 'p':
233 if ((trackspares = atoi(optarg)) < 0)
234 fatal("%s: bad spare sectors per track",
235 optarg);
236 break;
237 case 'r':
238 if ((rpm = atoi(optarg)) <= 0)
239 fatal("%s: bad revs/minute\n", optarg);
240 break;
241 case 's': /* used for LFS */
242 if ((fssize = atoi(optarg)) <= 0)
243 fatal("%s: bad file system size", optarg);
244 break;
245 case 't':
246 if ((ntracks = atoi(optarg)) <= 0)
247 fatal("%s: bad total tracks", optarg);
248 break;
249 case 'u':
250 if ((nsectors = atoi(optarg)) <= 0)
251 fatal("%s: bad sectors/track", optarg);
252 break;
253 case 'x':
254 if ((cylspares = atoi(optarg)) < 0)
255 fatal("%s: bad spare sectors per cylinder",
256 optarg);
257 break;
258 case '?':
259 default:
260 usage();
261 }
262 argc -= optind;
263 argv += optind;
264
265 if (argc != 2 && (mfs || argc != 1))
266 usage();
267
268 /*
269 * If the -N flag isn't specified, open the output file. If no path
270 * prefix, try /dev/r%s and then /dev/%s.
271 */
272 special = argv[0];
273 if (index(special, '/') == NULL) {
274 (void)sprintf(device, "%sr%s", _PATH_DEV, special);
275 if (stat(device, &st) == -1)
276 (void)sprintf(device, "%s%s", _PATH_DEV, special);
277 special = device;
278 }
279 if (!Nflag) {
280 fso = open(special,
281 (debug ? O_CREAT : 0) | O_WRONLY, DEFFILEMODE);
282 if (fso < 0)
283 fatal("%s: %s", special, strerror(errno));
284 } else
285 fso = -1;
286
287 /* Open the input file. */
288 fsi = open(special, O_RDONLY);
289 if (fsi < 0)
290 fatal("%s: %s", special, strerror(errno));
291 if (fstat(fsi, &st) < 0)
292 fatal("%s: %s", special, strerror(errno));
293
9ef376b4 294 if (!debug && !mfs && !S_ISCHR(st.st_mode))
2a5c97d5
KB
295 (void)printf("%s: %s: not a character-special device\n",
296 progname, special);
297 cp = index(argv[0], '\0') - 1;
298 if (!debug && (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)))
299 fatal("%s: can't figure out file system partition", argv[0]);
300
301#ifdef COMPAT
302 if (!mfs && disktype == NULL)
303 disktype = argv[1];
304#endif
305 if (debug)
306 lp = debug_readlabel(fsi);
307 else
308 lp = getdisklabel(special, fsi);
309
310 if (isdigit(*cp))
311 pp = &lp->d_partitions[0];
312 else
313 pp = &lp->d_partitions[*cp - 'a'];
314 if (pp->p_size == 0)
315 fatal("%s: `%c' partition is unavailable", argv[0], *cp);
316
317 /* If we're making a LFS, we break out here */
318 if (lfs)
319 exit(make_lfs(fso, lp, pp, minfree, bsize, segsize));
320
321 if (fssize == 0)
322 fssize = pp->p_size;
323 if (fssize > pp->p_size && !mfs)
324 fatal("%s: maximum file system size on the `%c' partition is %d",
325 argv[0], *cp, pp->p_size);
326 if (rpm == 0) {
327 rpm = lp->d_rpm;
328 if (rpm <= 0)
329 rpm = 3600;
330 }
331 if (ntracks == 0) {
332 ntracks = lp->d_ntracks;
333 if (ntracks <= 0)
334 fatal("%s: no default #tracks", argv[0]);
335 }
336 if (nsectors == 0) {
337 nsectors = lp->d_nsectors;
338 if (nsectors <= 0)
339 fatal("%s: no default #sectors/track", argv[0]);
340 }
341 if (sectorsize == 0) {
342 sectorsize = lp->d_secsize;
343 if (sectorsize <= 0)
344 fatal("%s: no default sector size", argv[0]);
345 }
346 if (trackskew == -1) {
347 trackskew = lp->d_trackskew;
348 if (trackskew < 0)
349 trackskew = 0;
350 }
351 if (interleave == 0) {
352 interleave = lp->d_interleave;
353 if (interleave <= 0)
354 interleave = 1;
355 }
356 if (fsize == 0) {
357 fsize = pp->p_fsize;
358 if (fsize <= 0)
359 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
360 }
361 if (bsize == 0) {
362 bsize = pp->p_frag * pp->p_fsize;
363 if (bsize <= 0)
364 bsize = MIN(DFL_BLKSIZE, 8 * fsize);
365 }
366 if (density == 0)
367 density = NFPI * fsize;
368 if (minfree < 10 && opt != FS_OPTSPACE) {
369 fprintf(stderr, "Warning: changing optimization to space ");
370 fprintf(stderr, "because minfree is less than 10%%\n");
371 opt = FS_OPTSPACE;
372 }
373 if (trackspares == -1) {
374 trackspares = lp->d_sparespertrack;
375 if (trackspares < 0)
376 trackspares = 0;
377 }
378 nphyssectors = nsectors + trackspares;
379 if (cylspares == -1) {
380 cylspares = lp->d_sparespercyl;
381 if (cylspares < 0)
382 cylspares = 0;
383 }
384 secpercyl = nsectors * ntracks - cylspares;
385 if (secpercyl != lp->d_secpercyl)
386 fprintf(stderr, "%s (%d) %s (%lu)\n",
387 "Warning: calculated sectors per cylinder", secpercyl,
388 "disagrees with disk label", lp->d_secpercyl);
389 if (maxbpg == 0)
390 maxbpg = MAXBLKPG(bsize);
391 headswitch = lp->d_headswitch;
392 trackseek = lp->d_trkseek;
393#ifdef notdef /* label may be 0 if faked up by kernel */
394 bbsize = lp->d_bbsize;
395 sbsize = lp->d_sbsize;
396#endif
397 oldpartition = *pp;
398#ifdef tahoe
399 realsectorsize = sectorsize;
400 if (sectorsize != DEV_BSIZE) { /* XXX */
401 int secperblk = DEV_BSIZE / sectorsize;
402
403 sectorsize = DEV_BSIZE;
404 nsectors /= secperblk;
405 nphyssectors /= secperblk;
406 secpercyl /= secperblk;
407 fssize /= secperblk;
408 pp->p_size /= secperblk;
409 }
410#endif
411 mkfs(pp, special, fsi, fso);
412#ifdef tahoe
413 if (realsectorsize != DEV_BSIZE)
414 pp->p_size *= DEV_BSIZE / realsectorsize;
415#endif
416 if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition)))
417 rewritelabel(special, fso, lp);
418 if (!Nflag)
419 close(fso);
420 close(fsi);
421#ifdef MFS
422 if (mfs) {
423 struct mfs_args args;
424 char buf[50];
425
426 (void)sprintf(buf, "mfs:%d", getpid());
427 args.name = buf;
428 args.base = membase;
429 args.size = fssize * sectorsize;
430 if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0)
431 fatal("%s: %s", argv[1], strerror(errno));
432 }
433#endif
434 exit(0);
435}
436
437#ifdef COMPAT
438char lmsg[] = "%s: can't read disk label; disk type must be specified";
439#else
440char lmsg[] = "%s: can't read disk label";
441#endif
442
443static struct disklabel *
444getdisklabel(s, fd)
445 char *s;
446 int fd;
447{
448 static struct disklabel lab;
449
450 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
451#ifdef COMPAT
452 if (disktype) {
453 struct disklabel *lp, *getdiskbyname();
454
455 unlabeled++;
456 lp = getdiskbyname(disktype);
457 if (lp == NULL)
458 fatal("%s: unknown disk type", disktype);
459 return (lp);
460 }
461#endif
462 (void)fprintf(stderr,
463 "%s: ioctl (GDINFO): %s\n", progname, strerror(errno));
464 fatal(lmsg, s);
465 }
466 return (&lab);
467}
468
469
470static struct disklabel *
471debug_readlabel(fd)
472 int fd;
473{
474 static struct disklabel lab;
475 int n;
476
477 if ((n = read(fd, &lab, sizeof(struct disklabel))) < 0)
478 fatal("unable to read disk label: %s", strerror(errno));
479 else if (n < sizeof(struct disklabel))
480 fatal("short read of disklabel: %d of %d bytes", n,
481 sizeof(struct disklabel));
482 return(&lab);
483}
484
485static void
486rewritelabel(s, fd, lp)
487 char *s;
488 int fd;
489 register struct disklabel *lp;
490{
491#ifdef COMPAT
492 if (unlabeled)
493 return;
494#endif
495 lp->d_checksum = 0;
496 lp->d_checksum = dkcksum(lp);
497 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
498 (void)fprintf(stderr,
499 "%s: ioctl (WDINFO): %s\n", progname, strerror(errno));
500 fatal("%s: can't rewrite disk label", s);
501 }
502#if vax
503 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
504 register i;
505 int cfd;
506 daddr_t alt;
507 char specname[64];
508 char blk[1024];
509 char *cp;
510
511 /*
512 * Make name for 'c' partition.
513 */
514 strcpy(specname, s);
515 cp = specname + strlen(specname) - 1;
516 if (!isdigit(*cp))
517 *cp = 'c';
518 cfd = open(specname, O_WRONLY);
519 if (cfd < 0)
520 fatal("%s: %s", specname, strerror(errno));
521 bzero(blk, sizeof(blk));
522 *(struct disklabel *)(blk + LABELOFFSET) = *lp;
523 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
524 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
525 if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize,
526 L_SET) == -1)
527 fatal("lseek to badsector area: %s",
528 strerror(errno));
529 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
530 fprintf(stderr,
531 "%s: alternate label %d write: %s\n",
532 progname, i/2, strerror(errno));
533 }
534 close(cfd);
535 }
536#endif
537}
538
539void
540usage()
541{
542 if (mfs) {
543 fprintf(stderr,
544 "usage: mfs [ -fsoptions ] special-device mount-point\n");
545 } else
546 fprintf(stderr,
547 "usage: newfs [ -fsoptions ] special-device%s\n",
548#ifdef COMPAT
549 " [device-type]");
550#else
551 "");
552#endif
553 fprintf(stderr, "where fsoptions are:\n");
554 fprintf(stderr, "\t-B LFS segment size\n");
555 fprintf(stderr, "\t-D debug\n");
556 fprintf(stderr, "\t-F mount flags\n");
557 fprintf(stderr, "\t-L create LFS file system\n");
558 fprintf(stderr,
559 "\t-N do not create file system, just print out parameters\n");
560 fprintf(stderr, "\t-S sector size\n");
561#ifdef COMPAT
562 fprintf(stderr, "\t-T disktype\n");
563#endif
564 fprintf(stderr, "\t-a maximum contiguous blocks\n");
565 fprintf(stderr, "\t-b block size\n");
566 fprintf(stderr, "\t-c cylinders/group\n");
567 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
568 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
569 fprintf(stderr, "\t-f frag size\n");
570 fprintf(stderr, "\t-i number of bytes per inode\n");
571 fprintf(stderr, "\t-k sector 0 skew, per track\n");
572 fprintf(stderr, "\t-l hardware sector interleave\n");
573 fprintf(stderr, "\t-m minimum free space %%\n");
574 fprintf(stderr, "\t-n number of distinguished rotational positions\n");
575 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
576 fprintf(stderr, "\t-p spare sectors per track\n");
577 fprintf(stderr, "\t-r revolutions/minute\n");
578 fprintf(stderr, "\t-s file system size (sectors)\n");
579 fprintf(stderr, "\t-t tracks/cylinder\n");
580 fprintf(stderr, "\t-u sectors/track\n");
581 fprintf(stderr, "\t-x spare sectors per cylinder\n");
582 exit(1);
583}