use fsize, bsize from label if no args
[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
187d180d 14static char sccsid[] = "@(#)newfs.c 6.7 (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 */
c5d3fd78
MK
94#ifdef tahoe
95int realsectorsize; /* bytes/sector in hardware */
96#endif
c6003316 97int rpm; /* revolutions/minute of drive */
a20edd44
KM
98int interleave; /* hardware sector interleave */
99int trackskew = -1; /* sector 0 skew, per track */
100int headswitch; /* head switch time, usec */
101int trackseek; /* track-to-track seek, usec */
187d180d
MK
102int fsize = 0; /* fragment size */
103int bsize = 0; /* block size */
8485bb11
KM
104int cpg = DESCPG; /* cylinders/cylinder group */
105int minfree = MINFREE; /* free space threshold */
106int opt = DEFAULTOPT; /* optimization preference (space or time) */
107int density = NBPI; /* number of bytes per inode */
108int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */
109int rotdelay = ROTDELAY; /* rotational delay between blocks */
c5d3fd78
MK
110int bbsize = BBSIZE; /* boot block size */
111int sbsize = SBSIZE; /* superblock size */
8485bb11 112
a54c0b3f 113char device[MAXPATHLEN];
a54c0b3f 114
8485bb11 115extern int errno;
a54c0b3f
SL
116char *index();
117char *rindex();
118char *sprintf();
119
120main(argc, argv)
1b8b6e44 121 int argc;
a54c0b3f
SL
122 char *argv[];
123{
124 char *cp, *special;
a54c0b3f 125 register struct partition *pp;
8485bb11
KM
126 register struct disklabel *lp;
127 struct disklabel *getdisklabel();
128 struct partition oldpartition;
a54c0b3f 129 struct stat st;
8485bb11 130 int fsi, fso;
a54c0b3f
SL
131 register int i;
132 int status;
133
134 argc--, argv++;
135 while (argc > 0 && argv[0][0] == '-') {
136 for (cp = &argv[0][1]; *cp; cp++)
137 switch (*cp) {
138
28b1d98d
KM
139 case 'N':
140 Nflag++;
11b2fe08
HS
141 break;
142
8485bb11 143 case 'S':
a54c0b3f 144 if (argc < 1)
8485bb11 145 fatal("-S: missing sector size");
a54c0b3f 146 argc--, argv++;
8485bb11
KM
147 sectorsize = atoi(*argv);
148 if (sectorsize <= 0)
149 fatal("%s: bad sector size", *argv);
a54c0b3f
SL
150 goto next;
151
8485bb11 152 case 'a':
75e589fc 153 if (argc < 1)
8485bb11 154 fatal("-a: spare sectors per cylinder");
75e589fc 155 argc--, argv++;
a20edd44
KM
156 cylspares = atoi(*argv);
157 if (cylspares < 0)
8485bb11 158 fatal("%s: bad spare sectors per cylinder", *argv);
75e589fc
KM
159 goto next;
160
a54c0b3f
SL
161 case 'b':
162 if (argc < 1)
163 fatal("-b: missing block size");
164 argc--, argv++;
165 bsize = atoi(*argv);
8485bb11 166 if (bsize < MINBSIZE)
a54c0b3f
SL
167 fatal("%s: bad block size", *argv);
168 goto next;
169
8485bb11 170 case 'c':
a54c0b3f 171 if (argc < 1)
8485bb11 172 fatal("-c: missing cylinders/group");
a54c0b3f 173 argc--, argv++;
8485bb11
KM
174 cpg = atoi(*argv);
175 if (cpg <= 0)
176 fatal("%s: bad cylinders/group", *argv);
a54c0b3f
SL
177 goto next;
178
8485bb11 179 case 'd':
a54c0b3f 180 if (argc < 1)
8485bb11 181 fatal("-d: missing sectors/track");
a54c0b3f 182 argc--, argv++;
8485bb11
KM
183 nsectors = atoi(*argv);
184 if (nsectors <= 0)
185 fatal("%s: bad sectors/track", *argv);
a54c0b3f
SL
186 goto next;
187
8485bb11 188 case 'f':
a54c0b3f 189 if (argc < 1)
8485bb11 190 fatal("-f: missing frag size");
a54c0b3f 191 argc--, argv++;
8485bb11
KM
192 fsize = atoi(*argv);
193 if (fsize <= 0)
194 fatal("%s: bad frag size", *argv);
195 goto next;
196
197 case 'i':
198 if (argc < 1)
199 fatal("-i: missing bytes per inode\n");
200 argc--, argv++;
201 density = atoi(*argv);
202 if (density <= 0)
203 fatal("%s: bad bytes per inode\n",
204 *argv);
a54c0b3f
SL
205 goto next;
206
a20edd44
KM
207 case 'k':
208 if (argc < 1)
209 fatal("-k: track skew");
210 argc--, argv++;
211 trackskew = atoi(*argv);
212 if (trackskew < 0)
213 fatal("%s: bad track skew", *argv);
214 goto next;
215
216 case 'l':
217 if (argc < 1)
218 fatal("-l: interleave");
219 argc--, argv++;
220 interleave = atoi(*argv);
221 if (interleave <= 0)
222 fatal("%s: bad interleave", *argv);
223 goto next;
224
c6003316
SL
225 case 'm':
226 if (argc < 1)
227 fatal("-m: missing free space %%\n");
228 argc--, argv++;
229 minfree = atoi(*argv);
230 if (minfree < 0 || minfree > 99)
231 fatal("%s: bad free space %%\n",
232 *argv);
233 goto next;
234
8485bb11
KM
235 case 'o':
236 if (argc < 1)
237 fatal("-o: missing optimization preference");
238 argc--, argv++;
239 if (strcmp(*argv, "space") == 0)
240 opt = FS_OPTSPACE;
241 else if (strcmp(*argv, "time") == 0)
242 opt = FS_OPTTIME;
243 else
244 fatal("%s: bad optimization preference %s",
245 *argv,
246 "(options are `space' or `time')");
247 goto next;
248
a20edd44
KM
249 case 'p':
250 if (argc < 1)
251 fatal("-p: spare sectors per track");
252 argc--, argv++;
253 trackspares = atoi(*argv);
254 if (trackspares < 0)
255 fatal("%s: bad spare sectors per track", *argv);
256 goto next;
257
c6003316
SL
258 case 'r':
259 if (argc < 1)
260 fatal("-r: missing revs/minute\n");
261 argc--, argv++;
262 rpm = atoi(*argv);
8485bb11 263 if (rpm <= 0)
c6003316
SL
264 fatal("%s: bad revs/minute\n", *argv);
265 goto next;
266
8485bb11 267 case 's':
685a1465 268 if (argc < 1)
8485bb11 269 fatal("-s: missing file system size");
685a1465 270 argc--, argv++;
8485bb11
KM
271 fssize = atoi(*argv);
272 if (fssize <= 0)
273 fatal("%s: bad file system size",
685a1465
KM
274 *argv);
275 goto next;
276
8485bb11
KM
277 case 't':
278 if (argc < 1)
279 fatal("-t: missing track total");
280 argc--, argv++;
281 ntracks = atoi(*argv);
282 if (ntracks <= 0)
283 fatal("%s: bad total tracks", *argv);
284 goto next;
285
a54c0b3f
SL
286 default:
287 fatal("-%c: unknown flag", cp);
288 }
289next:
290 argc--, argv++;
291 }
8485bb11
KM
292 if (argc < 1) {
293 fprintf(stderr, "usage: newfs [ fsoptions ] special-device\n");
294 fprintf(stderr, "where fsoptions are:\n");
28b1d98d
KM
295 fprintf(stderr, "\t-N do not create file system, %s\n",
296 "just print out parameters");
e6b4584b
SL
297 fprintf(stderr, "\t-b block size\n");
298 fprintf(stderr, "\t-f frag size\n");
c6003316 299 fprintf(stderr, "\t-m minimum free space %%\n");
75e589fc
KM
300 fprintf(stderr, "\t-o optimization preference %s\n",
301 "(`space' or `time')");
685a1465 302 fprintf(stderr, "\t-i number of bytes per inode\n");
6bd85141
KM
303 fprintf(stderr, "\t-c cylinders/group\n");
304 fprintf(stderr, "\t-s file system size (sectors)\n");
305 fprintf(stderr, "\t-r revolutions/minute\n");
8485bb11 306 fprintf(stderr, "\t-S sector size\n");
6bd85141
KM
307 fprintf(stderr, "\t-d sectors/track\n");
308 fprintf(stderr, "\t-t tracks/cylinder\n");
a20edd44 309 fprintf(stderr, "\t-p spare sectors per track\n");
8485bb11 310 fprintf(stderr, "\t-a spare sectors per cylinder\n");
6bd85141
KM
311 fprintf(stderr, "\t-l hardware sector interleave\n");
312 fprintf(stderr, "\t-k sector 0 skew, per track\n");
a54c0b3f
SL
313 exit(1);
314 }
315 special = argv[0];
1b8b6e44
KM
316 cp = rindex(special, '/');
317 if (cp != 0)
318 special = cp + 1;
2f56e34c 319 if (*special == 'r' && special[1] != 'a' && special[1] != 'b')
1b8b6e44
KM
320 special++;
321 special = sprintf(device, "/dev/r%s", special);
8485bb11
KM
322 if (!Nflag) {
323 fso = open(special, O_WRONLY);
324 if (fso < 0) {
325 perror(special);
326 exit(1);
327 }
328 } else
329 fso = -1;
330 fsi = open(special, O_RDONLY);
331 if (fsi < 0) {
332 perror(special);
333 exit(1);
334 }
335 if (fstat(fsi, &st) < 0) {
c6003316 336 fprintf(stderr, "newfs: "); perror(special);
a54c0b3f
SL
337 exit(2);
338 }
1b8b6e44
KM
339 if ((st.st_mode & S_IFMT) != S_IFCHR)
340 fatal("%s: not a character device", special);
a54c0b3f 341 cp = index(argv[0], '\0') - 1;
8485bb11 342 if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
a54c0b3f 343 fatal("%s: can't figure out file system partition", argv[0]);
8485bb11
KM
344 lp = getdisklabel(special, fsi);
345 if (isdigit(*cp))
346 pp = &lp->d_partitions[0];
347 else
348 pp = &lp->d_partitions[*cp - 'a'];
349 if (pp->p_size == 0)
350 fatal("%s: `%c' partition is unavailable", argv[0], *cp);
351 if (fssize == 0)
a54c0b3f 352 fssize = pp->p_size;
8485bb11
KM
353 if (fssize > pp->p_size)
354 fatal("%s: maximum file system size on the `%c' partition is %d",
355 argv[0], *cp, pp->p_size);
356 if (rpm == 0) {
357 rpm = lp->d_rpm;
358 if (rpm <= 0)
6181c540 359 rpm = 3600;
a54c0b3f
SL
360 }
361 if (ntracks == 0) {
8485bb11
KM
362 ntracks = lp->d_ntracks;
363 if (ntracks <= 0)
6181c540 364 fatal("%s: no default #tracks", argv[0]);
a54c0b3f 365 }
8485bb11
KM
366 if (nsectors == 0) {
367 nsectors = lp->d_nsectors;
368 if (nsectors <= 0)
6181c540 369 fatal("%s: no default #sectors/track", argv[0]);
8485bb11 370 }
a54c0b3f 371 if (sectorsize == 0) {
8485bb11
KM
372 sectorsize = lp->d_secsize;
373 if (sectorsize <= 0)
6181c540 374 fatal("%s: no default sector size", argv[0]);
a54c0b3f 375 }
a20edd44
KM
376 if (trackskew == -1) {
377 trackskew = lp->d_trackskew;
378 if (trackskew < 0)
6181c540 379 trackskew = 0;
a20edd44
KM
380 }
381 if (interleave == 0) {
382 interleave = lp->d_interleave;
383 if (interleave <= 0)
6181c540 384 interleave = 1;
a20edd44 385 }
a54c0b3f
SL
386 if (fsize == 0) {
387 fsize = pp->p_fsize;
8485bb11
KM
388 if (fsize <= 0)
389 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
a54c0b3f 390 }
8485bb11
KM
391 if (bsize == 0) {
392 bsize = pp->p_frag * pp->p_fsize;
393 if (bsize <= 0)
394 bsize = MIN(DFL_BLKSIZE, 8 * fsize);
c6003316 395 }
75e589fc 396 if (minfree < 10 && opt != FS_OPTSPACE) {
8485bb11
KM
397 fprintf(stderr, "Warning: changing optimization to space ");
398 fprintf(stderr, "because minfree is less than 10%%\n");
75e589fc
KM
399 opt = FS_OPTSPACE;
400 }
a20edd44
KM
401 if (trackspares == -1) {
402 trackspares = lp->d_sparespertrack;
403 if (trackspares < 0)
6181c540 404 trackspares = 0;
a20edd44
KM
405 }
406 nphyssectors = nsectors + trackspares;
407 if (cylspares == -1) {
408 cylspares = lp->d_sparespercyl;
409 if (cylspares < 0)
6181c540 410 cylspares = 0;
a20edd44
KM
411 }
412 secpercyl = nsectors * ntracks - cylspares;
8485bb11
KM
413 if (secpercyl != lp->d_secpercyl)
414 fprintf(stderr, "%s (%d) %s (%d)\n",
415 "Warning: calculated sectors per cylinder", secpercyl,
416 "disagrees with disk label", lp->d_secpercyl);
a20edd44
KM
417 headswitch = lp->d_headswitch;
418 trackseek = lp->d_trkseek;
c5d3fd78
MK
419 bbsize = lp->d_bbsize;
420 sbsize = lp->d_sbsize;
8485bb11 421 oldpartition = *pp;
c5d3fd78
MK
422#ifdef tahoe
423 realsectorsize = sectorsize;
187d180d 424 if (sectorsize != DEV_BSIZE) { /* XXX */
c5d3fd78
MK
425 int secperblk = DEV_BSIZE / sectorsize;
426
427 sectorsize = DEV_BSIZE;
428 nsectors /= secperblk;
429 nphyssectors /= secperblk;
430 secpercyl /= secperblk;
431 fssize /= secperblk;
432 pp->p_size /= secperblk;
433 }
434#endif
8485bb11 435 mkfs(pp, special, fsi, fso);
c5d3fd78
MK
436#ifdef tahoe
437 if (realsectorsize != DEV_BSIZE)
438 pp->p_size *= DEV_BSIZE / realsectorsize;
439#endif
8485bb11
KM
440 if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition)))
441 rewritelabel(special, fso, lp);
a54c0b3f
SL
442 exit(0);
443}
444
8485bb11
KM
445struct disklabel *
446getdisklabel(s, fd)
447 char *s;
448 int fd;
a54c0b3f 449{
8485bb11
KM
450 static struct disklabel lab;
451
452 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
453 perror("ioctl (GDINFO)");
454 fatal("%s: can't read disk label", s);
455 }
456 return (&lab);
457}
458
459rewritelabel(s, fd, lp)
460 char *s;
a54c0b3f 461 int fd;
8485bb11
KM
462 register struct disklabel *lp;
463{
464
465 lp->d_checksum = 0;
466 lp->d_checksum = dkcksum(lp);
467 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
468 perror("ioctl (GWINFO)");
469 fatal("%s: can't rewrite disk label", s);
a54c0b3f 470 }
bf8f0524
MK
471#if vax
472 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
473 register i;
c5d3fd78 474 int cfd;
bf8f0524 475 daddr_t alt;
c5d3fd78
MK
476 char specname[64];
477 char blk[1024];
478
479 /*
480 * Make name for 'c' partition.
481 */
482 strcpy(specname, s);
483 cp = specname + strlen(specname) - 1;
484 if (!isdigit(*cp))
485 *cp = 'c';
486 cfd = open(specname, O_WRONLY);
487 if (cfd < 0) {
488 perror(specname);
489 exit(2);
490 }
491 bzero(blk, sizeof(blk));
492 *(struct disklabel *)(blk + LABELOFFSET) = *lp;
bf8f0524
MK
493 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
494 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
495 lseek(cfd, (off_t)(alt + i) * lp->d_secsize, L_SET);
c5d3fd78 496 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) {
bf8f0524
MK
497 int oerrno = errno;
498 fprintf(stderr, "alternate label %d ", i/2);
499 errno = oerrno;
500 perror("write");
501 }
8485bb11
KM
502 }
503 }
bf8f0524 504#endif
a54c0b3f
SL
505}
506
507/*VARARGS*/
508fatal(fmt, arg1, arg2)
509 char *fmt;
510{
511
c6003316 512 fprintf(stderr, "newfs: ");
a54c0b3f
SL
513 fprintf(stderr, fmt, arg1, arg2);
514 putc('\n', stderr);
515 exit(10);
516}