xref: /original-bsd/sbin/fsck/main.c (revision 3708840b)
1 char version[] = "@(#)main.c	2.23	(Berkeley)	05/22/83";
2 
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <sys/param.h>
6 #include <sys/fs.h>
7 #include <sys/inode.h>
8 #include <dir.h>
9 #include <sys/stat.h>
10 #include <fstab.h>
11 
12 /* RECONSTRUCT ONLY BAD CG IN PASS 6 */
13 
14 typedef	int	(*SIG_TYP)();
15 
16 #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
17 #define	MAXINOPB	(MAXBSIZE / sizeof (struct dinode))
18 #define	SPERB		(MAXBSIZE / sizeof(short))
19 
20 #define	MAXDUP	10		/* limit on dup blks (per inode) */
21 #define	MAXBAD	10		/* limit on bad blks (per inode) */
22 
23 #define	USTATE	0		/* inode not allocated */
24 #define	FSTATE	01		/* inode is file */
25 #define	DSTATE	02		/* inode is directory */
26 #define	CLEAR	03		/* inode is to be cleared */
27 
28 typedef struct dinode	DINODE;
29 typedef struct direct	DIRECT;
30 
31 #define	ALLOC	((dp->di_mode & IFMT) != 0)
32 #define	DIRCT	((dp->di_mode & IFMT) == IFDIR)
33 #define	REG	((dp->di_mode & IFMT) == IFREG)
34 #define	BLK	((dp->di_mode & IFMT) == IFBLK)
35 #define	CHR	((dp->di_mode & IFMT) == IFCHR)
36 #define	LNK	((dp->di_mode & IFMT) == IFLNK)
37 #define	SOCK	((dp->di_mode & IFMT) == IFSOCK)
38 #define	BADBLK	((dp->di_mode & IFMT) == IFMT)
39 #define	SPECIAL	(BLK || CHR)
40 
41 ino_t	startinum;		/* blk num of first in raw area */
42 
43 struct bufarea {
44 	struct bufarea	*b_next;		/* must be first */
45 	daddr_t	b_bno;
46 	int	b_size;
47 	union {
48 		char	b_buf[MAXBSIZE];	/* buffer space */
49 		short	b_lnks[SPERB];		/* link counts */
50 		daddr_t	b_indir[MAXNINDIR];	/* indirect block */
51 		struct	fs b_fs;		/* super block */
52 		struct	cg b_cg;		/* cylinder group */
53 		struct dinode b_dinode[MAXINOPB]; /* inode block */
54 	} b_un;
55 	char	b_dirty;
56 };
57 
58 typedef struct bufarea BUFAREA;
59 
60 BUFAREA	inoblk;			/* inode blocks */
61 BUFAREA	fileblk;		/* other blks in filesys */
62 BUFAREA	sblk;			/* file system superblock */
63 BUFAREA	cgblk;
64 
65 #define	initbarea(x)	(x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
66 #define	dirty(x)	(x)->b_dirty = 1
67 #define	inodirty()	inoblk.b_dirty = 1
68 #define	sbdirty()	sblk.b_dirty = 1
69 #define	cgdirty()	cgblk.b_dirty = 1
70 
71 #define	dirblk		fileblk.b_un
72 #define	sblock		sblk.b_un.b_fs
73 #define	cgrp		cgblk.b_un.b_cg
74 
75 struct filecntl {
76 	int	rfdes;
77 	int	wfdes;
78 	int	mod;
79 } dfile;			/* file descriptors for filesys */
80 
81 #define	DUPTBLSIZE	100	/* num of dup blocks to remember */
82 daddr_t	duplist[DUPTBLSIZE];	/* dup block table */
83 daddr_t	*enddup;		/* next entry in dup table */
84 daddr_t	*muldup;		/* multiple dups part of table */
85 
86 #define	MAXLNCNT	500	/* num zero link cnts to remember */
87 ino_t	badlncnt[MAXLNCNT];	/* table of inos with zero link cnts */
88 ino_t	*badlnp;		/* next entry in table */
89 
90 char	rawflg;
91 char	nflag;			/* assume a no response */
92 char	yflag;			/* assume a yes response */
93 int	bflag;			/* location of alternate super block */
94 int	debug;			/* output debugging info */
95 char	preen;			/* just fix normal inconsistencies */
96 char	rplyflag;		/* any questions asked? */
97 char	hotroot;		/* checking root device */
98 char	fixcg;			/* corrupted free list bit maps */
99 
100 char	*blockmap;		/* ptr to primary blk allocation map */
101 char	*freemap;		/* ptr to secondary blk allocation map */
102 char	*statemap;		/* ptr to inode state table */
103 short	*lncntp;		/* ptr to link count table */
104 
105 char	*pathp;			/* pointer to pathname position */
106 char	*thisname;		/* ptr to current pathname component */
107 char	*srchname;		/* name being searched for in dir */
108 char	pathname[BUFSIZ];
109 char	*endpathname = &pathname[BUFSIZ - 2];
110 
111 char	*lfname = "lost+found";
112 
113 ino_t	inum;			/* inode we are currently working on */
114 ino_t	dnum;			/* directory inode currently being worked on */
115 ino_t	imax;			/* number of inodes */
116 ino_t	parentdir;		/* i number of parent directory */
117 ino_t	lastino;		/* hiwater mark of inodes */
118 ino_t	lfdir;			/* lost & found directory */
119 ino_t	orphan;			/* orphaned inode */
120 
121 off_t	filsize;		/* num blks seen in file */
122 off_t	maxblk;			/* largest logical blk in file */
123 off_t	bmapsz;			/* num chars in blockmap */
124 
125 daddr_t	n_ffree;		/* number of small free blocks */
126 daddr_t	n_bfree;		/* number of large free blocks */
127 daddr_t	n_blks;			/* number of blocks used */
128 daddr_t	n_files;		/* number of files seen */
129 daddr_t	n_index;
130 daddr_t	n_bad;
131 daddr_t	fmax;			/* number of blocks in the volume */
132 
133 daddr_t	badblk;
134 daddr_t	dupblk;
135 
136 int	inosumbad;
137 int	offsumbad;
138 int	frsumbad;
139 int	sbsumbad;
140 
141 #define	zapino(x)	(*(x) = zino)
142 struct	dinode zino;
143 
144 #define	setbmap(x)	setbit(blockmap, x)
145 #define	getbmap(x)	isset(blockmap, x)
146 #define	clrbmap(x)	clrbit(blockmap, x)
147 
148 #define	setfmap(x)	setbit(freemap, x)
149 #define	getfmap(x)	isset(freemap, x)
150 #define	clrfmap(x)	clrbit(freemap, x)
151 
152 #define	DATA	1
153 #define	ADDR	0
154 
155 #define	ALTERD	010
156 #define	KEEPON	04
157 #define	SKIP	02
158 #define	STOP	01
159 
160 int	(*signal())();
161 long	lseek();
162 time_t	time();
163 DINODE	*ginode();
164 BUFAREA	*getblk();
165 int	dirscan();
166 int	findino();
167 int	catch();
168 int	mkentry();
169 int	chgdd();
170 int	pass1check(), pass1bcheck(), pass2check(), pass4check(), pass5check();
171 int	(*pfunc)();
172 char	*rawname(), *rindex(), *unrawname();
173 extern int inside[], around[];
174 extern unsigned char *fragtbl[];
175 
176 char	*devname;
177 
178 main(argc, argv)
179 	int	argc;
180 	char	*argv[];
181 {
182 	struct fstab *fsp;
183 	int pid, passno, anygtr, sumstatus;
184 
185 	sync();
186 	while (--argc > 0 && **++argv == '-') {
187 		switch (*++*argv) {
188 
189 		case 'p':
190 			preen++;
191 			break;
192 
193 		case 'b':
194 			bflag = atoi(argv[0]+1);
195 			printf("Alternate super block location: %d\n", bflag);
196 			break;
197 
198 		case 'd':
199 			debug++;
200 			break;
201 
202 		case 'n':	/* default no answer flag */
203 		case 'N':
204 			nflag++;
205 			yflag = 0;
206 			break;
207 
208 		case 'y':	/* default yes answer flag */
209 		case 'Y':
210 			yflag++;
211 			nflag = 0;
212 			break;
213 
214 		default:
215 			errexit("%c option?\n", **argv);
216 		}
217 	}
218 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
219 		signal(SIGINT, catch);
220 	if (argc) {
221 		while (argc-- > 0) {
222 			hotroot = 0;
223 			checkfilesys(*argv++);
224 		}
225 		exit(0);
226 	}
227 	sumstatus = 0;
228 	passno = 1;
229 	do {
230 		anygtr = 0;
231 		if (setfsent() == 0)
232 			errexit("Can't open checklist file: %s\n", FSTAB);
233 		while ((fsp = getfsent()) != 0) {
234 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
235 			    strcmp(fsp->fs_type, FSTAB_RO))
236 				continue;
237 			if (preen == 0 ||
238 			    passno == 1 && fsp->fs_passno == passno) {
239 				if (blockcheck(fsp->fs_spec) == 0 && preen)
240 					exit(8);
241 			} else if (fsp->fs_passno > passno)
242 				anygtr = 1;
243 			else if (fsp->fs_passno == passno) {
244 				pid = fork();
245 				if (pid < 0) {
246 					perror("fork");
247 					exit(8);
248 				}
249 				if (pid == 0)
250 					if (blockcheck(fsp->fs_spec)==0)
251 						exit(8);
252 					else
253 						exit(0);
254 			}
255 		}
256 		if (preen) {
257 			int status;
258 			while (wait(&status) != -1)
259 				sumstatus |= status;
260 		}
261 		passno++;
262 	} while (anygtr);
263 	if (sumstatus)
264 		exit(8);
265 	endfsent();
266 	exit(0);
267 }
268 
269 blockcheck(name)
270 	char *name;
271 {
272 	struct stat stslash, stblock, stchar;
273 	char *raw;
274 	int looped = 0;
275 
276 	hotroot = 0;
277 	if (stat("/", &stslash) < 0){
278 		error("Can't stat root\n");
279 		return (0);
280 	}
281 retry:
282 	if (stat(name, &stblock) < 0){
283 		error("Can't stat %s\n", name);
284 		return (0);
285 	}
286 	if (stblock.st_mode & S_IFBLK) {
287 		raw = rawname(name);
288 		if (stat(raw, &stchar) < 0){
289 			error("Can't stat %s\n", raw);
290 			return (0);
291 		}
292 		if (stchar.st_mode & S_IFCHR) {
293 			if (stslash.st_dev == stblock.st_rdev) {
294 				hotroot++;
295 				raw = rawname(name);
296 			}
297 			checkfilesys(raw);
298 			return (1);
299 		} else {
300 			error("%s is not a character device\n", raw);
301 			return (0);
302 		}
303 	} else if (stblock.st_mode & S_IFCHR) {
304 		if (looped) {
305 			error("Can't make sense out of name %s\n", name);
306 			return (0);
307 		}
308 		name = unrawname(name);
309 		looped++;
310 		goto retry;
311 	}
312 	error("Can't make sense out of name %s\n", name);
313 	return (0);
314 }
315 
316 checkfilesys(filesys)
317 	char *filesys;
318 {
319 	register DINODE *dp;
320 	register ino_t *blp;
321 	register int i, n;
322 	ino_t savino;
323 	int b, c, j, partial, ndb;
324 	daddr_t d, s;
325 
326 	devname = filesys;
327 	if (setup(filesys) == 0) {
328 		if (preen)
329 			pfatal("CAN'T CHECK FILE SYSTEM.");
330 		return;
331 	}
332 /* 1: scan inodes tallying blocks used */
333 	if (preen == 0) {
334 		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
335 		if (hotroot)
336 			printf("** Root file system\n");
337 		printf("** Phase 1 - Check Blocks and Sizes\n");
338 	}
339 	pass1();
340 
341 /* 1b: locate first references to duplicates, if any */
342 	if (enddup != &duplist[0]) {
343 		if (preen)
344 			pfatal("INTERNAL ERROR: dups with -p");
345 		printf("** Phase 1b - Rescan For More DUPS\n");
346 		pass1b();
347 	}
348 
349 /* 2: traverse directories to check reference counts */
350 	if (preen == 0)
351 		printf("** Phase 2 - Check Pathnames\n");
352 	pass2();
353 
354 /* 3 */
355 	if (preen == 0)
356 		printf("** Phase 3 - Check Connectivity\n");
357 	pass3();
358 
359 /* 4 */
360 	if (preen == 0)
361 		printf("** Phase 4 - Check Reference Counts\n");
362 	pass4();
363 
364 /* 5 */
365 	if (preen == 0)
366 		printf("** Phase 5 - Check Cyl groups\n");
367 	pass5();
368 
369 	if (fixcg) {
370 		if (preen == 0)
371 			printf("** Phase 6 - Salvage Cylinder Groups\n");
372 		makecg();
373 		n_ffree = sblock.fs_cstotal.cs_nffree;
374 		n_bfree = sblock.fs_cstotal.cs_nbfree;
375 	}
376 
377 	pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
378 	    n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
379 	    n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
380 	if (dfile.mod) {
381 		time(&sblock.fs_time);
382 		sbdirty();
383 	}
384 	ckfini();
385 	free(blockmap);
386 	free(freemap);
387 	free(statemap);
388 	free(lncntp);
389 	if (dfile.mod) {
390 		if (preen) {
391 			if (hotroot)
392 				exit(4);
393 		} else {
394 			printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
395 			if (hotroot) {
396 				printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
397 				exit(4);
398 			}
399 		}
400 	}
401 	sync();			/* ??? */
402 }
403 
404 setup(dev)
405 	char *dev;
406 {
407 	dev_t rootdev;
408 	struct stat statb;
409 	int super = bflag ? bflag : SBLOCK;
410 	int i, j, size;
411 	int c, d, cgd;
412 
413 	bflag = 0;
414 	if (stat("/", &statb) < 0)
415 		errexit("Can't stat root\n");
416 	rootdev = statb.st_dev;
417 	if (stat(dev, &statb) < 0) {
418 		error("Can't stat %s\n", dev);
419 		return (0);
420 	}
421 	rawflg = 0;
422 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
423 		;
424 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
425 		rawflg++;
426 	else {
427 		if (reply("file is not a block or character device; OK") == 0)
428 			return (0);
429 	}
430 	if (rootdev == statb.st_rdev)
431 		hotroot++;
432 	if ((dfile.rfdes = open(dev, 0)) < 0) {
433 		error("Can't open %s\n", dev);
434 		return (0);
435 	}
436 	if (preen == 0)
437 		printf("** %s", dev);
438 	if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
439 		dfile.wfdes = -1;
440 		if (preen)
441 			pfatal("NO WRITE ACCESS");
442 		printf(" (NO WRITE)");
443 	}
444 	if (preen == 0)
445 		printf("\n");
446 	fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
447 	dfile.mod = 0;
448 	n_files = n_blks = n_ffree = n_bfree = 0;
449 	muldup = enddup = &duplist[0];
450 	badlnp = &badlncnt[0];
451 	lfdir = 0;
452 	rplyflag = 0;
453 	initbarea(&sblk);
454 	initbarea(&fileblk);
455 	initbarea(&inoblk);
456 	initbarea(&cgblk);
457 	/*
458 	 * Read in the super block and its summary info.
459 	 */
460 	if (bread(&dfile, &sblock, super, SBSIZE) == 0)
461 		return (0);
462 	sblk.b_bno = super;
463 	sblk.b_size = SBSIZE;
464 	/*
465 	 * run a few consistency checks of the super block
466 	 */
467 	if (sblock.fs_magic != FS_MAGIC)
468 		{ badsb("MAGIC NUMBER WRONG"); return (0); }
469 	if (sblock.fs_ncg < 1)
470 		{ badsb("NCG OUT OF RANGE"); return (0); }
471 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
472 		{ badsb("CPG OUT OF RANGE"); return (0); }
473 	if (sblock.fs_nsect < 1)
474 		{ badsb("NSECT < 1"); return (0); }
475 	if (sblock.fs_ntrak < 1)
476 		{ badsb("NTRAK < 1"); return (0); }
477 	if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
478 		{ badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
479 	if (sblock.fs_ipg % INOPB(&sblock))
480 		{ badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
481 	if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
482 		{ badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
483 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
484 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
485 		{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
486 	if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
487 		{ badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
488 	if (sblock.fs_size * NSPF(&sblock) <=
489 	    (sblock.fs_ncyl - 1) * sblock.fs_spc)
490 		{ badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
491 	if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
492 		{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
493 	/* rest we COULD repair... */
494 	if (sblock.fs_cgsize != fragroundup(&sblock,
495 	    sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
496 		{ badsb("CGSIZE INCORRECT"); return (0); }
497 	if (sblock.fs_cssize !=
498 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)))
499 		{ badsb("CSSIZE INCORRECT"); return (0); }
500 	fmax = sblock.fs_size;
501 	imax = sblock.fs_ncg * sblock.fs_ipg;
502 	n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
503 	/*
504 	 * read in the summary info.
505 	 */
506 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
507 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
508 		    sblock.fs_cssize - i : sblock.fs_bsize;
509 		sblock.fs_csp[j] = (struct csum *)calloc(1, size);
510 		bread(&dfile, (char *)sblock.fs_csp[j],
511 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
512 		    size);
513 	}
514 	/*
515 	 * allocate and initialize the necessary maps
516 	 */
517 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
518 	blockmap = (char *)calloc(bmapsz, sizeof (char));
519 	if (blockmap == NULL) {
520 		printf("cannot alloc %d bytes for blockmap\n", bmapsz);
521 		exit(1);
522 	}
523 	freemap = (char *)calloc(bmapsz, sizeof (char));
524 	if (freemap == NULL) {
525 		printf("cannot alloc %d bytes for freemap\n", bmapsz);
526 		exit(1);
527 	}
528 	statemap = (char *)calloc(imax+1, sizeof(char));
529 	if (statemap == NULL) {
530 		printf("cannot alloc %d bytes for statemap\n", imax + 1);
531 		exit(1);
532 	}
533 	lncntp = (short *)calloc(imax+1, sizeof(short));
534 	if (lncntp == NULL) {
535 		printf("cannot alloc %d bytes for lncntp\n",
536 		    (imax + 1) * sizeof(short));
537 		exit(1);
538 	}
539 	for (c = 0; c < sblock.fs_ncg; c++) {
540 		cgd = cgdmin(&sblock, c);
541 		if (c == 0) {
542 			d = cgbase(&sblock, c);
543 			cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
544 		} else
545 			d = cgsblock(&sblock, c);
546 		for (; d < cgd; d++)
547 			setbmap(d);
548 	}
549 
550 	startinum = imax + 1;
551 	return (1);
552 
553 badsb:
554 	ckfini();
555 	return (0);
556 }
557 
558 pass1()
559 {
560 	register int c, i, n, j;
561 	register DINODE *dp;
562 	int savino, ndb, partial;
563 
564 	pfunc = pass1check;
565 	inum = 0;
566 	n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
567 	for (c = 0; c < sblock.fs_ncg; c++) {
568 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
569 			continue;
570 		if (cgrp.cg_magic != CG_MAGIC) {
571 			pfatal("cg %d: bad magic number\n", c);
572 			bzero((caddr_t)&cgrp, sblock.fs_cgsize);
573 		}
574 		n = 0;
575 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
576 			dp = ginode();
577 			if (dp == NULL)
578 				continue;
579 			n++;
580 			if (ALLOC) {
581 				if (!isset(cgrp.cg_iused, i)) {
582 					if (debug)
583 						printf("%d bad, not used\n",
584 						    inum);
585 					inosumbad++;
586 				}
587 				n--;
588 				lastino = inum;
589 				if (!preen && BADBLK &&
590 				    reply("HOLD BAD BLOCK") == 1) {
591 					dp->di_size = sblock.fs_fsize;
592 					dp->di_mode = IFREG|0600;
593 					inodirty();
594 				} else if (ftypeok(dp) == 0)
595 					goto unknown;
596 				if (dp->di_size < 0) {
597 					if (debug)
598 						printf("bad size %d:",
599 							dp->di_size);
600 					goto unknown;
601 				}
602 				ndb = howmany(dp->di_size, sblock.fs_bsize);
603 				if (SPECIAL)
604 					ndb++;
605 				for (j = ndb; j < NDADDR; j++)
606 					if (dp->di_db[j] != 0) {
607 						if (debug)
608 							printf("bad direct addr: %d\n",
609 								dp->di_db[j]);
610 						goto unknown;
611 					}
612 				for (j = 0, ndb -= NDADDR; ndb > 0; j++)
613 					ndb /= NINDIR(&sblock);
614 				for (; j < NIADDR; j++)
615 					if (dp->di_ib[j] != 0) {
616 						if (debug)
617 							printf("bad indirect addr: %d\n",
618 								dp->di_ib[j]);
619 						goto unknown;
620 					}
621 				n_files++;
622 				lncntp[inum] = dp->di_nlink;
623 				if (dp->di_nlink <= 0) {
624 					if (badlnp < &badlncnt[MAXLNCNT])
625 						*badlnp++ = inum;
626 					else {
627 						pfatal("LINK COUNT TABLE OVERFLOW");
628 						if (reply("CONTINUE") == 0)
629 							errexit("");
630 					}
631 				}
632 				statemap[inum] = DIRCT ? DSTATE : FSTATE;
633 				badblk = dupblk = 0; filsize = 0; maxblk = 0;
634 				ckinode(dp, ADDR);
635 				filsize *= btodb(sblock.fs_fsize);
636 				if (dp->di_blocks != filsize) {
637 					pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
638 					    inum, dp->di_blocks, filsize);
639 					if (preen)
640 						printf(" (CORRECTED)\n");
641 					else if (reply("CORRECT") == 0)
642 						continue;
643 					dp->di_blocks = filsize;
644 					inodirty();
645 				}
646 				continue;
647 		unknown:
648 				if (!SOCK)
649 					pfatal("UNKNOWN FILE TYPE I=%u", inum);
650 				if ((preen && SOCK) || reply("CLEAR") == 1) {
651 					zapino(dp);
652 					inodirty();
653 					inosumbad++;
654 				}
655 			} else {
656 				if (isset(cgrp.cg_iused, i)) {
657 					if (debug)
658 						printf("%d bad, marked used\n",
659 						    inum);
660 					inosumbad++;
661 					n--;
662 				}
663 				partial = 0;
664 				for (j = 0; j < NDADDR; j++)
665 					if (dp->di_db[j] != 0)
666 						partial++;
667 				for (j = 0; j < NIADDR; j++)
668 					if (dp->di_ib[j] != 0)
669 						partial++;
670 				if (partial || dp->di_mode != 0 ||
671 				    dp->di_size != 0) {
672 					pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
673 					if (reply("CLEAR") == 1) {
674 						zapino(dp);
675 						inodirty();
676 						inosumbad++;
677 					}
678 				}
679 			}
680 		}
681 		if (n != cgrp.cg_cs.cs_nifree) {
682 			if (debug)
683 				printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
684 				    c, cgrp.cg_cs.cs_nifree, n);
685 			inosumbad++;
686 		}
687 		if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
688 		  || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
689 		  || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
690 		  || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
691 			sbsumbad++;
692 	}
693 }
694 
695 pass1check(blk, size)
696 	daddr_t blk;
697 	int size;
698 {
699 	register daddr_t *dlp;
700 	int res = KEEPON;
701 	int anyout;
702 
703 	anyout = outrange(blk, size);
704 	for (; size > 0; blk++, size--) {
705 		if (anyout && outrange(blk, 1)) {
706 			blkerr("BAD", blk);
707 			if (++badblk >= MAXBAD) {
708 				pwarn("EXCESSIVE BAD BLKS I=%u", inum);
709 				if (preen)
710 					printf(" (SKIPPING)\n");
711 				else if (reply("CONTINUE") == 0)
712 					errexit("");
713 				return (STOP);
714 			}
715 			res = SKIP;
716 		} else if (getbmap(blk)) {
717 			blkerr("DUP", blk);
718 			if (++dupblk >= MAXDUP) {
719 				pwarn("EXCESSIVE DUP BLKS I=%u", inum);
720 				if (preen)
721 					printf(" (SKIPPING)\n");
722 				else if (reply("CONTINUE") == 0)
723 					errexit("");
724 				return (STOP);
725 			}
726 			if (enddup >= &duplist[DUPTBLSIZE]) {
727 				pfatal("DUP TABLE OVERFLOW.");
728 				if (reply("CONTINUE") == 0)
729 					errexit("");
730 				return (STOP);
731 			}
732 			for (dlp = duplist; dlp < muldup; dlp++)
733 				if (*dlp == blk) {
734 					*enddup++ = blk;
735 					break;
736 				}
737 			if (dlp >= muldup) {
738 				*enddup++ = *muldup;
739 				*muldup++ = blk;
740 			}
741 		} else {
742 			n_blks++;
743 			setbmap(blk);
744 		}
745 		filsize++;
746 	}
747 	return (res);
748 }
749 
750 pass1b()
751 {
752 	register int c, i;
753 	register DINODE *dp;
754 
755 	pfunc = pass1bcheck;
756 	inum = 0;
757 	for (c = 0; c < sblock.fs_ncg; c++) {
758 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
759 			dp = ginode();
760 			if (dp == NULL)
761 				continue;
762 			if (statemap[inum] != USTATE &&
763 			    (ckinode(dp, ADDR) & STOP))
764 				goto out1b;
765 		}
766 	}
767 out1b:
768 	flush(&dfile, &inoblk);
769 }
770 
771 pass1bcheck(blk, size)
772 	daddr_t blk;
773 	int size;
774 {
775 	register daddr_t *dlp;
776 	int res = KEEPON;
777 
778 	for (; size > 0; blk++, size--) {
779 		if (outrange(blk, 1))
780 			res = SKIP;
781 		for (dlp = duplist; dlp < muldup; dlp++)
782 			if (*dlp == blk) {
783 				blkerr("DUP", blk);
784 				*dlp = *--muldup;
785 				*muldup = blk;
786 				if (muldup == duplist)
787 					return (STOP);
788 			}
789 	}
790 	return (res);
791 }
792 
793 pass2()
794 {
795 	register DINODE *dp;
796 
797 	inum = ROOTINO;
798 	thisname = pathp = pathname;
799 	pfunc = pass2check;
800 	switch (statemap[inum]) {
801 
802 	case USTATE:
803 		errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
804 
805 	case FSTATE:
806 		pfatal("ROOT INODE NOT DIRECTORY");
807 		if (reply("FIX") == 0 || (dp = ginode()) == NULL)
808 			errexit("");
809 		dp->di_mode &= ~IFMT;
810 		dp->di_mode |= IFDIR;
811 		inodirty();
812 		inosumbad++;
813 		statemap[inum] = DSTATE;
814 		/* fall into ... */
815 
816 	case DSTATE:
817 		descend();
818 		break;
819 
820 	case CLEAR:
821 		pfatal("DUPS/BAD IN ROOT INODE");
822 		printf("\n");
823 		if (reply("CONTINUE") == 0)
824 			errexit("");
825 		statemap[inum] = DSTATE;
826 		descend();
827 	}
828 }
829 
830 pass2check(dirp)
831 	register DIRECT *dirp;
832 {
833 	register char *p;
834 	register n;
835 	DINODE *dp;
836 
837 	if ((inum = dirp->d_ino) == 0)
838 		return (KEEPON);
839 	thisname = pathp;
840 	if (pathp + dirp->d_namlen >= endpathname) {
841 		*pathp = '\0';
842 		errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
843 	}
844 	for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
845 		if ((*pathp++ = *p++) == 0) {
846 			--pathp;
847 			break;
848 		}
849 	*pathp = 0;
850 	n = 0;
851 	if (inum > imax || inum <= 0)
852 		n = direrr("I OUT OF RANGE");
853 	else {
854 again:
855 		switch (statemap[inum]) {
856 		case USTATE:
857 			n = direrr("UNALLOCATED");
858 			break;
859 
860 		case CLEAR:
861 			if ((n = direrr("DUP/BAD")) == 1)
862 				break;
863 			if ((dp = ginode()) == NULL)
864 				break;
865 			statemap[inum] = DIRCT ? DSTATE : FSTATE;
866 			goto again;
867 
868 		case FSTATE:
869 			lncntp[inum]--;
870 			break;
871 
872 		case DSTATE:
873 			lncntp[inum]--;
874 			descend();
875 			break;
876 		}
877 	}
878 	pathp = thisname;
879 	if (n == 0)
880 		return (KEEPON);
881 	dirp->d_ino = 0;
882 	return (KEEPON|ALTERD);
883 }
884 
885 pass3()
886 {
887 	ino_t savino;
888 	register DINODE *dp;
889 
890 	for (inum = ROOTINO; inum <= lastino; inum++) {
891 		if (statemap[inum] == DSTATE) {
892 			pfunc = findino;
893 			srchname = "..";
894 			savino = inum;
895 			do {
896 				orphan = inum;
897 				if ((dp = ginode()) == NULL)
898 					break;
899 				filsize = dp->di_size;
900 				parentdir = 0;
901 				ckinode(dp, DATA);
902 				if ((inum = parentdir) == 0)
903 					break;
904 			} while (statemap[inum] == DSTATE);
905 			inum = orphan;
906 			if (linkup() == 1) {
907 				thisname = pathp = pathname;
908 				*pathp++ = '?';
909 				pfunc = pass2check;
910 				descend();
911 			}
912 			inum = savino;
913 		}
914 	}
915 }
916 
917 pass4()
918 {
919 	register int n;
920 	register ino_t *blp;
921 
922 	pfunc = pass4check;
923 	for (inum = ROOTINO; inum <= lastino; inum++) {
924 		switch (statemap[inum]) {
925 
926 		case FSTATE:
927 			n = lncntp[inum];
928 			if (n)
929 				adjust((short)n);
930 			else {
931 				for (blp = badlncnt;blp < badlnp; blp++)
932 					if (*blp == inum) {
933 						clri("UNREF", 1);
934 						break;
935 					}
936 			}
937 			break;
938 
939 		case DSTATE:
940 			clri("UNREF", 1);
941 			break;
942 
943 		case CLEAR:
944 			clri("BAD/DUP", 1);
945 			break;
946 		}
947 	}
948 	if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
949 		pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
950 		if (preen)
951 			printf(" (FIXED)\n");
952 		if (preen || reply("FIX") == 1) {
953 			sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
954 			sbdirty();
955 		}
956 	}
957 	flush(&dfile, &fileblk);
958 }
959 
960 pass4check(blk, size)
961 	daddr_t blk;
962 {
963 	register daddr_t *dlp;
964 	int res = KEEPON;
965 
966 	for (; size > 0; blk++, size--) {
967 		if (outrange(blk, 1))
968 			res = SKIP;
969 		else if (getbmap(blk)) {
970 			for (dlp = duplist; dlp < enddup; dlp++)
971 				if (*dlp == blk) {
972 					*dlp = *--enddup;
973 					return (KEEPON);
974 				}
975 			clrbmap(blk);
976 			n_blks--;
977 		}
978 	}
979 	return (res);
980 }
981 
982 pass5()
983 {
984 	register int c, n, i, b, d;
985 	short bo[MAXCPG][NRPOS];
986 	long botot[MAXCPG];
987 	long frsum[MAXFRAG];
988 	int blk;
989 	daddr_t cbase;
990 	int blockbits = (1<<sblock.fs_frag)-1;
991 
992 	bcopy(blockmap, freemap, (unsigned)bmapsz);
993 	dupblk = 0;
994 	n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
995 	for (c = 0; c < sblock.fs_ncg; c++) {
996 		cbase = cgbase(&sblock, c);
997 		bzero(botot, sizeof (botot));
998 		bzero(bo, sizeof (bo));
999 		bzero(frsum, sizeof (frsum));
1000 		/*
1001 		 * need to account for the super blocks
1002 		 * which appear (inaccurately) bad
1003 		 */
1004 		n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c);
1005 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
1006 			continue;
1007 		if (cgrp.cg_magic != CG_MAGIC) {
1008 			pfatal("cg %d: bad magic number\n", c);
1009 			bzero((caddr_t)&cgrp, sblock.fs_cgsize);
1010 		}
1011 		for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
1012 			blk = blkmap(&sblock, cgrp.cg_free, b);
1013 			if (blk == 0)
1014 				continue;
1015 			if (blk == blockbits) {
1016 				if (pass5check(cbase+b, sblock.fs_frag) == STOP)
1017 					goto out5;
1018 				/* this is clumsy ... */
1019 				n_ffree -= sblock.fs_frag;
1020 				n_bfree++;
1021 				botot[cbtocylno(&sblock, b)]++;
1022 				bo[cbtocylno(&sblock, b)]
1023 				    [cbtorpos(&sblock, b)]++;
1024 				continue;
1025 			}
1026 			for (d = 0; d < sblock.fs_frag; d++)
1027 				if ((blk & (1<<d)) &&
1028 				    pass5check(cbase+b+d,1) == STOP)
1029 					goto out5;
1030 			fragacct(&sblock, blk, frsum, 1);
1031 		}
1032 		if (bcmp(cgrp.cg_frsum, frsum, sizeof (frsum))) {
1033 			if (debug)
1034 			for (i = 0; i < sblock.fs_frag; i++)
1035 				if (cgrp.cg_frsum[i] != frsum[i])
1036 				printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
1037 				    c, i, cgrp.cg_frsum[i], frsum[i]);
1038 			frsumbad++;
1039 		}
1040 		if (bcmp(cgrp.cg_btot, botot, sizeof (botot))) {
1041 			if (debug)
1042 			for (n = 0; n < sblock.fs_cpg; n++)
1043 				if (botot[n] != cgrp.cg_btot[n])
1044 				printf("cg[%d].cg_btot[%d] have %d calc %d\n",
1045 				    c, n, cgrp.cg_btot[n], botot[n]);
1046 			offsumbad++;
1047 		}
1048 		if (bcmp(cgrp.cg_b, bo, sizeof (bo))) {
1049 			if (debug)
1050 			for (i = 0; i < NRPOS; i++)
1051 				if (bo[n][i] != cgrp.cg_b[n][i])
1052 				printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
1053 				    c, n, i, cgrp.cg_b[n][i], bo[n][i]);
1054 			offsumbad++;
1055 		}
1056 	}
1057 out5:
1058 	if (dupblk)
1059 		pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
1060 	if (fixcg == 0) {
1061 		if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
1062 			pwarn("%ld BLK(S) MISSING\n", fmax - b);
1063 			fixcg = 1;
1064 		} else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
1065 			pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
1066 			    inosumbad ? "(INODE FREE) " : "",
1067 			    offsumbad ? "(BLOCK OFFSETS) " : "",
1068 			    frsumbad ? "(FRAG SUMMARIES) " : "",
1069 			    sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
1070 			fixcg = 1;
1071 		} else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
1072 		    n_bfree != sblock.fs_cstotal.cs_nbfree) {
1073 			pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
1074 			if (preen)
1075 				printf(" (FIXED)\n");
1076 			if (preen || reply("FIX") == 1) {
1077 				sblock.fs_cstotal.cs_nffree = n_ffree;
1078 				sblock.fs_cstotal.cs_nbfree = n_bfree;
1079 				sbdirty();
1080 			}
1081 		}
1082 	}
1083 	if (fixcg) {
1084 		pwarn("BAD CYLINDER GROUPS");
1085 		if (preen)
1086 			printf(" (SALVAGED)\n");
1087 		else if (reply("SALVAGE") == 0)
1088 			fixcg = 0;
1089 	}
1090 }
1091 
1092 pass5check(blk, size)
1093 	daddr_t blk;
1094 	int size;
1095 {
1096 
1097 	if (outrange(blk, size)) {
1098 		fixcg = 1;
1099 		if (preen)
1100 			pfatal("BAD BLOCKS IN BIT MAPS.");
1101 		if (++badblk >= MAXBAD) {
1102 			printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
1103 			if (reply("CONTINUE") == 0)
1104 				errexit("");
1105 			return (STOP);
1106 		}
1107 	}
1108 	for (; size > 0; blk++, size--)
1109 		if (getfmap(blk)) {
1110 			fixcg = 1;
1111 			++dupblk;
1112 		} else {
1113 			n_ffree++;
1114 			setfmap(blk);
1115 		}
1116 	return (KEEPON);
1117 }
1118 
1119 ckinode(dp, flg)
1120 	DINODE *dp;
1121 	register flg;
1122 {
1123 	register daddr_t *ap;
1124 	register ret;
1125 	int (*func)(), n, ndb, size, offset;
1126 	ino_t number = inum;
1127 	DINODE dino;
1128 
1129 	if (SPECIAL)
1130 		return (KEEPON);
1131 	dino = *dp;
1132 	func = (flg == ADDR) ? pfunc : dirscan;
1133 	ndb = howmany(dino.di_size, sblock.fs_bsize);
1134 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
1135 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
1136 			size = numfrags(&sblock, fragroundup(&sblock, offset));
1137 		else
1138 			size = sblock.fs_frag;
1139 		dnum = number;
1140 		if (*ap && (ret = (*func)(*ap, size)) & STOP)
1141 			return (ret);
1142 	}
1143 	for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
1144 		dnum = number;
1145 		if (*ap) {
1146 			ret = iblock(*ap, n, flg,
1147 			    dino.di_size - sblock.fs_bsize * NDADDR);
1148 			if (ret & STOP)
1149 				return (ret);
1150 		}
1151 	}
1152 	return (KEEPON);
1153 }
1154 
1155 iblock(blk, ilevel, flg, isize)
1156 	daddr_t blk;
1157 	register ilevel;
1158 	int isize;
1159 {
1160 	register daddr_t *ap;
1161 	register daddr_t *aplim;
1162 	register int i, n;
1163 	int (*func)(), nif;
1164 	BUFAREA ib;
1165 
1166 	if (flg == ADDR) {
1167 		func = pfunc;
1168 		if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
1169 			return (n);
1170 	} else
1171 		func = dirscan;
1172 	if (outrange(blk, sblock.fs_frag))		/* protect thyself */
1173 		return (SKIP);
1174 	initbarea(&ib);
1175 	if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
1176 		return (SKIP);
1177 	ilevel--;
1178 	if (ilevel == 0) {
1179 		nif = lblkno(&sblock, isize) + 1;
1180 	} else /* ilevel == 1 */ {
1181 		nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
1182 	}
1183 	if (nif > NINDIR(&sblock))
1184 		nif = NINDIR(&sblock);
1185 	aplim = &ib.b_un.b_indir[nif];
1186 	for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
1187 		if (*ap) {
1188 			if (ilevel > 0)
1189 				n = iblock(*ap, ilevel, flg,
1190 				    isize - i*NINDIR(&sblock)*sblock.fs_bsize);
1191 			else
1192 				n = (*func)(*ap, sblock.fs_frag);
1193 			if (n & STOP)
1194 				return (n);
1195 		}
1196 	return (KEEPON);
1197 }
1198 
1199 outrange(blk, cnt)
1200 	daddr_t blk;
1201 	int cnt;
1202 {
1203 	register int c;
1204 
1205 	if ((unsigned)(blk+cnt) > fmax)
1206 		return (1);
1207 	c = dtog(&sblock, blk);
1208 	if (blk < cgdmin(&sblock, c)) {
1209 		if ((blk+cnt) > cgsblock(&sblock, c)) {
1210 			if (debug) {
1211 				printf("blk %d < cgdmin %d;",
1212 				    blk, cgdmin(&sblock, c));
1213 				printf(" blk+cnt %d > cgsbase %d\n",
1214 				    blk+cnt, cgsblock(&sblock, c));
1215 			}
1216 			return (1);
1217 		}
1218 	} else {
1219 		if ((blk+cnt) > cgbase(&sblock, c+1)) {
1220 			if (debug)  {
1221 				printf("blk %d >= cgdmin %d;",
1222 				    blk, cgdmin(&sblock, c));
1223 				printf(" blk+cnt %d > sblock.fs_fpg %d\n",
1224 				    blk+cnt, sblock.fs_fpg);
1225 			}
1226 			return (1);
1227 		}
1228 	}
1229 	return (0);
1230 }
1231 
1232 blkerr(s, blk)
1233 	daddr_t blk;
1234 	char *s;
1235 {
1236 
1237 	pfatal("%ld %s I=%u", blk, s, inum);
1238 	printf("\n");
1239 	statemap[inum] = CLEAR;
1240 }
1241 
1242 descend()
1243 {
1244 	register DINODE *dp;
1245 	register char *savname;
1246 	off_t savsize;
1247 
1248 	statemap[inum] = FSTATE;
1249 	if ((dp = ginode()) == NULL)
1250 		return;
1251 	savname = thisname;
1252 	*pathp++ = '/';
1253 	savsize = filsize;
1254 	filsize = dp->di_size;
1255 	ckinode(dp, DATA);
1256 	thisname = savname;
1257 	*--pathp = 0;
1258 	filsize = savsize;
1259 }
1260 
1261 struct dirstuff {
1262 	int loc;
1263 	int blkno;
1264 	int blksiz;
1265 	ino_t number;
1266 	enum {DONTKNOW, NOFIX, FIX} fix;
1267 };
1268 
1269 dirscan(blk, nf)
1270 	daddr_t blk;
1271 	int nf;
1272 {
1273 	register DIRECT *dp;
1274 	struct dirstuff dirp;
1275 	int blksiz, dsize, n;
1276 	char dbuf[DIRBLKSIZ];
1277 
1278 	if (outrange(blk, 1)) {
1279 		filsize -= sblock.fs_bsize;
1280 		return (SKIP);
1281 	}
1282 	blksiz = nf * sblock.fs_fsize;
1283 	dirp.loc = 0;
1284 	dirp.blkno = blk;
1285 	dirp.blksiz = blksiz;
1286 	if (dirp.number != dnum) {
1287 		dirp.number = dnum;
1288 		dirp.fix = DONTKNOW;
1289 	}
1290 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
1291 		dsize = dp->d_reclen;
1292 		bcopy(dp, dbuf, dsize);
1293 		if ((n = (*pfunc)(dbuf)) & ALTERD) {
1294 			if (getblk(&fileblk, blk, blksiz) != NULL) {
1295 				bcopy(dbuf, dp, dsize);
1296 				dirty(&fileblk);
1297 				sbdirty();
1298 			} else
1299 				n &= ~ALTERD;
1300 		}
1301 		if (n & STOP)
1302 			return (n);
1303 	}
1304 	return (filsize > 0 ? KEEPON : STOP);
1305 }
1306 
1307 /*
1308  * get next entry in a directory.
1309  */
1310 DIRECT *
1311 readdir(dirp)
1312 	register struct dirstuff *dirp;
1313 {
1314 	register DIRECT *dp, *ndp;
1315 	long size;
1316 
1317 	if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
1318 		filsize -= dirp->blksiz - dirp->loc;
1319 		return NULL;
1320 	}
1321 	while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 &&
1322 	    dirp->loc < dirp->blksiz) {
1323 		dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1324 	   	if (dp->d_ino < imax &&
1325 		    dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 &&
1326 		    dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ)
1327 			break;
1328 		dirp->loc += DIRBLKSIZ;
1329 		filsize -= DIRBLKSIZ;
1330 		if (dirp->fix == DONTKNOW) {
1331 			pfatal("DIRECTORY %D CORRUPTED", dirp->number);
1332 			dirp->fix = NOFIX;
1333 			if (reply("SALVAGE") != 0)
1334 				dirp->fix = FIX;
1335 		}
1336 		if (dirp->fix != FIX)
1337 			continue;
1338 		dp->d_reclen = DIRBLKSIZ;
1339 		dp->d_ino = 0;
1340 		dp->d_namlen = 0;
1341 		dirty(&fileblk);
1342 	}
1343 	if (filsize <= 0 || dirp->loc >= dirp->blksiz)
1344 		return NULL;
1345 	dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1346 	dirp->loc += dp->d_reclen;
1347 	filsize -= dp->d_reclen;
1348 	ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1349 	if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) ||
1350 	    (dirp->loc < dirp->blksiz && filsize > 0 &&
1351 	    (ndp->d_ino >= imax ||
1352 	    ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 ||
1353 	    ndp->d_reclen <= 0 ||
1354 	    ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) {
1355 		size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
1356 		dirp->loc += size;
1357 		filsize -= size;
1358 		if (dirp->fix == DONTKNOW) {
1359 			pfatal("DIRECTORY %D CORRUPTED", dirp->number);
1360 			dirp->fix = NOFIX;
1361 			if (reply("SALVAGE") != 0)
1362 				dirp->fix = FIX;
1363 		}
1364 		if (dirp->fix == FIX) {
1365 			dp->d_reclen += size;
1366 			dirty(&fileblk);
1367 		}
1368 	}
1369 	return (dp);
1370 }
1371 
1372 direrr(s)
1373 	char *s;
1374 {
1375 	register DINODE *dp;
1376 
1377 	pwarn("%s ", s);
1378 	pinode();
1379 	printf("\n");
1380 	if ((dp = ginode()) != NULL && ftypeok(dp))
1381 		pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
1382 	else
1383 		pfatal("NAME=%s", pathname);
1384 	return (reply("REMOVE"));
1385 }
1386 
1387 adjust(lcnt)
1388 	register short lcnt;
1389 {
1390 	register DINODE *dp;
1391 
1392 	if ((dp = ginode()) == NULL)
1393 		return;
1394 	if (dp->di_nlink == lcnt) {
1395 		if (linkup() == 0)
1396 			clri("UNREF", 0);
1397 	}
1398 	else {
1399 		pwarn("LINK COUNT %s",
1400 			(lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
1401 		pinode();
1402 		printf(" COUNT %d SHOULD BE %d",
1403 			dp->di_nlink, dp->di_nlink-lcnt);
1404 		if (preen) {
1405 			if (lcnt < 0) {
1406 				printf("\n");
1407 				preendie();
1408 			}
1409 			printf(" (ADJUSTED)\n");
1410 		}
1411 		if (preen || reply("ADJUST") == 1) {
1412 			dp->di_nlink -= lcnt;
1413 			inodirty();
1414 		}
1415 	}
1416 }
1417 
1418 clri(s, flg)
1419 	char *s;
1420 {
1421 	register DINODE *dp;
1422 
1423 	if ((dp = ginode()) == NULL)
1424 		return;
1425 	if (flg == 1) {
1426 		pwarn("%s %s", s, DIRCT?"DIR":"FILE");
1427 		pinode();
1428 	}
1429 	if (preen || reply("CLEAR") == 1) {
1430 		if (preen)
1431 			printf(" (CLEARED)\n");
1432 		n_files--;
1433 		pfunc = pass4check;
1434 		ckinode(dp, ADDR);
1435 		zapino(dp);
1436 		statemap[inum] = USTATE;
1437 		inodirty();
1438 		inosumbad++;
1439 	}
1440 }
1441 
1442 badsb(s)
1443 	char *s;
1444 {
1445 
1446 	if (preen)
1447 		printf("%s: ", devname);
1448 	printf("BAD SUPER BLOCK: %s\n", s);
1449 	pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
1450 	pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
1451 }
1452 
1453 DINODE *
1454 ginode()
1455 {
1456 	daddr_t iblk;
1457 
1458 	if (inum < ROOTINO || inum > imax) {
1459 		if (debug && (inum < 0 || inum > imax))
1460 			printf("inum out of range (%d)\n", inum);
1461 		return (NULL);
1462 	}
1463 	if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
1464 		iblk = itod(&sblock, inum);
1465 		if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
1466 			return (NULL);
1467 		}
1468 		startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
1469 	}
1470 	return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
1471 }
1472 
1473 ftypeok(dp)
1474 	DINODE *dp;
1475 {
1476 	switch (dp->di_mode & IFMT) {
1477 
1478 	case IFDIR:
1479 	case IFREG:
1480 	case IFBLK:
1481 	case IFCHR:
1482 	case IFLNK:
1483 		return (1);
1484 
1485 	default:
1486 		if (debug)
1487 			printf("bad file type 0%o\n", dp->di_mode);
1488 		return (0);
1489 	}
1490 }
1491 
1492 reply(s)
1493 	char *s;
1494 {
1495 	char line[80];
1496 
1497 	if (preen)
1498 		pfatal("INTERNAL ERROR: GOT TO reply()");
1499 	rplyflag = 1;
1500 	printf("\n%s? ", s);
1501 	if (nflag || dfile.wfdes < 0) {
1502 		printf(" no\n\n");
1503 		return (0);
1504 	}
1505 	if (yflag) {
1506 		printf(" yes\n\n");
1507 		return (1);
1508 	}
1509 	if (getline(stdin, line, sizeof(line)) == EOF)
1510 		errexit("\n");
1511 	printf("\n");
1512 	if (line[0] == 'y' || line[0] == 'Y')
1513 		return (1);
1514 	else
1515 		return (0);
1516 }
1517 
1518 getline(fp, loc, maxlen)
1519 	FILE *fp;
1520 	char *loc;
1521 {
1522 	register n;
1523 	register char *p, *lastloc;
1524 
1525 	p = loc;
1526 	lastloc = &p[maxlen-1];
1527 	while ((n = getc(fp)) != '\n') {
1528 		if (n == EOF)
1529 			return (EOF);
1530 		if (!isspace(n) && p < lastloc)
1531 			*p++ = n;
1532 	}
1533 	*p = 0;
1534 	return (p - loc);
1535 }
1536 
1537 BUFAREA *
1538 getblk(bp, blk, size)
1539 	daddr_t blk;
1540 	register BUFAREA *bp;
1541 	int size;
1542 {
1543 	register struct filecntl *fcp;
1544 	daddr_t dblk;
1545 
1546 	fcp = &dfile;
1547 	dblk = fsbtodb(&sblock, blk);
1548 	if (bp->b_bno == dblk)
1549 		return (bp);
1550 	flush(fcp, bp);
1551 	if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
1552 		bp->b_bno = dblk;
1553 		bp->b_size = size;
1554 		return (bp);
1555 	}
1556 	bp->b_bno = (daddr_t)-1;
1557 	return (NULL);
1558 }
1559 
1560 flush(fcp, bp)
1561 	struct filecntl *fcp;
1562 	register BUFAREA *bp;
1563 {
1564 
1565 	if (bp->b_dirty)
1566 		bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
1567 	bp->b_dirty = 0;
1568 }
1569 
1570 rwerr(s, blk)
1571 	char *s;
1572 	daddr_t blk;
1573 {
1574 
1575 	if (preen == 0)
1576 		printf("\n");
1577 	pfatal("CANNOT %s: BLK %ld", s, blk);
1578 	if (reply("CONTINUE") == 0)
1579 		errexit("Program terminated\n");
1580 }
1581 
1582 ckfini()
1583 {
1584 
1585 	flush(&dfile, &fileblk);
1586 	flush(&dfile, &sblk);
1587 	if (sblk.b_bno != SBLOCK) {
1588 		sblk.b_bno = SBLOCK;
1589 		sbdirty();
1590 		flush(&dfile, &sblk);
1591 	}
1592 	flush(&dfile, &inoblk);
1593 	close(dfile.rfdes);
1594 	close(dfile.wfdes);
1595 }
1596 
1597 pinode()
1598 {
1599 	register DINODE *dp;
1600 	register char *p;
1601 	char uidbuf[BUFSIZ];
1602 	char *ctime();
1603 
1604 	printf(" I=%u ", inum);
1605 	if ((dp = ginode()) == NULL)
1606 		return;
1607 	printf(" OWNER=");
1608 	if (getpw((int)dp->di_uid, uidbuf) == 0) {
1609 		for (p = uidbuf; *p != ':'; p++);
1610 		*p = 0;
1611 		printf("%s ", uidbuf);
1612 	}
1613 	else {
1614 		printf("%d ", dp->di_uid);
1615 	}
1616 	printf("MODE=%o\n", dp->di_mode);
1617 	if (preen)
1618 		printf("%s: ", devname);
1619 	printf("SIZE=%ld ", dp->di_size);
1620 	p = ctime(&dp->di_mtime);
1621 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
1622 }
1623 
1624 makecg()
1625 {
1626 	int c, blk;
1627 	daddr_t dbase, d, dlower, dupper, dmax;
1628 	long i, j, s;
1629 	register struct csum *cs;
1630 	register DINODE *dp;
1631 
1632 	sblock.fs_cstotal.cs_nbfree = 0;
1633 	sblock.fs_cstotal.cs_nffree = 0;
1634 	sblock.fs_cstotal.cs_nifree = 0;
1635 	sblock.fs_cstotal.cs_ndir = 0;
1636 	for (c = 0; c < sblock.fs_ncg; c++) {
1637 		dbase = cgbase(&sblock, c);
1638 		dmax = dbase + sblock.fs_fpg;
1639 		if (dmax > sblock.fs_size) {
1640 			for ( ; dmax >= sblock.fs_size; dmax--)
1641 				clrbit(cgrp.cg_free, dmax - dbase);
1642 			dmax++;
1643 		}
1644 		dlower = cgsblock(&sblock, c) - dbase;
1645 		dupper = cgdmin(&sblock, c) - dbase;
1646 		cs = &sblock.fs_cs(&sblock, c);
1647 		cgrp.cg_time = time(0);
1648 		cgrp.cg_magic = CG_MAGIC;
1649 		cgrp.cg_cgx = c;
1650 		if (c == sblock.fs_ncg - 1)
1651 			cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
1652 		else
1653 			cgrp.cg_ncyl = sblock.fs_cpg;
1654 		cgrp.cg_niblk = sblock.fs_ipg;
1655 		cgrp.cg_ndblk = dmax - dbase;
1656 		cgrp.cg_cs.cs_ndir = 0;
1657 		cgrp.cg_cs.cs_nffree = 0;
1658 		cgrp.cg_cs.cs_nbfree = 0;
1659 		cgrp.cg_cs.cs_nifree = 0;
1660 		cgrp.cg_rotor = 0;
1661 		cgrp.cg_frotor = 0;
1662 		cgrp.cg_irotor = 0;
1663 		for (i = 0; i < sblock.fs_frag; i++)
1664 			cgrp.cg_frsum[i] = 0;
1665 		inum = sblock.fs_ipg * c;
1666 		for (i = 0; i < sblock.fs_ipg; inum++, i++) {
1667 			cgrp.cg_cs.cs_nifree++;
1668 			clrbit(cgrp.cg_iused, i);
1669 			dp = ginode();
1670 			if (dp == NULL)
1671 				continue;
1672 			if (ALLOC) {
1673 				if (DIRCT)
1674 					cgrp.cg_cs.cs_ndir++;
1675 				cgrp.cg_cs.cs_nifree--;
1676 				setbit(cgrp.cg_iused, i);
1677 				continue;
1678 			}
1679 		}
1680 		while (i < MAXIPG) {
1681 			clrbit(cgrp.cg_iused, i);
1682 			i++;
1683 		}
1684 		if (c == 0)
1685 			for (i = 0; i < ROOTINO; i++) {
1686 				setbit(cgrp.cg_iused, i);
1687 				cgrp.cg_cs.cs_nifree--;
1688 			}
1689 		for (s = 0; s < MAXCPG; s++) {
1690 			cgrp.cg_btot[s] = 0;
1691 			for (i = 0; i < NRPOS; i++)
1692 				cgrp.cg_b[s][i] = 0;
1693 		}
1694 		if (c == 0) {
1695 			dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
1696 		}
1697 		for (d = dlower; d < dupper; d++)
1698 			clrbit(cgrp.cg_free, d);
1699 		for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
1700 		    d += sblock.fs_frag) {
1701 			j = 0;
1702 			for (i = 0; i < sblock.fs_frag; i++) {
1703 				if (!getbmap(dbase + d + i)) {
1704 					setbit(cgrp.cg_free, d + i);
1705 					j++;
1706 				} else
1707 					clrbit(cgrp.cg_free, d+i);
1708 			}
1709 			if (j == sblock.fs_frag) {
1710 				cgrp.cg_cs.cs_nbfree++;
1711 				cgrp.cg_btot[cbtocylno(&sblock, d)]++;
1712 				cgrp.cg_b[cbtocylno(&sblock, d)]
1713 				    [cbtorpos(&sblock, d)]++;
1714 			} else if (j > 0) {
1715 				cgrp.cg_cs.cs_nffree += j;
1716 				blk = blkmap(&sblock, cgrp.cg_free, d);
1717 				fragacct(&sblock, blk, cgrp.cg_frsum, 1);
1718 			}
1719 		}
1720 		for (j = d; d < dmax - dbase; d++) {
1721 			if (!getbmap(dbase + d)) {
1722 				setbit(cgrp.cg_free, d);
1723 				cgrp.cg_cs.cs_nffree++;
1724 			} else
1725 				clrbit(cgrp.cg_free, d);
1726 		}
1727 		for (; d % sblock.fs_frag != 0; d++)
1728 			clrbit(cgrp.cg_free, d);
1729 		if (j != d) {
1730 			blk = blkmap(&sblock, cgrp.cg_free, j);
1731 			fragacct(&sblock, blk, cgrp.cg_frsum, 1);
1732 		}
1733 		for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
1734 			clrblock(&sblock, cgrp.cg_free, d);
1735 		sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
1736 		sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
1737 		sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
1738 		sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
1739 		*cs = cgrp.cg_cs;
1740 		bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
1741 		    sblock.fs_cgsize);
1742 	}
1743 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
1744 		bwrite(&dfile, (char *)sblock.fs_csp[j],
1745 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1746 		    sblock.fs_cssize - i < sblock.fs_bsize ?
1747 		    sblock.fs_cssize - i : sblock.fs_bsize);
1748 	}
1749 	sblock.fs_ronly = 0;
1750 	sblock.fs_fmod = 0;
1751 	sbdirty();
1752 }
1753 
1754 findino(dirp)
1755 	register DIRECT *dirp;
1756 {
1757 	if (dirp->d_ino == 0)
1758 		return (KEEPON);
1759 	if (!strcmp(dirp->d_name, srchname)) {
1760 		if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1761 			parentdir = dirp->d_ino;
1762 		return (STOP);
1763 	}
1764 	return (KEEPON);
1765 }
1766 
1767 mkentry(dirp)
1768 	register DIRECT *dirp;
1769 {
1770 	register ino_t in;
1771 	register char *p;
1772 	DIRECT newent;
1773 	int newlen, oldlen;
1774 
1775 	newent.d_namlen = 11;
1776 	newlen = DIRSIZ(&newent);
1777 	if (dirp->d_ino != 0)
1778 		oldlen = DIRSIZ(dirp);
1779 	else
1780 		oldlen = 0;
1781 	if (dirp->d_reclen - oldlen < newlen)
1782 		return (KEEPON);
1783 	newent.d_reclen = dirp->d_reclen - oldlen;
1784 	dirp->d_reclen = oldlen;
1785 	dirp = (struct direct *)(((char *)dirp) + oldlen);
1786 	dirp->d_ino = orphan;
1787 	dirp->d_reclen = newent.d_reclen;
1788 	p = &dirp->d_name[2];
1789 	for (in = imax; in > 0; in /= 10)
1790 		p++;
1791 	*--p = 0;
1792 	dirp->d_namlen = p - dirp->d_name;
1793 	in = orphan;
1794 	while (p > dirp->d_name) {
1795 		*--p = (in % 10) + '0';
1796 		in /= 10;
1797 	}
1798 	*p = '#';
1799 	return (ALTERD|STOP);
1800 }
1801 
1802 chgdd(dirp)
1803 	register DIRECT *dirp;
1804 {
1805 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
1806 	dirp->d_name[2] == 0) {
1807 		dirp->d_ino = lfdir;
1808 		return (ALTERD|STOP);
1809 	}
1810 	return (KEEPON);
1811 }
1812 
1813 linkup()
1814 {
1815 	register DINODE *dp;
1816 	register lostdir;
1817 	register ino_t pdir;
1818 
1819 	if ((dp = ginode()) == NULL)
1820 		return (0);
1821 	lostdir = DIRCT;
1822 	pdir = parentdir;
1823 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
1824 	pinode();
1825 	if (preen && dp->di_size == 0)
1826 		return (0);
1827 	if (preen)
1828 		printf(" (RECONNECTED)\n");
1829 	else
1830 		if (reply("RECONNECT") == 0)
1831 			return (0);
1832 	orphan = inum;
1833 	if (lfdir == 0) {
1834 		inum = ROOTINO;
1835 		if ((dp = ginode()) == NULL) {
1836 			inum = orphan;
1837 			return (0);
1838 		}
1839 		pfunc = findino;
1840 		srchname = lfname;
1841 		filsize = dp->di_size;
1842 		parentdir = 0;
1843 		ckinode(dp, DATA);
1844 		inum = orphan;
1845 		if ((lfdir = parentdir) == 0) {
1846 			pfatal("SORRY. NO lost+found DIRECTORY");
1847 			printf("\n\n");
1848 			return (0);
1849 		}
1850 	}
1851 	inum = lfdir;
1852 	if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) {
1853 		inum = orphan;
1854 		pfatal("SORRY. NO lost+found DIRECTORY");
1855 		printf("\n\n");
1856 		return (0);
1857 	}
1858 	if (fragoff(&sblock, dp->di_size)) {
1859 		dp->di_size = fragroundup(&sblock, dp->di_size);
1860 		inodirty();
1861 	}
1862 	filsize = dp->di_size;
1863 	inum = orphan;
1864 	pfunc = mkentry;
1865 	if ((ckinode(dp, DATA) & ALTERD) == 0) {
1866 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
1867 		printf("\n\n");
1868 		return (0);
1869 	}
1870 	lncntp[inum]--;
1871 	if (lostdir) {
1872 		pfunc = chgdd;
1873 		dp = ginode();
1874 		filsize = dp->di_size;
1875 		ckinode(dp, DATA);
1876 		inum = lfdir;
1877 		if ((dp = ginode()) != NULL) {
1878 			dp->di_nlink++;
1879 			inodirty();
1880 			lncntp[inum]++;
1881 		}
1882 		inum = orphan;
1883 		pwarn("DIR I=%u CONNECTED. ", orphan);
1884 		printf("PARENT WAS I=%u\n", pdir);
1885 		if (preen == 0)
1886 			printf("\n");
1887 	}
1888 	return (1);
1889 }
1890 
1891 bread(fcp, buf, blk, size)
1892 	daddr_t blk;
1893 	register struct filecntl *fcp;
1894 	register size;
1895 	char *buf;
1896 {
1897 	if (lseek(fcp->rfdes, dbtob(blk), 0) < 0)
1898 		rwerr("SEEK", blk);
1899 	else if (read(fcp->rfdes, buf, size) == size)
1900 		return (1);
1901 	rwerr("READ", blk);
1902 	return (0);
1903 }
1904 
1905 bwrite(fcp, buf, blk, size)
1906 	daddr_t blk;
1907 	register struct filecntl *fcp;
1908 	register size;
1909 	char *buf;
1910 {
1911 
1912 	if (fcp->wfdes < 0)
1913 		return (0);
1914 	if (lseek(fcp->wfdes, dbtob(blk), 0) < 0)
1915 		rwerr("SEEK", blk);
1916 	else if (write(fcp->wfdes, buf, size) == size) {
1917 		fcp->mod = 1;
1918 		return (1);
1919 	}
1920 	rwerr("WRITE", blk);
1921 	return (0);
1922 }
1923 
1924 catch()
1925 {
1926 
1927 	ckfini();
1928 	exit(12);
1929 }
1930 
1931 char *
1932 unrawname(cp)
1933 	char *cp;
1934 {
1935 	char *dp = rindex(cp, '/');
1936 	struct stat stb;
1937 
1938 	if (dp == 0)
1939 		return (cp);
1940 	if (stat(cp, &stb) < 0)
1941 		return (cp);
1942 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
1943 		return (cp);
1944 	if (*(dp+1) != 'r')
1945 		return (cp);
1946 	strcpy(dp+1, dp+2);
1947 	return (cp);
1948 }
1949 
1950 char *
1951 rawname(cp)
1952 	char *cp;
1953 {
1954 	static char rawbuf[32];
1955 	char *dp = rindex(cp, '/');
1956 
1957 	if (dp == 0)
1958 		return (0);
1959 	*dp = 0;
1960 	strcpy(rawbuf, cp);
1961 	*dp = '/';
1962 	strcat(rawbuf, "/r");
1963 	strcat(rawbuf, dp+1);
1964 	return (rawbuf);
1965 }
1966 
1967 /* VARARGS1 */
1968 error(s1, s2, s3, s4)
1969 	char *s1;
1970 {
1971 
1972 	printf(s1, s2, s3, s4);
1973 }
1974 
1975 /* VARARGS1 */
1976 errexit(s1, s2, s3, s4)
1977 	char *s1;
1978 {
1979 	error(s1, s2, s3, s4);
1980 	exit(8);
1981 }
1982 
1983 /*
1984  * An inconsistency occured which shouldn't during normal operations.
1985  * Die if preening, otherwise just printf.
1986  */
1987 /* VARARGS1 */
1988 pfatal(s, a1, a2, a3)
1989 	char *s;
1990 {
1991 
1992 	if (preen) {
1993 		printf("%s: ", devname);
1994 		printf(s, a1, a2, a3);
1995 		printf("\n");
1996 		preendie();
1997 	}
1998 	printf(s, a1, a2, a3);
1999 }
2000 
2001 preendie()
2002 {
2003 
2004 	printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
2005 	exit(8);
2006 }
2007 
2008 /*
2009  * Pwarn is like printf when not preening,
2010  * or a warning (preceded by filename) when preening.
2011  */
2012 /* VARARGS1 */
2013 pwarn(s, a1, a2, a3, a4, a5, a6)
2014 	char *s;
2015 {
2016 
2017 	if (preen)
2018 		printf("%s: ", devname);
2019 	printf(s, a1, a2, a3, a4, a5, a6);
2020 }
2021 
2022 panic(s)
2023 	char *s;
2024 {
2025 
2026 	pfatal("internal inconsistency: %s\n");
2027 	exit(12);
2028 }
2029