|
|
1.1 ! root 1: /* ! 2: * Print a disc usage summary for ! 3: * some directories. ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <sys/types.h> ! 8: #include <sys/dir.h> ! 9: #include <sys/stat.h> ! 10: #include <sys/ino.h> ! 11: #include <errno.h> ! 12: ! 13: #define DIOSIZ (BUFSIZ/8) /* Size of directory i/o, until stacks grow */ ! 14: #define NLINK 500 /* Size of link table */ ! 15: #define NFNAME 1000 /* Size of filename */ ! 16: #define NRECUR 12 /* Depth of recursion < NFILE-3-2 */ ! 17: ! 18: int aflag; /* do files as well */ ! 19: int sflag; /* only give total */ ! 20: int depth; /* recursion depth */ ! 21: ! 22: struct linktab { ! 23: ino_t l_ino; ! 24: dev_t l_dev; ! 25: } linktab[NLINK]; ! 26: struct linktab *ltp; ! 27: ! 28: char fname[NFNAME]; ! 29: ! 30: char toodeep[] = "directory structure too deep to traverse"; ! 31: ! 32: struct stat sb; ! 33: ! 34: /* ! 35: * indirect block overhead based upon size of file ! 36: */ ! 37: long ranges[] = { ! 38: ND, /* direct blocks */ ! 39: ND + NBN, /* single indirect */ ! 40: ND + NBN*NBN, /* double indirect */ ! 41: ND + NBN*NBN*NBN /* tripple indirect */ ! 42: }; ! 43: ! 44: long duentry(); ! 45: long dufork(); ! 46: long dusize(); ! 47: char *buildname(); ! 48: void duerr(); ! 49: void dumsg(); ! 50: void usage(); ! 51: void main(); ! 52: ! 53: void ! 54: main(argc, argv) ! 55: char *argv[]; ! 56: { ! 57: register int i; ! 58: register char *ap; ! 59: int estat; ! 60: ! 61: while (argc>1 && *argv[1]=='-') { ! 62: for (ap = &argv[1][1]; *ap != '\0'; ap++) ! 63: switch (*ap) { ! 64: case 'a': ! 65: aflag = 1; ! 66: break; ! 67: ! 68: case 's': ! 69: sflag = 1; ! 70: break; ! 71: ! 72: default: ! 73: usage(); ! 74: } ! 75: argc--; ! 76: argv++; ! 77: } ! 78: if (argc < 2) ! 79: estat = du("."); ! 80: else { ! 81: estat = 0; ! 82: for (i=1; i<argc; i++) ! 83: estat |= du(argv[i]); ! 84: } ! 85: exit (estat); ! 86: } ! 87: ! 88: /* ! 89: * Print out disc usage summary ! 90: */ ! 91: du(name) ! 92: char *name; ! 93: { ! 94: register char *ep, *cp; ! 95: fsize_t size; ! 96: int nondir; ! 97: ! 98: ltp = linktab; ! 99: cp = name; ! 100: ep = fname; ! 101: while (*cp) ! 102: *ep++ = *cp++; ! 103: *ep = '\0'; ! 104: if (stat(name, &sb) < 0) ! 105: duerr("%s: nonexistent", name); ! 106: nondir = (sb.st_mode&S_IFMT) != S_IFDIR; ! 107: size = duentry(ep, &sb); ! 108: if (sflag || nondir) ! 109: printf("%ld\t%s\n", size, fname); ! 110: return (0); ! 111: } ! 112: ! 113: /* ! 114: * Do a du on a single entry ! 115: * The pointer is the end pointer ! 116: * into the fname buffer. ! 117: */ ! 118: long ! 119: duentry(ep, sbp) ! 120: char *ep; ! 121: struct stat *sbp; ! 122: { ! 123: extern int errno; ! 124: fsize_t total, fsize; ! 125: char iobuf[DIOSIZ]; ! 126: register char *np; ! 127: register struct direct *dp; ! 128: register int nb; ! 129: int fd; ! 130: int dirf; ! 131: ! 132: switch (sbp->st_mode & S_IFMT) { ! 133: case S_IFREG: ! 134: return (dusize(sbp)); ! 135: ! 136: case S_IFDIR: ! 137: total = dusize(sbp); ! 138: if (++depth >= NRECUR) { ! 139: depth = 0; ! 140: return (dufork(ep, sbp)); ! 141: } ! 142: if ((fd = open(fname, 0)) < 0) { ! 143: dumsg("cannot open `%s'", fname); ! 144: return (0); ! 145: } ! 146: while ((nb = read(fd, iobuf, DIOSIZ)) > 0) ! 147: for (dp = iobuf; dp < &iobuf[nb]; dp++) { ! 148: np = dp->d_name; ! 149: if (*np++=='.' ! 150: && (*np=='\0' || (*np++=='.' && *np=='\0'))) ! 151: continue; ! 152: if (dp->d_ino == 0) ! 153: continue; ! 154: if ((np = buildname(dp, ep)) == NULL) ! 155: continue; ! 156: if (stat(fname, &sb) < 0) { ! 157: dumsg("stat failed on `%s'", fname); ! 158: continue; ! 159: } ! 160: dirf = (sb.st_mode&S_IFMT)==S_IFDIR; ! 161: fsize = duentry(np, sbp); ! 162: if (aflag && !sflag && !dirf) ! 163: prsize(fsize); ! 164: total += fsize; ! 165: } ! 166: if (nb < 0) ! 167: dumsg("%s: directory read error", fname); ! 168: close(fd); ! 169: *ep = '\0'; ! 170: if (!sflag) ! 171: prsize(total); ! 172: --depth; ! 173: return (total); ! 174: ! 175: default: ! 176: return (0); ! 177: } ! 178: } ! 179: ! 180: /* ! 181: * Fork to do a du on recursive directory ! 182: * structure that is too deep to fit into ! 183: * user's open files. ! 184: */ ! 185: long ! 186: dufork(ep, sbp) ! 187: char *ep; ! 188: struct stat *sbp; ! 189: { ! 190: register int i; ! 191: register int pid; ! 192: int pfd[2] = {0, 0}; ! 193: int status; ! 194: long sz = 0; ! 195: ! 196: fflush(stdout); ! 197: if (pipe(pfd)<0 || (pid = fork())<0) { ! 198: if (pfd[0]) { ! 199: close(pfd[0]); ! 200: close(pfd[1]); ! 201: } ! 202: dumsg(toodeep); ! 203: return (0); ! 204: } ! 205: if (pid) { ! 206: close(pfd[1]); ! 207: while (wait(&status) >= 0) ! 208: ; ! 209: if (status || read(pfd[0], &sz, sizeof(long)) != sizeof(long)) ! 210: sz = 0; ! 211: close(pfd[0]); ! 212: return (sz); ! 213: } ! 214: for (i=3; i<_NFILE; i++) ! 215: if (i != pfd[1]) ! 216: close(i); ! 217: sz = duentry(ep, sbp); ! 218: write(pfd[1], &sz, sizeof(long)); ! 219: close(pfd[1]); ! 220: exit(0); ! 221: } ! 222: ! 223: /* ! 224: * Do a du on a single file. ! 225: * Now takes into account indirect blocks. ! 226: */ ! 227: long ! 228: dusize(sbp) ! 229: struct stat *sbp; ! 230: { ! 231: register int i; ! 232: register long blocks; ! 233: ! 234: if ((sbp->st_mode & S_IFMT) != S_IFDIR ! 235: && sbp->st_nlink > 1 ! 236: && addlink(sbp->st_dev, sbp->st_ino)) ! 237: return (0); ! 238: blocks = (sbp->st_size+BUFSIZ-1) / BUFSIZ; ! 239: for (i = 0; i < sizeof(ranges)/sizeof(ranges[0]); ++i) ! 240: if (blocks <= ranges[i]) ! 241: break; ! 242: return (blocks + i); ! 243: } ! 244: ! 245: /* ! 246: * Print out a size line. ! 247: */ ! 248: prsize(blocks) ! 249: fsize_t blocks; ! 250: { ! 251: printf("%ld\t%s\n", blocks, fname); ! 252: } ! 253: ! 254: /* ! 255: * Build up the next entry ! 256: * in the name. ! 257: */ ! 258: char * ! 259: buildname(dp, ep) ! 260: struct direct *dp; ! 261: register char *ep; ! 262: { ! 263: register char *cp = dp->d_name; ! 264: register unsigned n = DIRSIZ; ! 265: ! 266: if (ep+DIRSIZ+2 >= &fname[NFNAME]) { ! 267: dumsg(toodeep); ! 268: return (NULL); ! 269: } ! 270: if (ep[-1] != '/') ! 271: *ep++ = '/'; ! 272: do { ! 273: if (*cp == '\0') ! 274: break; ! 275: *ep++ = *cp++; ! 276: } while (--n); ! 277: *ep = '\0'; ! 278: return (ep); ! 279: } ! 280: ! 281: /* ! 282: * Add an entry to the table ! 283: * of i-numbers with multiple links. ! 284: * If there are too many multi-link files, ! 285: * they will get counted twice. ! 286: * Return 1 if already there. ! 287: */ ! 288: addlink(dev, ino) ! 289: register dev_t dev; ! 290: register ino_t ino; ! 291: { ! 292: register struct linktab *lp; ! 293: ! 294: for (lp = linktab; lp<ltp; lp++) ! 295: if (lp->l_ino==ino && lp->l_dev==dev) ! 296: return (1); ! 297: if (lp-linktab >= NLINK) ! 298: return (0); ! 299: lp->l_ino = ino; ! 300: lp->l_dev = dev; ! 301: ltp++; ! 302: return (0); ! 303: } ! 304: ! 305: void ! 306: usage() ! 307: { ! 308: fprintf(stderr, "Usage: du [-s] [name ...]\n"); ! 309: exit(1); ! 310: } ! 311: ! 312: /* VARARGS */ ! 313: void ! 314: duerr(x) ! 315: { ! 316: fprintf(stderr, "du: %r\n", &x); ! 317: exit (1); ! 318: } ! 319: ! 320: /* VARARGS */ ! 321: void ! 322: dumsg(x) ! 323: { ! 324: fprintf(stderr, "du: %r\n", &x); ! 325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.