add inode and directory buffer pointers
[unix-history] / usr / src / sbin / ncheck / ncheck.c
CommitLineData
c018628f
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
80ee6eb3 7#ifndef lint
c018628f
DF
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
13#ifndef lint
faf53319 14static char sccsid[] = "@(#)ncheck.c 5.10 (Berkeley) %G%";
c018628f
DF
15#endif not lint
16
d9c5783d
KM
17/*
18 * ncheck -- obtain file names from reading filesystem
19 */
20
b6407c9d 21#define NB 500
c312eebd 22#define MAXNINDIR (MAXBSIZE / sizeof (daddr_t))
d9c5783d 23
61b11ef4 24#include <sys/param.h>
faf53319 25#include <sys/time.h>
2785316e
KB
26#include <sys/vnode.h>
27#include <ufs/inode.h>
28#include <ufs/fs.h>
80ee6eb3 29#include <sys/dir.h>
5086d197 30#include <stdio.h>
d9c5783d
KM
31
32struct fs sblock;
806d9347 33struct dinode itab[MAXBSIZE/sizeof(struct dinode)];
56d45dcd 34struct dinode *gip;
61b11ef4
KM
35struct ilist {
36 ino_t ino;
37 u_short mode;
38 short uid;
39 short gid;
40} ilist[NB];
d9c5783d
KM
41struct htab
42{
43 ino_t h_ino;
44 ino_t h_pino;
5086d197 45 char *h_name;
9570c66d
KM
46} *htab;
47char *strngtab;
48long hsize;
5086d197
KM
49int strngloc;
50
51struct dirstuff {
52 int loc;
53 struct dinode *ip;
54 char dbuf[MAXBSIZE];
55};
d9c5783d
KM
56
57int aflg;
58int sflg;
61b11ef4
KM
59int iflg; /* number of inodes being searched for */
60int mflg;
d9c5783d
KM
61int fi;
62ino_t ino;
63int nhent;
64int nxfile;
837c8ed5 65int dev_bsize = 1;
d9c5783d
KM
66
67int nerror;
68daddr_t bmap();
69long atol();
837c8ed5
KM
70off_t lseek();
71char *malloc(), *strcpy();
d9c5783d 72struct htab *lookup();
837c8ed5 73struct direct *nreaddir();
d9c5783d
KM
74
75main(argc, argv)
20380c05
KM
76 int argc;
77 char *argv[];
d9c5783d 78{
d9c5783d
KM
79 long n;
80
81 while (--argc) {
82 argv++;
83 if (**argv=='-')
84 switch ((*argv)[1]) {
85
86 case 'a':
87 aflg++;
88 continue;
89
90 case 'i':
61b11ef4 91 for(iflg=0; iflg<NB; iflg++) {
d9c5783d
KM
92 n = atol(argv[1]);
93 if(n == 0)
94 break;
61b11ef4
KM
95 ilist[iflg].ino = n;
96 nxfile = iflg;
d9c5783d
KM
97 argv++;
98 argc--;
99 }
100 continue;
101
61b11ef4
KM
102 case 'm':
103 mflg++;
104 continue;
105
d9c5783d
KM
106 case 's':
107 sflg++;
108 continue;
109
110 default:
837c8ed5
KM
111 (void) fprintf(stderr, "ncheck: bad flag %c\n",
112 (*argv)[1]);
d9c5783d
KM
113 nerror++;
114 }
115 check(*argv);
116 }
117 return(nerror);
118}
119
120check(file)
20380c05 121 char *file;
d9c5783d 122{
20380c05 123 register int i, j, c;
d9c5783d
KM
124
125 fi = open(file, 0);
126 if(fi < 0) {
837c8ed5 127 (void) fprintf(stderr, "ncheck: cannot open %s\n", file);
d9c5783d
KM
128 nerror++;
129 return;
130 }
131 nhent = 0;
837c8ed5 132 (void) printf("%s:\n", file);
d9c5783d 133 sync();
837c8ed5 134 bread(SBOFF, (char *)&sblock, (long)SBSIZE);
20380c05 135 if (sblock.fs_magic != FS_MAGIC) {
837c8ed5 136 (void) printf("%s: not a file system\n", file);
20380c05
KM
137 nerror++;
138 return;
139 }
a66ab591 140 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
9570c66d 141 hsize = sblock.fs_ipg * sblock.fs_ncg - sblock.fs_cstotal.cs_nifree + 1;
837c8ed5
KM
142 htab = (struct htab *)malloc((unsigned)hsize * sizeof(struct htab));
143 strngtab = malloc((unsigned)(30 * hsize));
9570c66d 144 if (htab == 0 || strngtab == 0) {
837c8ed5 145 (void) printf("not enough memory to allocate tables\n");
9570c66d
KM
146 nerror++;
147 return;
148 }
d9c5783d
KM
149 ino = 0;
150 for (c = 0; c < sblock.fs_ncg; c++) {
806d9347
KM
151 for (i = 0;
152 i < sblock.fs_ipg / INOPF(&sblock);
153 i += sblock.fs_frag) {
154 bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
155 (char *)itab, sblock.fs_bsize);
156 for (j = 0; j < INOPB(&sblock); j++) {
157 if (itab[j].di_mode != 0)
158 pass1(&itab[j]);
159 ino++;
160 }
d9c5783d
KM
161 }
162 }
61b11ef4 163 ilist[nxfile+1].ino = 0;
d9c5783d
KM
164 ino = 0;
165 for (c = 0; c < sblock.fs_ncg; c++) {
806d9347
KM
166 for (i = 0;
167 i < sblock.fs_ipg / INOPF(&sblock);
168 i += sblock.fs_frag) {
169 bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
170 (char *)itab, sblock.fs_bsize);
171 for (j = 0; j < INOPB(&sblock); j++) {
172 if (itab[j].di_mode != 0)
173 pass2(&itab[j]);
174 ino++;
175 }
d9c5783d
KM
176 }
177 }
178 ino = 0;
179 for (c = 0; c < sblock.fs_ncg; c++) {
806d9347
KM
180 for (i = 0;
181 i < sblock.fs_ipg / INOPF(&sblock);
182 i += sblock.fs_frag) {
183 bread(fsbtodb(&sblock, cgimin(&sblock, c) + i),
184 (char *)itab, sblock.fs_bsize);
185 for (j = 0; j < INOPB(&sblock); j++) {
186 if (itab[j].di_mode != 0)
187 pass3(&itab[j]);
188 ino++;
189 }
d9c5783d
KM
190 }
191 }
837c8ed5 192 (void) close(fi);
9570c66d 193 for (i = 0; i < hsize; i++)
61b11ef4
KM
194 htab[i].h_ino = 0;
195 for (i = iflg; i < NB; i++)
196 ilist[i].ino = 0;
197 nxfile = iflg;
d9c5783d
KM
198}
199
200pass1(ip)
20380c05 201 register struct dinode *ip;
d9c5783d 202{
61b11ef4
KM
203 int i;
204
205 if (mflg)
206 for (i = 0; i < iflg; i++)
207 if (ino == ilist[i].ino) {
208 ilist[i].mode = ip->di_mode;
209 ilist[i].uid = ip->di_uid;
210 ilist[i].gid = ip->di_gid;
211 }
212 if ((ip->di_mode & IFMT) != IFDIR) {
d9c5783d
KM
213 if (sflg==0 || nxfile>=NB)
214 return;
215 if ((ip->di_mode&IFMT)==IFBLK || (ip->di_mode&IFMT)==IFCHR
61b11ef4
KM
216 || ip->di_mode&(ISUID|ISGID)) {
217 ilist[nxfile].ino = ino;
218 ilist[nxfile].mode = ip->di_mode;
219 ilist[nxfile].uid = ip->di_uid;
220 ilist[nxfile++].gid = ip->di_gid;
d9c5783d 221 return;
61b11ef4 222 }
d9c5783d 223 }
837c8ed5 224 (void) lookup(ino, 1);
d9c5783d
KM
225}
226
227pass2(ip)
20380c05 228 register struct dinode *ip;
d9c5783d 229{
5086d197
KM
230 register struct direct *dp;
231 struct dirstuff dirp;
d9c5783d 232 struct htab *hp;
d9c5783d
KM
233
234 if((ip->di_mode&IFMT) != IFDIR)
235 return;
5086d197
KM
236 dirp.loc = 0;
237 dirp.ip = ip;
56d45dcd 238 gip = ip;
837c8ed5 239 for (dp = nreaddir(&dirp); dp != NULL; dp = nreaddir(&dirp)) {
5086d197
KM
240 if(dp->d_ino == 0)
241 continue;
242 hp = lookup(dp->d_ino, 0);
243 if(hp == 0)
244 continue;
245 if(dotname(dp))
246 continue;
247 hp->h_pino = ino;
248 hp->h_name = &strngtab[strngloc];
249 strngloc += strlen(dp->d_name) + 1;
837c8ed5 250 (void) strcpy(hp->h_name, dp->d_name);
d9c5783d
KM
251 }
252}
253
254pass3(ip)
20380c05 255 register struct dinode *ip;
d9c5783d 256{
5086d197
KM
257 register struct direct *dp;
258 struct dirstuff dirp;
d9c5783d 259 int k;
d9c5783d
KM
260
261 if((ip->di_mode&IFMT) != IFDIR)
262 return;
5086d197
KM
263 dirp.loc = 0;
264 dirp.ip = ip;
56d45dcd 265 gip = ip;
837c8ed5 266 for(dp = nreaddir(&dirp); dp != NULL; dp = nreaddir(&dirp)) {
5086d197
KM
267 if(aflg==0 && dotname(dp))
268 continue;
61b11ef4 269 if(sflg == 0 && iflg == 0)
5086d197 270 goto pr;
61b11ef4
KM
271 for(k = 0; ilist[k].ino != 0; k++)
272 if(ilist[k].ino == dp->d_ino)
273 break;
274 if (ilist[k].ino == 0)
275 continue;
276 if (mflg)
837c8ed5 277 (void) printf("mode %-6o uid %-5d gid %-5d ino ",
61b11ef4 278 ilist[k].mode, ilist[k].uid, ilist[k].gid);
5086d197 279 pr:
837c8ed5 280 (void) printf("%-5lu\t", dp->d_ino);
5086d197 281 pname(ino, 0);
837c8ed5 282 (void) printf("/%s", dp->d_name);
5086d197 283 if (lookup(dp->d_ino, 0))
837c8ed5
KM
284 (void) printf("/.");
285 (void) printf("\n");
5086d197
KM
286 }
287}
288
289/*
290 * get next entry in a directory.
291 */
292struct direct *
837c8ed5 293nreaddir(dirp)
5086d197
KM
294 register struct dirstuff *dirp;
295{
296 register struct direct *dp;
297 daddr_t lbn, d;
298
299 for(;;) {
300 if (dirp->loc >= dirp->ip->di_size)
301 return NULL;
43cc0ec7
KM
302 if (blkoff(&sblock, dirp->loc) == 0) {
303 lbn = lblkno(&sblock, dirp->loc);
5086d197
KM
304 d = bmap(lbn);
305 if(d == 0)
306 return NULL;
307 bread(fsbtodb(&sblock, d), dirp->dbuf,
308 dblksize(&sblock, dirp->ip, lbn));
d9c5783d 309 }
5086d197 310 dp = (struct direct *)
3352e84a 311 (dirp->dbuf + blkoff(&sblock, dirp->loc));
5086d197
KM
312 dirp->loc += dp->d_reclen;
313 if (dp->d_ino == 0)
314 continue;
315 return (dp);
d9c5783d
KM
316 }
317}
318
319dotname(dp)
20380c05 320 register struct direct *dp;
d9c5783d
KM
321{
322
323 if (dp->d_name[0]=='.')
5086d197
KM
324 if (dp->d_name[1]==0 ||
325 (dp->d_name[1]=='.' && dp->d_name[2]==0))
d9c5783d
KM
326 return(1);
327 return(0);
328}
329
330pname(i, lev)
20380c05
KM
331 ino_t i;
332 int lev;
d9c5783d
KM
333{
334 register struct htab *hp;
335
336 if (i==ROOTINO)
337 return;
338 if ((hp = lookup(i, 0)) == 0) {
837c8ed5 339 (void) printf("???");
d9c5783d
KM
340 return;
341 }
342 if (lev > 10) {
837c8ed5 343 (void) printf("...");
d9c5783d
KM
344 return;
345 }
346 pname(hp->h_pino, ++lev);
837c8ed5 347 (void) printf("/%s", hp->h_name);
d9c5783d
KM
348}
349
350struct htab *
351lookup(i, ef)
20380c05
KM
352 ino_t i;
353 int ef;
d9c5783d
KM
354{
355 register struct htab *hp;
356
9570c66d 357 for (hp = &htab[i%hsize]; hp->h_ino;) {
d9c5783d
KM
358 if (hp->h_ino==i)
359 return(hp);
9570c66d 360 if (++hp >= &htab[hsize])
d9c5783d
KM
361 hp = htab;
362 }
363 if (ef==0)
364 return(0);
9570c66d 365 if (++nhent >= hsize) {
837c8ed5
KM
366 (void) fprintf(stderr, "ncheck: hsize of %ld is too small\n",
367 hsize);
d9c5783d
KM
368 exit(1);
369 }
370 hp->h_ino = i;
371 return(hp);
372}
373
837c8ed5 374bread(bno, buf, lcount)
20380c05 375 daddr_t bno;
837c8ed5
KM
376 register char *buf;
377 long lcount;
d9c5783d 378{
837c8ed5
KM
379 register int i, cnt = lcount;
380 register off_t off = bno * dev_bsize;
d9c5783d 381
837c8ed5 382 (void) lseek(fi, off, 0);
d9c5783d 383 if (read(fi, buf, cnt) != cnt) {
837c8ed5
KM
384 (void) fprintf(stderr, "ncheck: read error %ld\n", bno);
385 if (cnt % dev_bsize) {
386 /* THIS INDICATES A SERIOUS BUG */
387 /* bzero is probably not correct, but will do */
388 (void) fprintf(stderr,
389 "ncheck: bread: cnt %d not multiple of %d\n",
390 cnt, dev_bsize);
391 bzero(buf, cnt);
392 return;
393 }
394 for (i = 0; i < cnt; i += dev_bsize) {
395 (void) lseek(fi, off, 0);
396 if (read(fi, buf, dev_bsize) != dev_bsize) {
397 (void) fprintf(stderr,
398 "ncheck: re-read error %ld\n", bno);
399 bzero(buf, dev_bsize);
400 }
401 off += dev_bsize;
402 buf += dev_bsize;
403 bno++;
404 }
d9c5783d
KM
405 }
406}
407
6a5c181e
KB
408/*
409 * Swiped from standalone sys.c.
410 */
411#define NBUFS 4
412char b[NBUFS][MAXBSIZE];
413daddr_t blknos[NBUFS];
414
d9c5783d 415daddr_t
6a5c181e
KB
416bmap(bn)
417 register daddr_t bn;
d9c5783d 418{
6a5c181e
KB
419 register int j;
420 int i, sh;
421 daddr_t nb, *bap;
422
423 if (bn < 0) {
837c8ed5 424 (void) fprintf(stderr, "ncheck: bn %ld negative\n", bn);
6a5c181e
KB
425 return ((daddr_t)0);
426 }
427
428 /*
429 * blocks 0..NDADDR are direct blocks
430 */
431 if(bn < NDADDR)
432 return(gip->di_db[bn]);
433
434 /*
435 * addresses NIADDR have single and double indirect blocks.
436 * the first step is to determine how many levels of indirection.
437 */
438 sh = 1;
439 bn -= NDADDR;
440 for (j = NIADDR; j > 0; j--) {
441 sh *= NINDIR(&sblock);
442 if (bn < sh)
443 break;
444 bn -= sh;
445 }
446 if (j == 0) {
837c8ed5 447 (void) printf("ncheck: bn %ld ovf, ino %lu\n", bn, ino);
6a5c181e
KB
448 return ((daddr_t)0);
449 }
450
451 /*
452 * fetch the first indirect block address from the inode
453 */
454 nb = gip->di_ib[NIADDR - j];
455 if (nb == 0) {
837c8ed5 456 (void) printf("ncheck: bn %ld void1, ino %lu\n", bn, ino);
6a5c181e
KB
457 return ((daddr_t)0);
458 }
459
460 /*
461 * fetch through the indirect blocks
462 */
463 for (; j <= NIADDR; j++) {
464 if (blknos[j] != nb) {
465 bread(fsbtodb(&sblock, nb), b[j], sblock.fs_bsize);
466 blknos[j] = nb;
467 }
468 bap = (daddr_t *)b[j];
469 sh /= NINDIR(&sblock);
470 i = (bn / sh) % NINDIR(&sblock);
471 nb = bap[i];
472 if(nb == 0) {
837c8ed5
KM
473 (void) printf("ncheck: bn %ld void2, ino %lu\n", bn,
474 ino);
6a5c181e
KB
475 return ((daddr_t)0);
476 }
d9c5783d 477 }
6a5c181e 478 return (nb);
d9c5783d 479}