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