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