xref: /csrg-svn/sbin/fsck/utilities.c (revision 17991)
1 #ifndef lint
2 static char version[] = "@(#)utilities.c	3.4 (Berkeley) 02/15/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 	if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
94 		bp->b_bno = dblk;
95 		bp->b_size = size;
96 		return (bp);
97 	}
98 	bp->b_bno = (daddr_t)-1;
99 	return (NULL);
100 }
101 
102 flush(fcp, bp)
103 	struct filecntl *fcp;
104 	register BUFAREA *bp;
105 {
106 	register int i, j;
107 
108 	if (!bp->b_dirty)
109 		return;
110 	bp->b_dirty = 0;
111 	(void)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 		(void)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 	(void)close(dfile.rfdes);
146 	(void)close(dfile.wfdes);
147 }
148 
149 bread(fcp, buf, blk, size)
150 	register struct filecntl *fcp;
151 	char *buf;
152 	daddr_t blk;
153 	long size;
154 {
155 	if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
156 		rwerr("SEEK", blk);
157 	else if (read(fcp->rfdes, buf, (int)size) == size)
158 		return (1);
159 	rwerr("READ", blk);
160 	return (0);
161 }
162 
163 bwrite(fcp, buf, blk, size)
164 	register struct filecntl *fcp;
165 	char *buf;
166 	daddr_t blk;
167 	long size;
168 {
169 
170 	if (fcp->wfdes < 0)
171 		return (0);
172 	if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
173 		rwerr("SEEK", blk);
174 	else if (write(fcp->wfdes, buf, (int)size) == size) {
175 		fcp->mod = 1;
176 		return (1);
177 	}
178 	rwerr("WRITE", blk);
179 	return (0);
180 }
181 
182 /*
183  * allocate a data block with the specified number of fragments
184  */
185 allocblk(frags)
186 	int frags;
187 {
188 	register int i, j, k;
189 
190 	if (frags <= 0 || frags > sblock.fs_frag)
191 		return (0);
192 	for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) {
193 		for (j = 0; j <= sblock.fs_frag - frags; j++) {
194 			if (getbmap(i + j))
195 				continue;
196 			for (k = 1; k < frags; k++)
197 				if (getbmap(i + j + k))
198 					break;
199 			if (k < frags) {
200 				j += k;
201 				continue;
202 			}
203 			for (k = 0; k < frags; k++)
204 				setbmap(i + j + k);
205 			n_blks += frags;
206 			return (i + j);
207 		}
208 	}
209 	return (0);
210 }
211 
212 /*
213  * Free a previously allocated block
214  */
215 freeblk(blkno, frags)
216 	daddr_t blkno;
217 	int frags;
218 {
219 	struct inodesc idesc;
220 
221 	idesc.id_blkno = blkno;
222 	idesc.id_numfrags = frags;
223 	pass4check(&idesc);
224 }
225 
226 /*
227  * Find a pathname
228  */
229 getpathname(namebuf, curdir, ino)
230 	char *namebuf;
231 	ino_t curdir, ino;
232 {
233 	int len;
234 	register char *cp;
235 	struct inodesc idesc;
236 	extern int findname();
237 
238 	if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
239 		strcpy(namebuf, "?");
240 		return;
241 	}
242 	bzero(&idesc, sizeof(struct inodesc));
243 	idesc.id_type = DATA;
244 	cp = &namebuf[BUFSIZ - 1];
245 	*cp-- = '\0';
246 	if (curdir != ino) {
247 		idesc.id_parent = curdir;
248 		goto namelookup;
249 	}
250 	while (ino != ROOTINO) {
251 		idesc.id_number = ino;
252 		idesc.id_func = findino;
253 		idesc.id_name = "..";
254 		if ((ckinode(ginode(ino), &idesc) & STOP) == 0)
255 			break;
256 	namelookup:
257 		idesc.id_number = idesc.id_parent;
258 		idesc.id_parent = ino;
259 		idesc.id_func = findname;
260 		idesc.id_name = namebuf;
261 		if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0)
262 			break;
263 		len = strlen(namebuf);
264 		cp -= len;
265 		if (cp < &namebuf[MAXNAMLEN])
266 			break;
267 		bcopy(namebuf, cp, len);
268 		*--cp = '/';
269 		ino = idesc.id_number;
270 	}
271 	if (ino != ROOTINO) {
272 		strcpy(namebuf, "?");
273 		return;
274 	}
275 	bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp);
276 }
277 
278 catch()
279 {
280 
281 	ckfini();
282 	exit(12);
283 }
284 
285 /*
286  * determine whether an inode should be fixed.
287  */
288 dofix(idesc, msg)
289 	register struct inodesc *idesc;
290 	char *msg;
291 {
292 
293 	switch (idesc->id_fix) {
294 
295 	case DONTKNOW:
296 		if (idesc->id_type == DATA)
297 			direrr(idesc->id_number, msg);
298 		else
299 			pwarn(msg);
300 		if (preen) {
301 			printf(" (SALVAGED)\n");
302 			idesc->id_fix = FIX;
303 			return (ALTERED);
304 		}
305 		if (reply("SALVAGE") == 0) {
306 			idesc->id_fix = NOFIX;
307 			return (0);
308 		}
309 		idesc->id_fix = FIX;
310 		return (ALTERED);
311 
312 	case FIX:
313 		return (ALTERED);
314 
315 	case NOFIX:
316 		return (0);
317 
318 	default:
319 		errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
320 	}
321 	/* NOTREACHED */
322 }
323 
324 /* VARARGS1 */
325 errexit(s1, s2, s3, s4)
326 	char *s1;
327 {
328 	printf(s1, s2, s3, s4);
329 	exit(8);
330 }
331 
332 /*
333  * An inconsistency occured which shouldn't during normal operations.
334  * Die if preening, otherwise just printf.
335  */
336 /* VARARGS1 */
337 pfatal(s, a1, a2, a3)
338 	char *s;
339 {
340 
341 	if (preen) {
342 		printf("%s: ", devname);
343 		printf(s, a1, a2, a3);
344 		printf("\n");
345 		printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
346 			devname);
347 		exit(8);
348 	}
349 	printf(s, a1, a2, a3);
350 }
351 
352 /*
353  * Pwarn is like printf when not preening,
354  * or a warning (preceded by filename) when preening.
355  */
356 /* VARARGS1 */
357 pwarn(s, a1, a2, a3, a4, a5, a6)
358 	char *s;
359 {
360 
361 	if (preen)
362 		printf("%s: ", devname);
363 	printf(s, a1, a2, a3, a4, a5, a6);
364 }
365 
366 #ifndef lint
367 /*
368  * Stub for routines from kernel.
369  */
370 panic(s)
371 	char *s;
372 {
373 
374 	pfatal("INTERNAL INCONSISTENCY:");
375 	errexit(s);
376 }
377 #endif
378