calc and print out pathname of offending hard links to directories
[unix-history] / usr / src / sbin / fsck / utilities.c
CommitLineData
5d9906c0 1#ifndef lint
3ad2f081 2static char version[] = "@(#)utilities.c 3.4 (Berkeley) %G%";
5d9906c0
KM
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>
3ad2f081 10#include <sys/dir.h>
5d9906c0
KM
11#include "fsck.h"
12
13long lseek();
14
15ftypeok(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
35reply(s)
36 char *s;
37{
38 char line[80];
39
40 if (preen)
41 pfatal("INTERNAL ERROR: GOT TO reply()");
5d9906c0
KM
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
60getline(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
79BUFAREA *
80getblk(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
102flush(fcp, bp)
103 struct filecntl *fcp;
104 register BUFAREA *bp;
105{
7718c0e6 106 register int i, j;
5d9906c0 107
7718c0e6
KM
108 if (!bp->b_dirty)
109 return;
5d9906c0 110 bp->b_dirty = 0;
7718c0e6
KM
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 }
5d9906c0
KM
120}
121
122rwerr(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
134ckfini()
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
149bread(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
163bwrite(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
3e2a23ca
KM
182/*
183 * allocate a data block with the specified number of fragments
184 */
185allocblk(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 */
215freeblk(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
3ad2f081
KM
226/*
227 * Find a pathname
228 */
229getpathname(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
5d9906c0
KM
278catch()
279{
280
281 ckfini();
282 exit(12);
283}
284
285/*
286 * determine whether an inode should be fixed.
287 */
7718c0e6 288dofix(idesc, msg)
5d9906c0 289 register struct inodesc *idesc;
7718c0e6 290 char *msg;
5d9906c0
KM
291{
292
293 switch (idesc->id_fix) {
294
295 case DONTKNOW:
7718c0e6
KM
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 }
5d9906c0
KM
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
5d9906c0
KM
324/* VARARGS1 */
325errexit(s1, s2, s3, s4)
326 char *s1;
327{
7718c0e6 328 printf(s1, s2, s3, s4);
5d9906c0
KM
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 */
337pfatal(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");
7718c0e6
KM
345 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
346 devname);
347 exit(8);
5d9906c0
KM
348 }
349 printf(s, a1, a2, a3);
350}
351
5d9906c0
KM
352/*
353 * Pwarn is like printf when not preening,
354 * or a warning (preceded by filename) when preening.
355 */
356/* VARARGS1 */
357pwarn(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 */
370panic(s)
371 char *s;
372{
373
7718c0e6
KM
374 pfatal("INTERNAL INCONSISTENCY:");
375 errexit(s);
5d9906c0
KM
376}
377#endif