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