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