date and time created 87/02/15 16:03:39 by lepreau
[unix-history] / usr / src / sbin / newfs / newfs.c
CommitLineData
c018628f
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
a54c0b3f 13#ifndef lint
bf8f0524 14static char sccsid[] = "@(#)newfs.c 6.4 (Berkeley) %G%";
c018628f 15#endif not lint
a54c0b3f
SL
16
17/*
c6003316 18 * newfs: friendly front end to mkfs
a54c0b3f
SL
19 */
20#include <sys/param.h>
21#include <sys/stat.h>
22#include <sys/fs.h>
14b4eb74 23#include <sys/dir.h>
8485bb11
KM
24#include <sys/ioctl.h>
25#include <sys/disklabel.h>
26#include <sys/file.h>
a54c0b3f
SL
27
28#include <stdio.h>
8485bb11 29#include <ctype.h>
a54c0b3f 30
8485bb11
KM
31/*
32 * The following two constants set the default block and fragment sizes.
33 * Both constants must be a power of 2 and meet the following constraints:
34 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE
35 * sectorsize <= DESFRAGSIZE <= DESBLKSIZE
36 * DESBLKSIZE / DESFRAGSIZE <= 8
37 */
38#define DFL_FRAGSIZE 1024
39#define DFL_BLKSIZE 8192
40
41/*
42 * Cylinder groups may have up to MAXCPG cylinders. The actual
43 * number used depends upon how much information can be stored
44 * on a single cylinder. The default is to used 16 cylinders
45 * per group.
46 */
47#define DESCPG 16 /* desired fs_cpg */
89241117 48
8485bb11
KM
49/*
50 * MINFREE gives the minimum acceptable percentage of file system
51 * blocks which may be free. If the freelist drops below this level
52 * only the superuser may continue to allocate blocks. This may
53 * be set to 0 if no reserve of free blocks is deemed necessary,
54 * however throughput drops by fifty percent if the file system
55 * is run at between 90% and 100% full; thus the default value of
56 * fs_minfree is 10%. With 10% free space, fragmentation is not a
57 * problem, so we choose to optimize for time.
58 */
59#define MINFREE 10
60#define DEFAULTOPT FS_OPTTIME
61
62/*
63 * ROTDELAY gives the minimum number of milliseconds to initiate
64 * another disk transfer on the same cylinder. It is used in
65 * determining the rotationally optimal layout for disk blocks
66 * within a file; the default of fs_rotdelay is 4ms.
67 */
68#define ROTDELAY 4
69
70/*
71 * MAXCONTIG sets the default for the maximum number of blocks
72 * that may be allocated sequentially. Since UNIX drivers are
73 * not capable of scheduling multi-block transfers, this defaults
74 * to 1 (ie no contiguous blocks are allocated).
75 */
76#define MAXCONTIG 1
77
78/*
79 * Each file system has a number of inodes statically allocated.
80 * We allocate one inode slot per NBPI bytes, expecting this
81 * to be far more than we will ever need.
82 */
83#define NBPI 2048
84
85int Nflag; /* run without writing file system */
a54c0b3f 86int fssize; /* file system size */
a54c0b3f
SL
87int ntracks; /* # tracks/cylinder */
88int nsectors; /* # sectors/track */
a20edd44 89int nphyssectors; /* # sectors/track including spares */
8485bb11 90int secpercyl; /* sectors per cylinder */
a20edd44
KM
91int trackspares = -1; /* spare sectors per track */
92int cylspares = -1; /* spare sectors per cylinder */
a54c0b3f 93int sectorsize; /* bytes/sector */
c6003316 94int rpm; /* revolutions/minute of drive */
a20edd44
KM
95int interleave; /* hardware sector interleave */
96int trackskew = -1; /* sector 0 skew, per track */
97int headswitch; /* head switch time, usec */
98int trackseek; /* track-to-track seek, usec */
8485bb11
KM
99int fsize = DFL_FRAGSIZE; /* fragment size */
100int bsize = DFL_BLKSIZE; /* block size */
101int cpg = DESCPG; /* cylinders/cylinder group */
102int minfree = MINFREE; /* free space threshold */
103int opt = DEFAULTOPT; /* optimization preference (space or time) */
104int density = NBPI; /* number of bytes per inode */
105int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */
106int rotdelay = ROTDELAY; /* rotational delay between blocks */
107
a54c0b3f 108char device[MAXPATHLEN];
a54c0b3f 109
8485bb11 110extern int errno;
a54c0b3f
SL
111char *index();
112char *rindex();
113char *sprintf();
114
115main(argc, argv)
1b8b6e44 116 int argc;
a54c0b3f
SL
117 char *argv[];
118{
119 char *cp, *special;
a54c0b3f 120 register struct partition *pp;
8485bb11
KM
121 register struct disklabel *lp;
122 struct disklabel *getdisklabel();
123 struct partition oldpartition;
a54c0b3f 124 struct stat st;
8485bb11 125 int fsi, fso;
a54c0b3f
SL
126 register int i;
127 int status;
128
129 argc--, argv++;
130 while (argc > 0 && argv[0][0] == '-') {
131 for (cp = &argv[0][1]; *cp; cp++)
132 switch (*cp) {
133
28b1d98d
KM
134 case 'N':
135 Nflag++;
11b2fe08
HS
136 break;
137
8485bb11 138 case 'S':
a54c0b3f 139 if (argc < 1)
8485bb11 140 fatal("-S: missing sector size");
a54c0b3f 141 argc--, argv++;
8485bb11
KM
142 sectorsize = atoi(*argv);
143 if (sectorsize <= 0)
144 fatal("%s: bad sector size", *argv);
a54c0b3f
SL
145 goto next;
146
8485bb11 147 case 'a':
75e589fc 148 if (argc < 1)
8485bb11 149 fatal("-a: spare sectors per cylinder");
75e589fc 150 argc--, argv++;
a20edd44
KM
151 cylspares = atoi(*argv);
152 if (cylspares < 0)
8485bb11 153 fatal("%s: bad spare sectors per cylinder", *argv);
75e589fc
KM
154 goto next;
155
a54c0b3f
SL
156 case 'b':
157 if (argc < 1)
158 fatal("-b: missing block size");
159 argc--, argv++;
160 bsize = atoi(*argv);
8485bb11 161 if (bsize < MINBSIZE)
a54c0b3f
SL
162 fatal("%s: bad block size", *argv);
163 goto next;
164
8485bb11 165 case 'c':
a54c0b3f 166 if (argc < 1)
8485bb11 167 fatal("-c: missing cylinders/group");
a54c0b3f 168 argc--, argv++;
8485bb11
KM
169 cpg = atoi(*argv);
170 if (cpg <= 0)
171 fatal("%s: bad cylinders/group", *argv);
a54c0b3f
SL
172 goto next;
173
8485bb11 174 case 'd':
a54c0b3f 175 if (argc < 1)
8485bb11 176 fatal("-d: missing sectors/track");
a54c0b3f 177 argc--, argv++;
8485bb11
KM
178 nsectors = atoi(*argv);
179 if (nsectors <= 0)
180 fatal("%s: bad sectors/track", *argv);
a54c0b3f
SL
181 goto next;
182
8485bb11 183 case 'f':
a54c0b3f 184 if (argc < 1)
8485bb11 185 fatal("-f: missing frag size");
a54c0b3f 186 argc--, argv++;
8485bb11
KM
187 fsize = atoi(*argv);
188 if (fsize <= 0)
189 fatal("%s: bad frag size", *argv);
190 goto next;
191
192 case 'i':
193 if (argc < 1)
194 fatal("-i: missing bytes per inode\n");
195 argc--, argv++;
196 density = atoi(*argv);
197 if (density <= 0)
198 fatal("%s: bad bytes per inode\n",
199 *argv);
a54c0b3f
SL
200 goto next;
201
a20edd44
KM
202 case 'k':
203 if (argc < 1)
204 fatal("-k: track skew");
205 argc--, argv++;
206 trackskew = atoi(*argv);
207 if (trackskew < 0)
208 fatal("%s: bad track skew", *argv);
209 goto next;
210
211 case 'l':
212 if (argc < 1)
213 fatal("-l: interleave");
214 argc--, argv++;
215 interleave = atoi(*argv);
216 if (interleave <= 0)
217 fatal("%s: bad interleave", *argv);
218 goto next;
219
c6003316
SL
220 case 'm':
221 if (argc < 1)
222 fatal("-m: missing free space %%\n");
223 argc--, argv++;
224 minfree = atoi(*argv);
225 if (minfree < 0 || minfree > 99)
226 fatal("%s: bad free space %%\n",
227 *argv);
228 goto next;
229
8485bb11
KM
230 case 'o':
231 if (argc < 1)
232 fatal("-o: missing optimization preference");
233 argc--, argv++;
234 if (strcmp(*argv, "space") == 0)
235 opt = FS_OPTSPACE;
236 else if (strcmp(*argv, "time") == 0)
237 opt = FS_OPTTIME;
238 else
239 fatal("%s: bad optimization preference %s",
240 *argv,
241 "(options are `space' or `time')");
242 goto next;
243
a20edd44
KM
244 case 'p':
245 if (argc < 1)
246 fatal("-p: spare sectors per track");
247 argc--, argv++;
248 trackspares = atoi(*argv);
249 if (trackspares < 0)
250 fatal("%s: bad spare sectors per track", *argv);
251 goto next;
252
c6003316
SL
253 case 'r':
254 if (argc < 1)
255 fatal("-r: missing revs/minute\n");
256 argc--, argv++;
257 rpm = atoi(*argv);
8485bb11 258 if (rpm <= 0)
c6003316
SL
259 fatal("%s: bad revs/minute\n", *argv);
260 goto next;
261
8485bb11 262 case 's':
685a1465 263 if (argc < 1)
8485bb11 264 fatal("-s: missing file system size");
685a1465 265 argc--, argv++;
8485bb11
KM
266 fssize = atoi(*argv);
267 if (fssize <= 0)
268 fatal("%s: bad file system size",
685a1465
KM
269 *argv);
270 goto next;
271
8485bb11
KM
272 case 't':
273 if (argc < 1)
274 fatal("-t: missing track total");
275 argc--, argv++;
276 ntracks = atoi(*argv);
277 if (ntracks <= 0)
278 fatal("%s: bad total tracks", *argv);
279 goto next;
280
a54c0b3f
SL
281 default:
282 fatal("-%c: unknown flag", cp);
283 }
284next:
285 argc--, argv++;
286 }
8485bb11
KM
287 if (argc < 1) {
288 fprintf(stderr, "usage: newfs [ fsoptions ] special-device\n");
289 fprintf(stderr, "where fsoptions are:\n");
28b1d98d
KM
290 fprintf(stderr, "\t-N do not create file system, %s\n",
291 "just print out parameters");
e6b4584b
SL
292 fprintf(stderr, "\t-b block size\n");
293 fprintf(stderr, "\t-f frag size\n");
c6003316 294 fprintf(stderr, "\t-m minimum free space %%\n");
75e589fc
KM
295 fprintf(stderr, "\t-o optimization preference %s\n",
296 "(`space' or `time')");
685a1465 297 fprintf(stderr, "\t-i number of bytes per inode\n");
6bd85141
KM
298 fprintf(stderr, "\t-c cylinders/group\n");
299 fprintf(stderr, "\t-s file system size (sectors)\n");
300 fprintf(stderr, "\t-r revolutions/minute\n");
8485bb11 301 fprintf(stderr, "\t-S sector size\n");
6bd85141
KM
302 fprintf(stderr, "\t-d sectors/track\n");
303 fprintf(stderr, "\t-t tracks/cylinder\n");
a20edd44 304 fprintf(stderr, "\t-p spare sectors per track\n");
8485bb11 305 fprintf(stderr, "\t-a spare sectors per cylinder\n");
6bd85141
KM
306 fprintf(stderr, "\t-l hardware sector interleave\n");
307 fprintf(stderr, "\t-k sector 0 skew, per track\n");
a54c0b3f
SL
308 exit(1);
309 }
310 special = argv[0];
1b8b6e44
KM
311 cp = rindex(special, '/');
312 if (cp != 0)
313 special = cp + 1;
2f56e34c 314 if (*special == 'r' && special[1] != 'a' && special[1] != 'b')
1b8b6e44
KM
315 special++;
316 special = sprintf(device, "/dev/r%s", special);
8485bb11
KM
317 if (!Nflag) {
318 fso = open(special, O_WRONLY);
319 if (fso < 0) {
320 perror(special);
321 exit(1);
322 }
323 } else
324 fso = -1;
325 fsi = open(special, O_RDONLY);
326 if (fsi < 0) {
327 perror(special);
328 exit(1);
329 }
330 if (fstat(fsi, &st) < 0) {
c6003316 331 fprintf(stderr, "newfs: "); perror(special);
a54c0b3f
SL
332 exit(2);
333 }
1b8b6e44
KM
334 if ((st.st_mode & S_IFMT) != S_IFCHR)
335 fatal("%s: not a character device", special);
a54c0b3f 336 cp = index(argv[0], '\0') - 1;
8485bb11 337 if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
a54c0b3f 338 fatal("%s: can't figure out file system partition", argv[0]);
8485bb11
KM
339 lp = getdisklabel(special, fsi);
340 if (isdigit(*cp))
341 pp = &lp->d_partitions[0];
342 else
343 pp = &lp->d_partitions[*cp - 'a'];
344 if (pp->p_size == 0)
345 fatal("%s: `%c' partition is unavailable", argv[0], *cp);
346 if (fssize == 0)
a54c0b3f 347 fssize = pp->p_size;
8485bb11
KM
348 if (fssize > pp->p_size)
349 fatal("%s: maximum file system size on the `%c' partition is %d",
350 argv[0], *cp, pp->p_size);
351 if (rpm == 0) {
352 rpm = lp->d_rpm;
353 if (rpm <= 0)
354 fatal("%s: no default rpm", argv[1]);
a54c0b3f
SL
355 }
356 if (ntracks == 0) {
8485bb11
KM
357 ntracks = lp->d_ntracks;
358 if (ntracks <= 0)
a54c0b3f
SL
359 fatal("%s: no default #tracks", argv[1]);
360 }
8485bb11
KM
361 if (nsectors == 0) {
362 nsectors = lp->d_nsectors;
363 if (nsectors <= 0)
364 fatal("%s: no default #sectors/track", argv[1]);
365 }
a54c0b3f 366 if (sectorsize == 0) {
8485bb11
KM
367 sectorsize = lp->d_secsize;
368 if (sectorsize <= 0)
a54c0b3f
SL
369 fatal("%s: no default sector size", argv[1]);
370 }
a20edd44
KM
371 if (trackskew == -1) {
372 trackskew = lp->d_trackskew;
373 if (trackskew < 0)
374 fatal("%s: no default track skew", argv[1]);
375 }
376 if (interleave == 0) {
377 interleave = lp->d_interleave;
378 if (interleave <= 0)
379 fatal("%s: no default interleave", argv[1]);
380 }
a54c0b3f
SL
381 if (fsize == 0) {
382 fsize = pp->p_fsize;
8485bb11
KM
383 if (fsize <= 0)
384 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
a54c0b3f 385 }
8485bb11
KM
386 if (bsize == 0) {
387 bsize = pp->p_frag * pp->p_fsize;
388 if (bsize <= 0)
389 bsize = MIN(DFL_BLKSIZE, 8 * fsize);
c6003316 390 }
75e589fc 391 if (minfree < 10 && opt != FS_OPTSPACE) {
8485bb11
KM
392 fprintf(stderr, "Warning: changing optimization to space ");
393 fprintf(stderr, "because minfree is less than 10%%\n");
75e589fc
KM
394 opt = FS_OPTSPACE;
395 }
a20edd44
KM
396 if (trackspares == -1) {
397 trackspares = lp->d_sparespertrack;
398 if (trackspares < 0)
399 fatal("%s: no default spares/track", argv[1]);
400 }
401 nphyssectors = nsectors + trackspares;
402 if (cylspares == -1) {
403 cylspares = lp->d_sparespercyl;
404 if (cylspares < 0)
405 fatal("%s: no default spares/cylinder", argv[1]);
406 }
407 secpercyl = nsectors * ntracks - cylspares;
8485bb11
KM
408 if (secpercyl != lp->d_secpercyl)
409 fprintf(stderr, "%s (%d) %s (%d)\n",
410 "Warning: calculated sectors per cylinder", secpercyl,
411 "disagrees with disk label", lp->d_secpercyl);
a20edd44
KM
412 headswitch = lp->d_headswitch;
413 trackseek = lp->d_trkseek;
8485bb11
KM
414 oldpartition = *pp;
415 mkfs(pp, special, fsi, fso);
416 if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition)))
417 rewritelabel(special, fso, lp);
a54c0b3f
SL
418 exit(0);
419}
420
8485bb11
KM
421#ifdef byioctl
422struct disklabel *
423getdisklabel(s, fd)
424 char *s;
425 int fd;
a54c0b3f 426{
8485bb11
KM
427 static struct disklabel lab;
428
429 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
430 perror("ioctl (GDINFO)");
431 fatal("%s: can't read disk label", s);
432 }
433 return (&lab);
434}
435
436rewritelabel(s, fd, lp)
437 char *s;
a54c0b3f 438 int fd;
8485bb11
KM
439 register struct disklabel *lp;
440{
441
442 lp->d_checksum = 0;
443 lp->d_checksum = dkcksum(lp);
444 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
445 perror("ioctl (GWINFO)");
446 fatal("%s: can't rewrite disk label", s);
a54c0b3f 447 }
8485bb11
KM
448}
449#else byioctl
450char specname[64];
451char boot[BBSIZE];
452
453struct disklabel *
454getdisklabel(s, fd)
455 char *s;
456 int fd;
457{
458 char *cp;
459 u_long magic = htonl(DISKMAGIC);
460 register struct disklabel *lp;
461 int cfd;
462
463 /*
464 * Make name for 'c' partition.
465 */
466 strcpy(specname, s);
467 cp = specname + strlen(specname) - 1;
468 if (!isdigit(*cp))
469 *cp = 'c';
470 cfd = open(specname, O_RDONLY);
471 if (cfd < 0) {
472 perror(specname);
473 exit(2);
a54c0b3f 474 }
8485bb11
KM
475
476 if (read(cfd, boot, BBSIZE) < BBSIZE) {
477 perror(specname);
a54c0b3f
SL
478 exit(2);
479 }
8485bb11
KM
480 close(cfd);
481 for (lp = (struct disklabel *)(boot + LABELOFFSET);
482 lp <= (struct disklabel *)(boot + BBSIZE -
483 sizeof(struct disklabel));
484 lp = (struct disklabel *)((char *)lp + 128))
485 if (lp->d_magic == magic && lp->d_magic2 == magic)
486 break;
487 if (lp > (struct disklabel *)(boot + BBSIZE -
488 sizeof(struct disklabel)) ||
489 lp->d_magic != magic || lp->d_magic2 != magic ||
490 dkcksum(lp) != 0) {
491 fprintf(stderr,
492 "Bad pack magic number (label is damaged, or pack is unlabeled)\n");
a54c0b3f
SL
493 exit(1);
494 }
8485bb11
KM
495 return (lp);
496}
497
498rewritelabel(s, fd, lp)
499 char *s;
500 int fd;
501 register struct disklabel *lp;
502{
bf8f0524
MK
503 int cfd;
504
8485bb11
KM
505 lp->d_checksum = 0;
506 lp->d_checksum = dkcksum(lp);
507 cfd = open(specname, O_WRONLY);
508 if (cfd < 0) {
509 perror(specname);
a54c0b3f
SL
510 exit(2);
511 }
8485bb11
KM
512 lseek(cfd, (off_t)0, L_SET);
513 if (write(cfd, boot, BBSIZE) < BBSIZE) {
514 perror(specname);
a54c0b3f
SL
515 exit(2);
516 }
bf8f0524
MK
517#if vax
518 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
519 register i;
520 daddr_t alt;
521
522 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
523 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
524 lseek(cfd, (off_t)(alt + i) * lp->d_secsize, L_SET);
525 if (write(cfd, boot, lp->d_secsize) < lp->d_secsize) {
526 int oerrno = errno;
527 fprintf(stderr, "alternate label %d ", i/2);
528 errno = oerrno;
529 perror("write");
530 }
8485bb11
KM
531 }
532 }
bf8f0524 533#endif
8485bb11 534 close(cfd);
a54c0b3f 535}
8485bb11 536#endif byioctl
a54c0b3f
SL
537
538/*VARARGS*/
539fatal(fmt, arg1, arg2)
540 char *fmt;
541{
542
c6003316 543 fprintf(stderr, "newfs: ");
a54c0b3f
SL
544 fprintf(stderr, fmt, arg1, arg2);
545 putc('\n', stderr);
546 exit(10);
547}