update /etc/dumpdates in place
[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
3cfe4689 8static char sccsid[] = "@(#)utilities.c 5.2 (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;
cee9cbac 173 pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:");
49505034
KM
174 for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) {
175 if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) {
cee9cbac 176 printf(" %d,", blk + i / DEV_BSIZE);
49505034
KM
177 bzero(cp, DEV_BSIZE);
178 errs++;
179 }
180 }
cee9cbac 181 printf("\n");
49505034 182 return (errs);
5d9906c0
KM
183}
184
185bwrite(fcp, buf, blk, size)
186 register struct filecntl *fcp;
187 char *buf;
188 daddr_t blk;
189 long size;
190{
cee9cbac
KM
191 int i;
192 char *cp;
5d9906c0
KM
193
194 if (fcp->wfdes < 0)
cee9cbac 195 return;
5d9906c0
KM
196 if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
197 rwerr("SEEK", blk);
198 else if (write(fcp->wfdes, buf, (int)size) == size) {
199 fcp->mod = 1;
cee9cbac 200 return;
5d9906c0
KM
201 }
202 rwerr("WRITE", blk);
cee9cbac
KM
203 if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
204 rwerr("SEEK", blk);
205 pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
206 for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE)
207 if (write(fcp->wfdes, cp, DEV_BSIZE) < 0)
208 printf(" %d,", blk + i / DEV_BSIZE);
209 printf("\n");
210 return;
5d9906c0
KM
211}
212
3e2a23ca
KM
213/*
214 * allocate a data block with the specified number of fragments
215 */
216allocblk(frags)
217 int frags;
218{
219 register int i, j, k;
220
221 if (frags <= 0 || frags > sblock.fs_frag)
222 return (0);
223 for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) {
224 for (j = 0; j <= sblock.fs_frag - frags; j++) {
225 if (getbmap(i + j))
226 continue;
227 for (k = 1; k < frags; k++)
228 if (getbmap(i + j + k))
229 break;
230 if (k < frags) {
231 j += k;
232 continue;
233 }
234 for (k = 0; k < frags; k++)
235 setbmap(i + j + k);
236 n_blks += frags;
237 return (i + j);
238 }
239 }
240 return (0);
241}
242
243/*
244 * Free a previously allocated block
245 */
246freeblk(blkno, frags)
247 daddr_t blkno;
248 int frags;
249{
250 struct inodesc idesc;
251
252 idesc.id_blkno = blkno;
253 idesc.id_numfrags = frags;
254 pass4check(&idesc);
255}
256
3ad2f081
KM
257/*
258 * Find a pathname
259 */
260getpathname(namebuf, curdir, ino)
261 char *namebuf;
262 ino_t curdir, ino;
263{
264 int len;
265 register char *cp;
266 struct inodesc idesc;
267 extern int findname();
268
269 if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
270 strcpy(namebuf, "?");
271 return;
272 }
273 bzero(&idesc, sizeof(struct inodesc));
274 idesc.id_type = DATA;
275 cp = &namebuf[BUFSIZ - 1];
276 *cp-- = '\0';
277 if (curdir != ino) {
278 idesc.id_parent = curdir;
279 goto namelookup;
280 }
281 while (ino != ROOTINO) {
282 idesc.id_number = ino;
283 idesc.id_func = findino;
284 idesc.id_name = "..";
285 if ((ckinode(ginode(ino), &idesc) & STOP) == 0)
286 break;
287 namelookup:
288 idesc.id_number = idesc.id_parent;
289 idesc.id_parent = ino;
290 idesc.id_func = findname;
291 idesc.id_name = namebuf;
292 if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0)
293 break;
294 len = strlen(namebuf);
295 cp -= len;
296 if (cp < &namebuf[MAXNAMLEN])
297 break;
298 bcopy(namebuf, cp, len);
299 *--cp = '/';
300 ino = idesc.id_number;
301 }
302 if (ino != ROOTINO) {
303 strcpy(namebuf, "?");
304 return;
305 }
306 bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp);
307}
308
5d9906c0
KM
309catch()
310{
311
312 ckfini();
313 exit(12);
314}
315
3cfe4689
MK
316/*
317 * When preening, allow a single quit to signal
318 * a special exit after filesystem checks complete
319 * so that reboot sequence may be interrupted.
320 */
321catchquit()
322{
323 extern returntosingle;
324
325 printf("returning to single-user after filesystem check\n");
326 returntosingle = 1;
327 (void)signal(SIGQUIT, SIG_DFL);
328}
329
330/*
331 * Ignore a single quit signal; wait and flush just in case.
332 * Used by child processes in preen.
333 */
334voidquit()
335{
336
337 sleep(1);
338 (void)signal(SIGQUIT, SIG_IGN);
339 (void)signal(SIGQUIT, SIG_DFL);
340}
341
5d9906c0
KM
342/*
343 * determine whether an inode should be fixed.
344 */
7718c0e6 345dofix(idesc, msg)
5d9906c0 346 register struct inodesc *idesc;
7718c0e6 347 char *msg;
5d9906c0
KM
348{
349
350 switch (idesc->id_fix) {
351
352 case DONTKNOW:
7718c0e6
KM
353 if (idesc->id_type == DATA)
354 direrr(idesc->id_number, msg);
355 else
356 pwarn(msg);
357 if (preen) {
358 printf(" (SALVAGED)\n");
359 idesc->id_fix = FIX;
360 return (ALTERED);
361 }
5d9906c0
KM
362 if (reply("SALVAGE") == 0) {
363 idesc->id_fix = NOFIX;
364 return (0);
365 }
366 idesc->id_fix = FIX;
367 return (ALTERED);
368
369 case FIX:
370 return (ALTERED);
371
372 case NOFIX:
373 return (0);
374
375 default:
376 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
377 }
378 /* NOTREACHED */
379}
380
5d9906c0
KM
381/* VARARGS1 */
382errexit(s1, s2, s3, s4)
383 char *s1;
384{
7718c0e6 385 printf(s1, s2, s3, s4);
5d9906c0
KM
386 exit(8);
387}
388
389/*
390 * An inconsistency occured which shouldn't during normal operations.
391 * Die if preening, otherwise just printf.
392 */
393/* VARARGS1 */
394pfatal(s, a1, a2, a3)
395 char *s;
396{
397
398 if (preen) {
399 printf("%s: ", devname);
400 printf(s, a1, a2, a3);
401 printf("\n");
7718c0e6
KM
402 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
403 devname);
404 exit(8);
5d9906c0
KM
405 }
406 printf(s, a1, a2, a3);
407}
408
5d9906c0
KM
409/*
410 * Pwarn is like printf when not preening,
411 * or a warning (preceded by filename) when preening.
412 */
413/* VARARGS1 */
414pwarn(s, a1, a2, a3, a4, a5, a6)
415 char *s;
416{
417
418 if (preen)
419 printf("%s: ", devname);
420 printf(s, a1, a2, a3, a4, a5, a6);
421}
422
423#ifndef lint
424/*
425 * Stub for routines from kernel.
426 */
427panic(s)
428 char *s;
429{
430
7718c0e6
KM
431 pfatal("INTERNAL INCONSISTENCY:");
432 errexit(s);
5d9906c0
KM
433}
434#endif