xref: /csrg-svn/sbin/fsck/utilities.c (revision 21758)
1 #ifndef lint
2 static char version[] = "@(#)utilities.c	3.7 (Berkeley) 06/02/85";
3 #endif
4 
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <sys/param.h>
8 #include <sys/inode.h>
9 #include <sys/fs.h>
10 #include <sys/dir.h>
11 #include "fsck.h"
12 
13 long	lseek();
14 
15 ftypeok(dp)
16 	DINODE *dp;
17 {
18 	switch (dp->di_mode & IFMT) {
19 
20 	case IFDIR:
21 	case IFREG:
22 	case IFBLK:
23 	case IFCHR:
24 	case IFLNK:
25 	case IFSOCK:
26 		return (1);
27 
28 	default:
29 		if (debug)
30 			printf("bad file type 0%o\n", dp->di_mode);
31 		return (0);
32 	}
33 }
34 
35 reply(s)
36 	char *s;
37 {
38 	char line[80];
39 
40 	if (preen)
41 		pfatal("INTERNAL ERROR: GOT TO reply()");
42 	printf("\n%s? ", s);
43 	if (nflag || dfile.wfdes < 0) {
44 		printf(" no\n\n");
45 		return (0);
46 	}
47 	if (yflag) {
48 		printf(" yes\n\n");
49 		return (1);
50 	}
51 	if (getline(stdin, line, sizeof(line)) == EOF)
52 		errexit("\n");
53 	printf("\n");
54 	if (line[0] == 'y' || line[0] == 'Y')
55 		return (1);
56 	else
57 		return (0);
58 }
59 
60 getline(fp, loc, maxlen)
61 	FILE *fp;
62 	char *loc;
63 {
64 	register n;
65 	register char *p, *lastloc;
66 
67 	p = loc;
68 	lastloc = &p[maxlen-1];
69 	while ((n = getc(fp)) != '\n') {
70 		if (n == EOF)
71 			return (EOF);
72 		if (!isspace(n) && p < lastloc)
73 			*p++ = n;
74 	}
75 	*p = 0;
76 	return (p - loc);
77 }
78 
79 BUFAREA *
80 getblk(bp, blk, size)
81 	register BUFAREA *bp;
82 	daddr_t blk;
83 	long size;
84 {
85 	register struct filecntl *fcp;
86 	daddr_t dblk;
87 
88 	fcp = &dfile;
89 	dblk = fsbtodb(&sblock, blk);
90 	if (bp->b_bno == dblk)
91 		return (bp);
92 	flush(fcp, bp);
93 	bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size);
94 	bp->b_bno = dblk;
95 	bp->b_size = size;
96 	return (bp);
97 }
98 
99 flush(fcp, bp)
100 	struct filecntl *fcp;
101 	register BUFAREA *bp;
102 {
103 	register int i, j;
104 
105 	if (!bp->b_dirty)
106 		return;
107 	if (bp->b_errs != 0)
108 		pfatal("WRITING ZERO'ED BLOCK %d TO DISK\n", bp->b_bno);
109 	bp->b_dirty = 0;
110 	bp->b_errs = 0;
111 	bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
112 	if (bp != &sblk)
113 		return;
114 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
115 		bwrite(&dfile, (char *)sblock.fs_csp[j],
116 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
117 		    sblock.fs_cssize - i < sblock.fs_bsize ?
118 		    sblock.fs_cssize - i : sblock.fs_bsize);
119 	}
120 }
121 
122 rwerr(s, blk)
123 	char *s;
124 	daddr_t blk;
125 {
126 
127 	if (preen == 0)
128 		printf("\n");
129 	pfatal("CANNOT %s: BLK %ld", s, blk);
130 	if (reply("CONTINUE") == 0)
131 		errexit("Program terminated\n");
132 }
133 
134 ckfini()
135 {
136 
137 	flush(&dfile, &fileblk);
138 	flush(&dfile, &sblk);
139 	if (sblk.b_bno != SBLOCK) {
140 		sblk.b_bno = SBLOCK;
141 		sbdirty();
142 		flush(&dfile, &sblk);
143 	}
144 	flush(&dfile, &inoblk);
145 	flush(&dfile, &cgblk);
146 	(void)close(dfile.rfdes);
147 	(void)close(dfile.wfdes);
148 }
149 
150 bread(fcp, buf, blk, size)
151 	register struct filecntl *fcp;
152 	char *buf;
153 	daddr_t blk;
154 	long size;
155 {
156 	char *cp;
157 	int i, errs;
158 
159 	if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
160 		rwerr("SEEK", blk);
161 	else if (read(fcp->rfdes, buf, (int)size) == size)
162 		return (0);
163 	rwerr("READ", blk);
164 	if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
165 		rwerr("SEEK", blk);
166 	errs = 0;
167 	pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:");
168 	for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) {
169 		if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) {
170 			printf(" %d,", blk + i / DEV_BSIZE);
171 			bzero(cp, DEV_BSIZE);
172 			errs++;
173 		}
174 	}
175 	printf("\n");
176 	return (errs);
177 }
178 
179 bwrite(fcp, buf, blk, size)
180 	register struct filecntl *fcp;
181 	char *buf;
182 	daddr_t blk;
183 	long size;
184 {
185 	int i;
186 	char *cp;
187 
188 	if (fcp->wfdes < 0)
189 		return;
190 	if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
191 		rwerr("SEEK", blk);
192 	else if (write(fcp->wfdes, buf, (int)size) == size) {
193 		fcp->mod = 1;
194 		return;
195 	}
196 	rwerr("WRITE", blk);
197 	if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
198 		rwerr("SEEK", blk);
199 	pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
200 	for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE)
201 		if (write(fcp->wfdes, cp, DEV_BSIZE) < 0)
202 			printf(" %d,", blk + i / DEV_BSIZE);
203 	printf("\n");
204 	return;
205 }
206 
207 /*
208  * allocate a data block with the specified number of fragments
209  */
210 allocblk(frags)
211 	int frags;
212 {
213 	register int i, j, k;
214 
215 	if (frags <= 0 || frags > sblock.fs_frag)
216 		return (0);
217 	for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) {
218 		for (j = 0; j <= sblock.fs_frag - frags; j++) {
219 			if (getbmap(i + j))
220 				continue;
221 			for (k = 1; k < frags; k++)
222 				if (getbmap(i + j + k))
223 					break;
224 			if (k < frags) {
225 				j += k;
226 				continue;
227 			}
228 			for (k = 0; k < frags; k++)
229 				setbmap(i + j + k);
230 			n_blks += frags;
231 			return (i + j);
232 		}
233 	}
234 	return (0);
235 }
236 
237 /*
238  * Free a previously allocated block
239  */
240 freeblk(blkno, frags)
241 	daddr_t blkno;
242 	int frags;
243 {
244 	struct inodesc idesc;
245 
246 	idesc.id_blkno = blkno;
247 	idesc.id_numfrags = frags;
248 	pass4check(&idesc);
249 }
250 
251 /*
252  * Find a pathname
253  */
254 getpathname(namebuf, curdir, ino)
255 	char *namebuf;
256 	ino_t curdir, ino;
257 {
258 	int len;
259 	register char *cp;
260 	struct inodesc idesc;
261 	extern int findname();
262 
263 	if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
264 		strcpy(namebuf, "?");
265 		return;
266 	}
267 	bzero(&idesc, sizeof(struct inodesc));
268 	idesc.id_type = DATA;
269 	cp = &namebuf[BUFSIZ - 1];
270 	*cp-- = '\0';
271 	if (curdir != ino) {
272 		idesc.id_parent = curdir;
273 		goto namelookup;
274 	}
275 	while (ino != ROOTINO) {
276 		idesc.id_number = ino;
277 		idesc.id_func = findino;
278 		idesc.id_name = "..";
279 		if ((ckinode(ginode(ino), &idesc) & STOP) == 0)
280 			break;
281 	namelookup:
282 		idesc.id_number = idesc.id_parent;
283 		idesc.id_parent = ino;
284 		idesc.id_func = findname;
285 		idesc.id_name = namebuf;
286 		if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0)
287 			break;
288 		len = strlen(namebuf);
289 		cp -= len;
290 		if (cp < &namebuf[MAXNAMLEN])
291 			break;
292 		bcopy(namebuf, cp, len);
293 		*--cp = '/';
294 		ino = idesc.id_number;
295 	}
296 	if (ino != ROOTINO) {
297 		strcpy(namebuf, "?");
298 		return;
299 	}
300 	bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp);
301 }
302 
303 catch()
304 {
305 
306 	ckfini();
307 	exit(12);
308 }
309 
310 /*
311  * determine whether an inode should be fixed.
312  */
313 dofix(idesc, msg)
314 	register struct inodesc *idesc;
315 	char *msg;
316 {
317 
318 	switch (idesc->id_fix) {
319 
320 	case DONTKNOW:
321 		if (idesc->id_type == DATA)
322 			direrr(idesc->id_number, msg);
323 		else
324 			pwarn(msg);
325 		if (preen) {
326 			printf(" (SALVAGED)\n");
327 			idesc->id_fix = FIX;
328 			return (ALTERED);
329 		}
330 		if (reply("SALVAGE") == 0) {
331 			idesc->id_fix = NOFIX;
332 			return (0);
333 		}
334 		idesc->id_fix = FIX;
335 		return (ALTERED);
336 
337 	case FIX:
338 		return (ALTERED);
339 
340 	case NOFIX:
341 		return (0);
342 
343 	default:
344 		errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
345 	}
346 	/* NOTREACHED */
347 }
348 
349 /* VARARGS1 */
350 errexit(s1, s2, s3, s4)
351 	char *s1;
352 {
353 	printf(s1, s2, s3, s4);
354 	exit(8);
355 }
356 
357 /*
358  * An inconsistency occured which shouldn't during normal operations.
359  * Die if preening, otherwise just printf.
360  */
361 /* VARARGS1 */
362 pfatal(s, a1, a2, a3)
363 	char *s;
364 {
365 
366 	if (preen) {
367 		printf("%s: ", devname);
368 		printf(s, a1, a2, a3);
369 		printf("\n");
370 		printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
371 			devname);
372 		exit(8);
373 	}
374 	printf(s, a1, a2, a3);
375 }
376 
377 /*
378  * Pwarn is like printf when not preening,
379  * or a warning (preceded by filename) when preening.
380  */
381 /* VARARGS1 */
382 pwarn(s, a1, a2, a3, a4, a5, a6)
383 	char *s;
384 {
385 
386 	if (preen)
387 		printf("%s: ", devname);
388 	printf(s, a1, a2, a3, a4, a5, a6);
389 }
390 
391 #ifndef lint
392 /*
393  * Stub for routines from kernel.
394  */
395 panic(s)
396 	char *s;
397 {
398 
399 	pfatal("INTERNAL INCONSISTENCY:");
400 	errexit(s);
401 }
402 #endif
403