symbolic links take on user ownership of their containing directory
[unix-history] / usr / src / sbin / ncheck / ncheck.c
index 570288a..32cc434 100644 (file)
@@ -1,48 +1,81 @@
-static char *sccsid = "@(#)ncheck.c    1.6 (Berkeley) %G%";
+/*-
+ * Copyright (c) 1988, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.proprietary.c%
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ncheck.c   5.18 (Berkeley) %G%";
+#endif /* not lint */
+
 /*
  * ncheck -- obtain file names from reading filesystem
  */
 
 #define        NB              500
 /*
  * ncheck -- obtain file names from reading filesystem
  */
 
 #define        NB              500
-#define        HSIZE           2503
-#define        NDIR(fs)        ((fs)->fs_bsize/sizeof(struct direct))
-#define        MAXNDIR         (MAXBSIZE/sizeof(struct direct))
 #define        MAXNINDIR       (MAXBSIZE / sizeof (daddr_t))
 
 #define        MAXNINDIR       (MAXBSIZE / sizeof (daddr_t))
 
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/time.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
 #include <stdio.h>
 #include <stdio.h>
-#include "../h/param.h"
-#include "../h/inode.h"
-#include "../h/dir.h"
-#include "../h/fs.h"
-
-struct fs      sblock;
-struct dinode  itab[MAXIPG];
-struct         dinode  *gip;
-ino_t  ilist[NB];
+
+struct fs      *sblockp;
+struct dinode  itab[MAXBSIZE/sizeof(struct dinode)];
+struct dinode  *gip;
+struct ilist {
+       ino_t   ino;
+       u_short mode;
+       short   uid;
+       short   gid;
+} ilist[NB];
 struct htab
 {
        ino_t   h_ino;
        ino_t   h_pino;
 struct htab
 {
        ino_t   h_ino;
        ino_t   h_pino;
-       char    h_name[DIRSIZ];
-} htab[HSIZE];
+       char    *h_name;
+} *htab;
+char *strngtab;
+long hsize;
+int strngloc;
+
+struct dirstuff {
+       int loc;
+       struct dinode *ip;
+       char dbuf[MAXBSIZE];
+};
 
 int    aflg;
 int    sflg;
 
 int    aflg;
 int    sflg;
+int    iflg; /* number of inodes being searched for */
+int    mflg;
 int    fi;
 ino_t  ino;
 int    nhent;
 int    nxfile;
 int    fi;
 ino_t  ino;
 int    nhent;
 int    nxfile;
+int    dev_bsize = 1;
 
 int    nerror;
 daddr_t        bmap();
 long   atol();
 
 int    nerror;
 daddr_t        bmap();
 long   atol();
+char   *malloc(), *strcpy();
 struct htab *lookup();
 struct htab *lookup();
+struct direct *nreaddir();
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
-       register i;
        long n;
 
        while (--argc) {
        long n;
 
        while (--argc) {
@@ -55,23 +88,28 @@ main(argc, argv)
                        continue;
 
                case 'i':
                        continue;
 
                case 'i':
-                       for(i=0; i<NB; i++) {
+                       for(iflg=0; iflg<NB && argc >= 2; iflg++) {
                                n = atol(argv[1]);
                                if(n == 0)
                                        break;
                                n = atol(argv[1]);
                                if(n == 0)
                                        break;
-                               ilist[i] = n;
-                               nxfile = i;
+                               ilist[iflg].ino = n;
+                               nxfile = iflg;
                                argv++;
                                argc--;
                        }
                        continue;
 
                                argv++;
                                argc--;
                        }
                        continue;
 
+               case 'm':
+                       mflg++;
+                       continue;
+
                case 's':
                        sflg++;
                        continue;
 
                default:
                case 's':
                        sflg++;
                        continue;
 
                default:
-                       fprintf(stderr, "ncheck: bad flag %c\n", (*argv)[1]);
+                       (void) fprintf(stderr, "ncheck: bad flag %c\n",
+                           (*argv)[1]);
                        nerror++;
                }
                check(*argv);
                        nerror++;
                }
                check(*argv);
@@ -83,163 +121,206 @@ check(file)
        char *file;
 {
        register int i, j, c;
        char *file;
 {
        register int i, j, c;
-       int nfiles;
 
        fi = open(file, 0);
        if(fi < 0) {
 
        fi = open(file, 0);
        if(fi < 0) {
-               fprintf(stderr, "ncheck: cannot open %s\n", file);
+               (void) fprintf(stderr, "ncheck: cannot open %s\n", file);
                nerror++;
                return;
        }
        nhent = 0;
                nerror++;
                return;
        }
        nhent = 0;
-       printf("%s:\n", file);
+       (void) printf("%s:\n", file);
        sync();
        sync();
-       bread(SBLOCK, (char *)&sblock, SBSIZE);
-       if (sblock.fs_magic != FS_MAGIC) {
-               printf("%s: not a file system\n", file);
+       dev_bsize = 1;
+       sblockp = (struct fs *)malloc((unsigned)SBSIZE);
+       if (sblockp == 0) {
+               (void) printf("icheck: couldn't malloc superblock memory\n");
                nerror++;
                return;
        }
                nerror++;
                return;
        }
-       nfiles = sblock.fs_ipg * sblock.fs_ncg;
-       if (nfiles > 65535) {
-               printf("%s: %d is a preposterous number of files\n",
-                   file, nfiles);
+       bread((daddr_t)SBOFF, (char *)sblockp, (long)SBSIZE);
+       if (sblockp->fs_magic != FS_MAGIC) {
+               (void) printf("%s: not a file system\n", file);
+               nerror++;
+               return;
+       }
+       dev_bsize = sblockp->fs_fsize / fsbtodb(sblockp, 1);
+       hsize = sblockp->fs_ipg * sblockp->fs_ncg -
+           sblockp->fs_cstotal.cs_nifree + 1;
+       htab = (struct htab *)malloc((unsigned)hsize * sizeof(struct htab));
+       strngtab = malloc((unsigned)(30 * hsize));
+       if (htab == 0 || strngtab == 0) {
+               (void) printf("not enough memory to allocate tables\n");
                nerror++;
                return;
        }
        ino = 0;
                nerror++;
                return;
        }
        ino = 0;
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
-                   sblock.fs_ipg * sizeof (struct dinode));
-               for(j=0; j<sblock.fs_ipg; j++) {
-                       pass1(&itab[j]);
-                       ino++;
+       for (c = 0; c < sblockp->fs_ncg; c++) {
+               for (i = 0;
+                    i < sblockp->fs_ipg / INOPF(sblockp);
+                    i += sblockp->fs_frag) {
+                       bread(fsbtodb(sblockp, cgimin(sblockp, c) + i),
+                           (char *)itab, sblockp->fs_bsize);
+                       for (j = 0; j < INOPB(sblockp); j++) {
+                               if (itab[j].di_mode != 0)
+                                       pass1(&itab[j]);
+                               ino++;
+                       }
                }
        }
                }
        }
-       ilist[nxfile+1] = 0;
+       ilist[nxfile+1].ino = 0;
        ino = 0;
        ino = 0;
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
-                   sblock.fs_ipg * sizeof (struct dinode));
-               for(j=0; j<sblock.fs_ipg; j++) {
-                       pass2(&itab[j]);
-                       ino++;
+       for (c = 0; c < sblockp->fs_ncg; c++) {
+               for (i = 0;
+                    i < sblockp->fs_ipg / INOPF(sblockp);
+                    i += sblockp->fs_frag) {
+                       bread(fsbtodb(sblockp, cgimin(sblockp, c) + i),
+                           (char *)itab, sblockp->fs_bsize);
+                       for (j = 0; j < INOPB(sblockp); j++) {
+                               if (itab[j].di_mode != 0)
+                                       pass2(&itab[j]);
+                               ino++;
+                       }
                }
        }
        ino = 0;
                }
        }
        ino = 0;
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
-                   sblock.fs_ipg * sizeof (struct dinode));
-               for(j=0; j<sblock.fs_ipg; j++) {
-                       pass3(&itab[j]);
-                       ino++;
+       for (c = 0; c < sblockp->fs_ncg; c++) {
+               for (i = 0;
+                    i < sblockp->fs_ipg / INOPF(sblockp);
+                    i += sblockp->fs_frag) {
+                       bread(fsbtodb(sblockp, cgimin(sblockp, c) + i),
+                           (char *)itab, sblockp->fs_bsize);
+                       for (j = 0; j < INOPB(sblockp); j++) {
+                               if (itab[j].di_mode != 0)
+                                       pass3(&itab[j]);
+                               ino++;
+                       }
                }
        }
                }
        }
+       (void) close(fi);
+       for (i = 0; i < hsize; i++)
+               htab[i].h_ino = 0;
+       for (i = iflg; i < NB; i++)
+               ilist[i].ino = 0;
+       nxfile = iflg;
 }
 
 pass1(ip)
        register struct dinode *ip;
 {
 }
 
 pass1(ip)
        register struct dinode *ip;
 {
-       if((ip->di_mode & IFMT) != IFDIR) {
+       int i;
+
+       if (mflg)
+               for (i = 0; i < iflg; i++)
+                       if (ino == ilist[i].ino) {
+                               ilist[i].mode = ip->di_mode;
+                               ilist[i].uid = ip->di_uid;
+                               ilist[i].gid = ip->di_gid;
+                       }
+       if ((ip->di_mode & IFMT) != IFDIR) {
                if (sflg==0 || nxfile>=NB)
                        return;
                if ((ip->di_mode&IFMT)==IFBLK || (ip->di_mode&IFMT)==IFCHR
                if (sflg==0 || nxfile>=NB)
                        return;
                if ((ip->di_mode&IFMT)==IFBLK || (ip->di_mode&IFMT)==IFCHR
-                 || ip->di_mode&(ISUID|ISGID))
-                       ilist[nxfile++] = ino;
+                 || ip->di_mode&(ISUID|ISGID)) {
+                       ilist[nxfile].ino = ino;
+                       ilist[nxfile].mode = ip->di_mode;
+                       ilist[nxfile].uid = ip->di_uid;
+                       ilist[nxfile++].gid = ip->di_gid;
                        return;
                        return;
+               }
        }
        }
-       lookup(ino, 1);
+       (void) lookup(ino, 1);
 }
 
 pass2(ip)
        register struct dinode *ip;
 {
 }
 
 pass2(ip)
        register struct dinode *ip;
 {
-       struct direct dbuf[MAXNDIR];
-       long doff;
-       struct direct *dp;
-       register i, j;
-       int k;
+       register struct direct *dp;
+       struct dirstuff dirp;
        struct htab *hp;
        struct htab *hp;
-       daddr_t d;
-       ino_t kno;
 
        if((ip->di_mode&IFMT) != IFDIR)
                return;
 
        if((ip->di_mode&IFMT) != IFDIR)
                return;
+       dirp.loc = 0;
+       dirp.ip = ip;
        gip = ip;
        gip = ip;
-       doff = 0;
-       for(i=0;; i++) {
-               if(doff >= ip->di_size)
-                       break;
-               d = bmap(i);
-               if(d == 0)
-                       break;
-               bread(fsbtodb(&sblock, d), (char *)dbuf, sizeof(dbuf));
-               for(j=0; j < NDIR(&sblock); j++) {
-                       if(doff >= ip->di_size)
-                               break;
-                       doff += sizeof(struct direct);
-                       dp = dbuf+j;
-                       kno = dp->d_ino;
-                       if(kno == 0)
-                               continue;
-                       hp = lookup(kno, 0);
-                       if(hp == 0)
-                               continue;
-                       if(dotname(dp))
-                               continue;
-                       hp->h_pino = ino;
-                       for(k=0; k<DIRSIZ; k++)
-                               hp->h_name[k] = dp->d_name[k];
-               }
+       for (dp = nreaddir(&dirp); dp != NULL; dp = nreaddir(&dirp)) {
+               if(dp->d_ino == 0)
+                       continue;
+               hp = lookup(dp->d_ino, 0);
+               if(hp == 0)
+                       continue;
+               if(dotname(dp))
+                       continue;
+               hp->h_pino = ino;
+               hp->h_name = &strngtab[strngloc];
+               strngloc += strlen(dp->d_name) + 1;
+               (void) strcpy(hp->h_name, dp->d_name);
        }
 }
 
 pass3(ip)
        register struct dinode *ip;
 {
        }
 }
 
 pass3(ip)
        register struct dinode *ip;
 {
-       struct direct dbuf[MAXNDIR];
-       long doff;
-       struct direct *dp;
-       register i, j;
+       register struct direct *dp;
+       struct dirstuff dirp;
        int k;
        int k;
-       daddr_t d;
-       ino_t kno;
 
        if((ip->di_mode&IFMT) != IFDIR)
                return;
 
        if((ip->di_mode&IFMT) != IFDIR)
                return;
+       dirp.loc = 0;
+       dirp.ip = ip;
        gip = ip;
        gip = ip;
-       doff = 0;
-       for(i=0;; i++) {
-               if(doff >= ip->di_size)
-                       break;
-               d = bmap(i);
-               if(d == 0)
-                       break;
-               bread(fsbtodb(&sblock, d), (char *)dbuf, sizeof(dbuf));
-               for(j=0; j < NDIR(&sblock); j++) {
-                       if(doff >= ip->di_size)
+       for(dp = nreaddir(&dirp); dp != NULL; dp = nreaddir(&dirp)) {
+               if(aflg==0 && dotname(dp))
+                       continue;
+               if(sflg == 0 && iflg == 0)
+                       goto pr;
+               for(k = 0; ilist[k].ino != 0; k++)
+                       if(ilist[k].ino == dp->d_ino)
                                break;
                                break;
-                       doff += sizeof(struct direct);
-                       dp = dbuf+j;
-                       kno = dp->d_ino;
-                       if(kno == 0)
-                               continue;
-                       if(aflg==0 && dotname(dp))
-                               continue;
-                       if(ilist[0] == 0)
-                               goto pr;
-                       for(k=0; ilist[k] != 0; k++)
-                               if(ilist[k] == kno)
-                                       goto pr;
+               if (ilist[k].ino == 0)
                        continue;
                        continue;
-               pr:
-                       printf("%u      ", kno);
-                       pname(ino, 0);
-                       printf("/%.14s", dp->d_name);
-                       if (lookup(kno, 0))
-                               printf("/.");
-                       printf("\n");
+               if (mflg)
+                       (void) printf("mode %-6o uid %-5d gid %-5d ino ",
+                           ilist[k].mode, ilist[k].uid, ilist[k].gid);
+       pr:
+               (void) printf("%-5lu\t", dp->d_ino);
+               pname(ino, 0);
+               (void) printf("/%s", dp->d_name);
+               if (lookup(dp->d_ino, 0))
+                       (void) printf("/.");
+               (void) printf("\n");
+       }
+}
+
+/*
+ * get next entry in a directory.
+ */
+struct direct *
+nreaddir(dirp)
+       register struct dirstuff *dirp;
+{
+       register struct direct *dp;
+       daddr_t lbn, d;
+
+       for(;;) {
+               if (dirp->loc >= dirp->ip->di_size)
+                       return NULL;
+               if (blkoff(sblockp, dirp->loc) == 0) {
+                       lbn = lblkno(sblockp, dirp->loc);
+                       d = bmap(lbn);
+                       if(d == 0)
+                               return NULL;
+                       bread(fsbtodb(sblockp, d), dirp->dbuf,
+                             (long)dblksize(sblockp, dirp->ip, lbn));
                }
                }
+               dp = (struct direct *)
+                   (dirp->dbuf + blkoff(sblockp, dirp->loc));
+               dirp->loc += dp->d_reclen;
+               if (dp->d_ino == 0)
+                       continue;
+               return (dp);
        }
 }
 
        }
 }
 
@@ -248,7 +329,8 @@ dotname(dp)
 {
 
        if (dp->d_name[0]=='.')
 {
 
        if (dp->d_name[0]=='.')
-               if (dp->d_name[1]==0 || (dp->d_name[1]=='.' && dp->d_name[2]==0))
+               if (dp->d_name[1]==0 ||
+                  (dp->d_name[1]=='.' && dp->d_name[2]==0))
                        return(1);
        return(0);
 }
                        return(1);
        return(0);
 }
@@ -262,15 +344,15 @@ pname(i, lev)
        if (i==ROOTINO)
                return;
        if ((hp = lookup(i, 0)) == 0) {
        if (i==ROOTINO)
                return;
        if ((hp = lookup(i, 0)) == 0) {
-               printf("???");
+               (void) printf("???");
                return;
        }
        if (lev > 10) {
                return;
        }
        if (lev > 10) {
-               printf("...");
+               (void) printf("...");
                return;
        }
        pname(hp->h_pino, ++lev);
                return;
        }
        pname(hp->h_pino, ++lev);
-       printf("/%.14s", hp->h_name);
+       (void) printf("/%s", hp->h_name);
 }
 
 struct htab *
 }
 
 struct htab *
@@ -280,50 +362,126 @@ lookup(i, ef)
 {
        register struct htab *hp;
 
 {
        register struct htab *hp;
 
-       for (hp = &htab[i%HSIZE]; hp->h_ino;) {
+       for (hp = &htab[i%hsize]; hp->h_ino;) {
                if (hp->h_ino==i)
                        return(hp);
                if (hp->h_ino==i)
                        return(hp);
-               if (++hp >= &htab[HSIZE])
+               if (++hp >= &htab[hsize])
                        hp = htab;
        }
        if (ef==0)
                return(0);
                        hp = htab;
        }
        if (ef==0)
                return(0);
-       if (++nhent >= HSIZE) {
-               fprintf(stderr, "ncheck: out of core-- increase HSIZE\n");
+       if (++nhent >= hsize) {
+               (void) fprintf(stderr, "ncheck: hsize of %ld is too small\n",
+                   hsize);
                exit(1);
        }
        hp->h_ino = i;
        return(hp);
 }
 
                exit(1);
        }
        hp->h_ino = i;
        return(hp);
 }
 
-bread(bno, buf, cnt)
+bread(bno, buf, lcount)
        daddr_t bno;
        daddr_t bno;
-       char *buf;
-       int cnt;
+       register char *buf;
+       long lcount;
 {
 {
-       register i;
+       register int i, cnt = lcount;
+       register off_t off = bno * dev_bsize;
 
 
-       lseek(fi, bno * DEV_BSIZE, 0);
+       (void) lseek(fi, off, SEEK_SET);
        if (read(fi, buf, cnt) != cnt) {
        if (read(fi, buf, cnt) != cnt) {
-               fprintf(stderr, "ncheck: read error %d\n", bno);
-               for(i=0; i < cnt; i++)
-                       buf[i] = 0;
+               (void) fprintf(stderr, "ncheck: read error %ld\n", bno);
+               if (cnt % dev_bsize) {
+                       /* THIS INDICATES A SERIOUS BUG */
+                       /* bzero is probably not correct, but will do */
+                       (void) fprintf(stderr,
+                           "ncheck: bread: cnt %d not multiple of %d\n",
+                           cnt, dev_bsize);
+                       bzero(buf, cnt);
+                       return;
+               }
+               for (i = 0; i < cnt; i += dev_bsize) {
+                       (void) lseek(fi, off, SEEK_SET);
+                       if (read(fi, buf, dev_bsize) != dev_bsize) {
+                               (void) fprintf(stderr,
+                                   "ncheck: re-read error %ld\n", bno);
+                               bzero(buf, dev_bsize);
+                       }
+                       off += dev_bsize;
+                       buf += dev_bsize;
+                       bno++;
+               }
        }
 }
 
        }
 }
 
+/*
+ * Swiped from standalone sys.c.
+ */
+#define        NBUFS   4
+char   b[NBUFS][MAXBSIZE];
+daddr_t        blknos[NBUFS];
+
 daddr_t
 daddr_t
-bmap(i)
-       int i;
+bmap(bn)
+       register daddr_t bn;
 {
 {
-       daddr_t ibuf[MAXNINDIR];
-
-       if(i < NDADDR)
-               return(gip->di_db[i]);
-       i -= NDADDR;
-       if(i > NINDIR(&sblock)) {
-               fprintf(stderr, "ncheck: %u - huge directory\n", ino);
-               return((daddr_t)0);
+       register int j;
+       int i, sh;
+       daddr_t nb, *bap;
+
+       if (bn < 0) {
+               (void) fprintf(stderr, "ncheck: bn %ld negative\n", bn);
+               return ((daddr_t)0);
+       }
+
+       /*
+        * blocks 0..NDADDR are direct blocks
+        */
+       if(bn < NDADDR)
+               return(gip->di_db[bn]);
+
+       /*
+        * addresses NIADDR have single and double indirect blocks.
+        * the first step is to determine how many levels of indirection.
+        */
+       sh = 1;
+       bn -= NDADDR;
+       for (j = NIADDR; j > 0; j--) {
+               sh *= NINDIR(sblockp);
+               if (bn < sh)
+                       break;
+               bn -= sh;
+       }
+       if (j == 0) {
+               (void) printf("ncheck: bn %ld ovf, ino %lu\n", bn, ino);
+               return ((daddr_t)0);
+       }
+
+       /*
+        * fetch the first indirect block address from the inode
+        */
+       nb = gip->di_ib[NIADDR - j];
+       if (nb == 0) {
+               (void) printf("ncheck: bn %ld void1, ino %lu\n", bn, ino);
+               return ((daddr_t)0);
+       }
+
+       /*
+        * fetch through the indirect blocks
+        */
+       for (; j <= NIADDR; j++) {
+               if (blknos[j] != nb) {
+                       bread(fsbtodb(sblockp, nb), b[j], sblockp->fs_bsize);
+                       blknos[j] = nb;
+               }
+               bap = (daddr_t *)b[j];
+               sh /= NINDIR(sblockp);
+               i = (bn / sh) % NINDIR(sblockp);
+               nb = bap[i];
+               if(nb == 0) {
+                       (void) printf("ncheck: bn %ld void2, ino %lu\n", bn,
+                           ino);
+                       return ((daddr_t)0);
+               }
        }
        }
-       bread(fsbtodb(&sblock, gip->di_ib[i]), (char *)ibuf, sizeof(ibuf));
-       return(ibuf[i]);
+       return (nb);
 }
 }