/* fsdiruse.c */ /* */ /* Author: John Pfuntner / Tom Sirc */ /* Program: fsdiruse */ /* Version: 1.1 */ /* */ /* Purpose: Display the usage within a filesystem */ /* with a breakdown of the usage in the subdirectories. */ /* */ /* Syntax: fsdiruse [-i] [-v] [dir ... ] */ /* */ /* Modified from John Pfuntner's dirsize program to add */ /* - summary of usage within first level subdirectories*/ /* - Uses lstat() instead of stat() so it won't try to */ /* follow symlinks */ /* - checks that subdirectory is within same */ /* filesystem (not a mountpoint) */ /* - Reports counts of subdirectories, other */ /* non-directory and non-regular file types */ /* */ #/* Copyright 1994, 2000, IBM Corporation and Tivoli Systems # * All rights reserved # * # * Distribute freely, except: don't remove my name from the source or # * documentation (don't take credit for my work), mark your changes # * (don't get me blamed for your possible bugs), don't alter or # * remove this notice. No fee may be charged if you distribute the # * package (except for such things as the price of a disk or tape, # * postage, etc.). No warranty of any kind, express or implied, is # * included with this software; use at your own risk, responsibility # * for damages (if any) to anyone resulting from the use of this # * software rests entirely with the user. # * # * Send me bug reports, bug fixes, enhancements, requests, flames, # * etc. I can be reached as follows: # * # * John Pfuntner John_Pfuntner@tivoli.com # */ /* */ /* Author: John Pfuntner */ /* Program: dirsize */ /* Version: 1.1 */ /* */ /* Purpose: Display contents of a directory or */ /* directories, showing subdirectory structure and the */ /* number of bytes in each directory. */ /* */ /* Syntax: dirsize [-i] [-v] [dir ... ] */ /* */ #define _POSIX_SOURCE #define _XOPEN_SOURCE_EXTENDED 1 #include #include #include #include #include #include #define true 1 #define false 0 int verbose=false; int ignoreMissingSymlinks=false; double files, dirs=0; double blkfiles, chrfiles=0; double extlnks, fifofiles=0; double symlnks, sockets=0; double mntpoints=0; double total_files, total_dirs=0; double total_blkfiles, total_chrfiles=0; double total_extlnks, total_fifofiles=0; double total_symlnks, total_sockets=0; double total_mntpoints=0; int fsid; struct uniq { dev_t dev; ino_t node; struct uniq *next; } *uniques=NULL; void unique_init() { struct uniq *temp; while (uniques != NULL) { temp = uniques; uniques = uniques->next; free(temp); } } int unique(struct stat Stat) { struct uniq *temp; /* have we counted this file before? */ for (temp = uniques; temp != NULL; temp = temp->next) if ((Stat.st_dev == temp->dev) && (Stat.st_ino == temp->node)) return false; /* not unique */ /* unique */ if (verbose) printf("inode %d (dev %d) is unique %d\n", Stat.st_ino, Stat.st_dev, Stat.st_size); temp = (struct uniq*) malloc(sizeof(struct uniq)); temp->next = uniques; temp->dev = Stat.st_dev; temp->node = Stat.st_ino; uniques = temp; return true; } int ignore(char *dir, char *file) { struct stat Stat; char *name; int ret; if (!ignoreMissingSymlinks) return false; strcpy(name=(char*)malloc(strlen(dir)+strlen(file)+2), dir); strcat(name, "/"); strcat(name, file); ret = lstat(name, &Stat); free(name); return ((ret == 0) && (S_ISLNK(Stat.st_mode))); } int get_stat(char *dir, char *file, struct stat *Stat) { char *name; int ret; strcpy(name=(char*)malloc(strlen(dir)+strlen(file)+2), dir); strcat(name, "/"); strcat(name, file); /* ret = lstat(name, Stat); */ ret = lstat(name, Stat); free(name); return ret; } double traverse(char *pref, char *suff, int depth) { DIR *stream; struct dirent *dirent; struct stat Stat; char *dir, *newname; double temp, ret, subdirbytes; int done, i; if (strlen(suff) > 0) { dir = (char*) malloc(strlen(pref)+strlen(suff)+2); if (strcmp(pref, "/") == 0) strcpy(dir, ""); else strcpy(dir, pref); strcat(dir, "/"); strcat(dir, suff); } else { dir = pref; unique_init(); } ret = 0; if ((stream = opendir(dir)) == NULL) { if ((errno == EACCES) || (errno == EPERM)) fprintf(stderr, "cannot access %s\n", dir); else { fprintf(stderr, "opendir() error for %s: %s\n", dir, strerror(errno)); ret = -1; } } errno = 0; if (stream != NULL) { /* do subdirectories first */ done = false; while ((!done) && (ret != -1)) { errno = 0; if ((dirent = readdir(stream)) == NULL) { if (errno == 0) done = true; else if ((errno == EACCES) || (errno == EPERM)) fprintf(stderr, "readdir() cannot access entry in %s\n", dir); else { fprintf(stderr, "readdir() error in %s directory: %s\n", dir, strerror(errno)); ret = -1; done = true; } } else { errno = 0; if (get_stat(dir, dirent->d_name, &Stat) != 0) { if (!ignore(dir, dirent->d_name)) { fprintf(stderr, "stat() error for %s/%s: %s\n", dir, dirent->d_name, strerror(errno)); ret = -1; done = true; } } /* else if (S_ISDIR(Stat.st_mode)) { */ else if (S_ISDIR(Stat.st_mode) && (!S_ISLNK(Stat.st_mode))) { if ((strcmp(dirent->d_name, ".") != 0) && (strcmp(dirent->d_name, "..") != 0)) { if ((int)Stat.st_dev == fsid) { if ((temp = traverse(dir, dirent->d_name, depth+1)) == -1) { ret = -1; done = true; } else { ret += temp; if (verbose) printf("traverse dir (%s) now %.0f dirs: %.0f\n", dir, ret, dirs); } } else { if (verbose) printf("Directory %s %s (fsid: %d) is not in the same device as base directory (fsid: %d) \n", dir, dirent->d_name, Stat.st_dev, fsid); mntpoints++; } } } } } if (ret != -1) { /* now go back and pick up remaining files we haven't seen yet */ if (depth == 0) { subdirbytes = ret; /* printf("subdirbytes: %.0f %s\n", ret, dir); */ } rewinddir(stream); done = false; while ((!done) && (ret != -1)) { errno = 0; if ((dirent = readdir(stream)) == NULL) { if (errno == 0) done = true; else if ((errno != EACCES) && (errno != EPERM)) { fprintf(stderr, "readdir() error in %s directory: %s\n", dir, strerror(errno)); ret = -1; done = true; } } else { errno = 0; if (get_stat(dir, dirent->d_name, &Stat) != 0) { if (!ignore(dir, dirent->d_name)) { fprintf(stderr, "stat() error for %s/%s: %s\n", dir, dirent->d_name, strerror(errno)); ret = -1; done = true; } } /* else if ((!S_ISDIR(Stat.st_mode)) && unique(Stat)) { */ else if ((S_ISREG(Stat.st_mode)) && unique(Stat)) { files++; ret += Stat.st_size; if (verbose) printf("traverse(%s) now %.0f files: %.0f\n", dir, ret, files); } else { if (S_ISBLK(Stat.st_mode)) blkfiles++; else if (S_ISCHR(Stat.st_mode)) chrfiles++; /* else if (S_ISEXTL(Stat.st_mode)) extlnks++; */ else if (S_ISFIFO(Stat.st_mode)) fifofiles++; else if (S_ISLNK(Stat.st_mode)) symlnks++; else if (S_ISSOCK(Stat.st_mode)) sockets++; } } } } } if ((stream != NULL) && (closedir(stream) != 0) && (ret != -1)) { fprintf(stderr, "closedir() error for %s: %s\n", dir, strerror(errno)); return -1; } /* if (ret != -1) { for (i=0; i 0) { printf("---------- ---------- ---------- ------------------------------\n"); } printf("%10.0f %10.0f %10.0f in subdirectories \n", subdirbytes, total_dirs, total_files); printf("%10.0f %10.0f not in subdirectories \n", (ret - subdirbytes), files); /* Add those not in a subdirectory to the totals */ total_files += files; total_dirs += dirs; total_blkfiles += blkfiles; total_chrfiles += chrfiles; total_extlnks += extlnks; total_fifofiles += fifofiles; total_symlnks += symlnks; total_sockets += sockets; total_mntpoints += mntpoints; /* Print overall totals */ printf("%10.0f %10.0f %10.0f total \n", ret, total_dirs, total_files); printf("\n"); printf("block spc char spc ext links pipes/fifo symlinks sockets \n"); printf("---------- ---------- ---------- ---------- ---------- ---------- \n"); printf("%10.0f %10.0f %10.0f %10.0f %10.0f %10.0f \n", total_blkfiles, total_chrfiles, total_extlnks, total_fifofiles, total_symlnks, total_sockets); printf("\n"); /* printf("%10.0f filesystems mounted off or under this directory not counted \n", total_mntpoints); */ } } if (strlen(suff) > 0) free(dir); return ret; } /* Get the filesystem id (so we don't count filesystems that are mounted underneath) */ int getfsid(char *path) { int ret=0; int fd; struct statvfs buf; if (strlen(path) > 0) { if (verbose) printf("Getting statvfs for %s\n", path); ret = statvfs(path, &buf); } else { if (verbose) printf("Getting statvfs for current directory\n"); ret = statvfs(".", &buf); } if (ret != 0) { perror("statvfs() error!"); return (errno); } else { /* Save the filesystem id holding the requested directory */ fsid = buf.f_fsid; if (verbose) { printf(" File system ID. : %d \n", buf.f_fsid ); printf(" READ ONLY: %s \n", ((buf.f_flag & ST_RDONLY) ? "yes" : "no")); printf(" Total number of file serial numbers: %d \n", buf.f_files ); printf(" block size: %d bytes \n", buf.f_bsize); printf("\n"); printf(" Used Free Total \n"); printf(" ---------- ---------- ---------- ------------------------------\n"); printf(" Blocks %10.0d %10.0d %10.0d \n", (buf.f_blocks-buf.f_bavail), buf.f_bavail, buf.f_blocks, buf.f_bsize); printf(" Bytes %10.0f %10.0f %10.0f \n", ((double)(buf.f_blocks-buf.f_bavail) * buf.f_bsize), ((double)buf.f_bavail * buf.f_bsize), ((double)buf.f_blocks * buf.f_bsize)); printf("\n"); } } return ret; } resetCounters() { files = dirs = blkfiles = chrfiles = extlnks = fifofiles = symlnks = sockets = mntpoints=0; total_files = total_dirs = total_blkfiles = total_chrfiles=0; total_extlnks = total_fifofiles = total_symlnks = total_sockets = total_mntpoints=0; } syntax(char *pgm) { fprintf(stderr, "%s: {-i} {-v} {dir ...}\n", pgm); exit(1); } main(int argc, char **argv) { int c; extern int optind; setbuf(stdout, NULL); setbuf(stderr, NULL); printf("\n"); while ((c = getopt(argc, argv, "iv")) != -1) { switch (c) { case 'i': ignoreMissingSymlinks ^= true; break; case 'v': verbose ^= true; break; default: syntax(argv[0]); } } if (optind >= argc) { if (getfsid(".") != 0) return; printf("Bytes used Dirs Files Sub-directory \n"); printf("---------- ---------- ---------- ------------------------------\n"); traverse(".", "", 0); } else while (optind < argc) { if (getfsid(".") != 0) return; if (getfsid(argv[optind]) != 0) break; printf("Bytes used Dirs Files Sub-directory \n"); printf("---------- ---------- ---------- ------------------------------\n"); traverse(argv[optind], "", 0); optind++; if (optind < argc) { resetCounters(); puts("---------------------------------------------------------\n"); printf(" %s \n", argv[optind]); } } }