xref: /original-bsd/sbin/newlfs/newfs.c (revision 333da485)
1 /*-
2  * Copyright (c) 1989, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1989, 1992, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)newfs.c	8.2 (Berkeley) 01/13/94";
16 #endif /* not lint */
17 
18 /*
19  * newfs: friendly front end to mkfs
20  */
21 #include <sys/param.h>
22 #include <sys/ucred.h>
23 #include <sys/stat.h>
24 #include <sys/ioctl.h>
25 #include <sys/disklabel.h>
26 #include <sys/file.h>
27 #include <sys/mount.h>
28 
29 #include <ufs/ufs/dir.h>
30 #include <ufs/ufs/dinode.h>
31 #include <ufs/ffs/fs.h>
32 
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 
45 int	mfs;			/* run as the memory based filesystem */
46 int	Nflag;			/* run without writing file system */
47 int	fssize;			/* file system size */
48 int	ntracks;		/* # tracks/cylinder */
49 int	nsectors;		/* # sectors/track */
50 int	nphyssectors;		/* # sectors/track including spares */
51 int	secpercyl;		/* sectors per cylinder */
52 int	trackspares = -1;	/* spare sectors per track */
53 int	cylspares = -1;		/* spare sectors per cylinder */
54 int	sectorsize;		/* bytes/sector */
55 #ifdef tahoe
56 int	realsectorsize;		/* bytes/sector in hardware */
57 #endif
58 int	rpm;			/* revolutions/minute of drive */
59 int	interleave;		/* hardware sector interleave */
60 int	trackskew = -1;		/* sector 0 skew, per track */
61 int	headswitch;		/* head switch time, usec */
62 int	trackseek;		/* track-to-track seek, usec */
63 int	fsize = 0;		/* fragment size */
64 int	bsize = 0;		/* block size */
65 int	cpg = DESCPG;		/* cylinders/cylinder group */
66 int	cpgflg;			/* cylinders/cylinder group flag was given */
67 int	minfree = MINFREE;	/* free space threshold */
68 int	opt = DEFAULTOPT;	/* optimization preference (space or time) */
69 int	density;		/* number of bytes per inode */
70 int	maxcontig = MAXCONTIG;	/* max contiguous blocks to allocate */
71 int	rotdelay = ROTDELAY;	/* rotational delay between blocks */
72 int	maxbpg;			/* maximum blocks per file in a cyl group */
73 int	nrpos = NRPOS;		/* # of distinguished rotational positions */
74 int	bbsize = BBSIZE;	/* boot block size */
75 int	sbsize = SBSIZE;	/* superblock size */
76 int	mntflags;		/* flags to be passed to mount */
77 u_long	memleft;		/* virtual memory available */
78 caddr_t	membase;		/* start address of memory based filesystem */
79 #ifdef COMPAT
80 char	*disktype;
81 int	unlabeled;
82 #endif
83 
84 char	device[MAXPATHLEN];
85 char	*progname, *special;
86 
87 static struct disklabel *getdisklabel __P((char *, int));
88 static struct disklabel *debug_readlabel __P((int));
89 static void rewritelabel __P((char *, int, struct disklabel *));
90 static void usage __P((void));
91 
92 int
93 main(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)) < LFS_MINBLOCKSIZE)
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 
268 	if (!debug && !mfs && !S_ISCHR(st.st_mode))
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 */
292 	exit(make_lfs(fso, lp, pp, minfree, bsize, segsize));
293 }
294 
295 #ifdef COMPAT
296 char lmsg[] = "%s: can't read disk label; disk type must be specified";
297 #else
298 char lmsg[] = "%s: can't read disk label";
299 #endif
300 
301 static struct disklabel *
302 getdisklabel(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 
328 static struct disklabel *
329 debug_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 
343 static void
344 rewritelabel(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 
397 void
398 usage()
399 {
400 	if (mfs) {
401 		fprintf(stderr,
402 		    "usage: mfs [ -fsoptions ] special-device mount-point\n");
403 	} else
404 		fprintf(stderr,
405 		    "usage: newlfs [ -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 }
442