from Chris Newcomb; new version of du, plus bug fixes
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 17 Mar 1989 09:20:37 +0000 (01:20 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 17 Mar 1989 09:20:37 +0000 (01:20 -0800)
SCCS-vsn: usr.bin/du/du.1 6.2
SCCS-vsn: usr.bin/du/du.c 5.1

usr/src/usr.bin/du/du.1
usr/src/usr.bin/du/du.c

index d16d00c..40bb2fc 100644 (file)
@@ -1,4 +1,4 @@
-.\"    @(#)du.1        6.1 (Berkeley) %G%
+.\"    @(#)du.1        6.2 (Berkeley) %G%
 .\"
 .TH DU 1 ""
 .AT 3
 .\"
 .TH DU 1 ""
 .AT 3
@@ -7,9 +7,7 @@ du \- summarize disk usage
 .SH SYNOPSIS
 .B du
 [
 .SH SYNOPSIS
 .B du
 [
-.B \-s
-] [
-.B \-a
+.B \-asx
 ] [ name ... ]
 .SH DESCRIPTION
 .I Du
 ] [ name ... ]
 .SH DESCRIPTION
 .I Du
@@ -19,30 +17,26 @@ directory or file
 .IR name .
 If
 .I name
 .IR name .
 If
 .I name
-is missing,
-`\fB.\fR'
-is used.
+is missing, the current directory is used.
 .PP
 .PP
-The argument
-.B \-s
-causes only the grand total to
-be given.
-The argument
+The
 .B \-a
 .B \-a
-causes an entry to be generated
-for each file.
+option causes an entry to be generated for each file.
+The
+.B \-s
+option causes only the grand total to be given.
 Absence of either causes an entry to be generated for
 each directory only.
 .PP
 Absence of either causes an entry to be generated for
 each directory only.
 .PP
-A file which has two links to it is only counted once.
+The
+.B \-x
+option keeps
+.I du
+from crossing any mount points.
+.PP
+A file which has multiple links to it is only counted
+(and displayed) once per
+.I du
+execution.
 .SH "SEE ALSO"
 df(1), quot(8)
 .SH "SEE ALSO"
 df(1), quot(8)
-.SH BUGS
-Non-directories
-given as arguments (not under
-.B \-a
-option) are not listed.
-.br
-If there are too many distinct linked files,
-.I du
-counts the excess files multiply.
index 30019fe..47aa1bb 100644 (file)
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Newcomb.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)du.c        4.12 (Berkeley) %G%";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)du.c       5.1 (Berkeley) %G%";
+#endif /* not lint */
 
 
-#include <stdio.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/param.h>
 #include <sys/stat.h>
-#include <sys/dir.h>
+#include <dirent.h>
+#include <strings.h>
+#include <stdio.h>
 
 
-char   path[BUFSIZ], name[BUFSIZ];
-int    aflg;
-int    sflg;
-char   *dot = ".";
+/* this macro uses ints, not longs */
+#define        kb(n)   (howmany(dbtob(n), 1024))
 
 
-#define ML     1000
-struct {
-       int     dev;
-       ino_t   ino;
-} ml[ML];
-int    mlx;
+typedef struct _ID {
+       dev_t   dev;
+       ino_t   inode;
+} ID;
 
 
-long   descend();
-char   *index(), *rindex(), *strcpy();
-
-#define        kb(n)   (howmany(dbtob(n), 1024))
+ID *files;
+dev_t device;
+int crossmounts, listdirs, listfiles, maxfiles, numfiles;
+char path[MAXPATHLEN + 1];
 
 main(argc, argv)
        int argc;
        char **argv;
 {
 
 main(argc, argv)
        int argc;
        char **argv;
 {
-       long blocks = 0;
-       register char *np;
-       int pid;
+       extern int optind, errno;
+       int ch, reset;
+       char *malloc(), top[MAXPATHLEN + 1];
 
 
-       argc--, argv++;
-again:
-       if (argc && !strcmp(*argv, "-s")) {
-               sflg++;
-               argc--, argv++;
-               goto again;
-       }
-       if (argc && !strcmp(*argv, "-a")) {
-               aflg++;
-               argc--, argv++;
-               goto again;
-       }
-       if (argc == 0) {
-               argv = &dot;
-               argc = 1;
-       }
-       do {
-               if (argc > 1) {
-                       pid = fork();
-                       if (pid == -1) {
-                               fprintf(stderr, "No more processes.\n");
-                               exit(1);
-                       }
-                       if (pid != 0)
-                               wait((int *)0);
+       listdirs = crossmounts = 1;
+       while ((ch = getopt(argc, argv, "asx")) != EOF)
+               switch(ch) {
+               case 'a':
+                       listfiles = 1;
+                       break;
+               case 's':
+                       listfiles = listdirs = 0;
+                       break;
+               case 'x':
+                       crossmounts = 0;
+                       break;
+               case '?':
+               default:
+                       fprintf(stderr, "usage: du [-asx] [name ...]\n");
+                       exit(1);
                }
                }
-               if (argc == 1 || pid == 0) {
-                       (void) strcpy(path, *argv);
-                       (void) strcpy(name, *argv);
-                       if (np = rindex(name, '/')) {
-                               *np++ = '\0';
-                               if (chdir(*name ? name : "/") < 0) {
-                                       perror(*name ? name : "/");
-                                       exit(1);
-                               }
-                       } else
-                               np = path;
-                       blocks = descend(path, *np ? np : ".");
-                       if (sflg)
-                               printf("%ld\t%s\n", kb(blocks), path);
-                       if (argc > 1)
+       argv += optind;
+
+       files = (ID *)malloc((u_int)(sizeof(ID) * (maxfiles = 128)));
+
+       if (!*argv)
+               du(".");
+       else {
+               if (argv[1])
+                       (void)getwd(top);
+               for (; *argv; ++argv) {
+                       du(*argv);
+                       if (argv[1] && index(*argv, '/') && chdir(top)) {
+                               (void)fprintf(stderr, "du: %s: %s\n",
+                                   top, strerror(errno));
                                exit(1);
                                exit(1);
+                       }
                }
                }
-               argc--, argv++;
-       } while (argc > 0);
+       }
        exit(0);
 }
 
        exit(0);
 }
 
-DIR    *dirp = NULL;
+struct stat info;
 
 
-long
-descend(base, name)
-       char *base, *name;
+du(arg)
+       register char *arg;
 {
 {
-       char *ebase0, *ebase;
-       struct stat stb;
-       int i;
-       long blocks = 0;
-       long curoff = NULL;
-       register struct direct *dp;
+       extern int errno;
+       u_long total, descend();
 
 
-       ebase0 = ebase = index(base, 0);
-       if (ebase > base && ebase[-1] == '/')
-               ebase--;
-       if (lstat(name, &stb) < 0) {
-               perror(base);
-               *ebase0 = 0;
-               return (0);
-       }
-       if (stb.st_nlink > 1 && (stb.st_mode&S_IFMT) != S_IFDIR) {
-               for (i = 0; i <= mlx; i++)
-                       if (ml[i].ino == stb.st_ino && ml[i].dev == stb.st_dev)
-                               return (0);
-               if (mlx < ML) {
-                       ml[mlx].dev = stb.st_dev;
-                       ml[mlx].ino = stb.st_ino;
-                       mlx++;
-               }
-       }
-       blocks = stb.st_blocks;
-       if ((stb.st_mode&S_IFMT) != S_IFDIR) {
-               if (aflg)
-                       printf("%ld\t%s\n", kb(blocks), base);
-               return (blocks);
+       if (lstat(arg, &info)) {
+               (void)fprintf(stderr, "du: %s: %s\n", path, strerror(errno));
+               return;
        }
        }
-       if (dirp != NULL)
-               closedir(dirp);
-       dirp = opendir(name);
-       if (dirp == NULL) {
-               perror(base);
-               *ebase0 = 0;
-               return (0);
+       if ((info.st_mode&S_IFMT) != S_IFDIR) {
+               (void)printf("%u\t%s\n", kb(info.st_blocks), arg);
+               return;
        }
        }
-       if (chdir(name) < 0) {
-               perror(base);
-               *ebase0 = 0;
-               closedir(dirp);
-               dirp = NULL;
-               return (0);
+       device = info.st_dev;
+       (void)strcpy(path, arg);
+       total = descend(path);
+       if (!listfiles && !listdirs)
+               (void)printf("%u\t%s\n", kb(total), path);
+}
+
+u_long
+descend(endp)
+       register char *endp;
+{
+       extern int errno;
+       register DIR *dir;
+       register ID *fp;
+       register struct dirent *dp;
+       u_long total;
+       char *realloc();
+
+       if (info.st_nlink > 1) {
+               for (fp = files + numfiles - 1; fp >= files; --fp)
+                       if (info.st_ino == fp->inode &&
+                           info.st_dev == fp->dev)
+                               return(0L);
+               if (numfiles == maxfiles)
+                       files = (ID *)realloc((char *)files,
+                           (u_int)(sizeof(ID) * (maxfiles += 128)));
+               files[numfiles].inode = info.st_ino;
+               files[numfiles].dev = info.st_dev;
+               ++numfiles;
        }
        }
-       while (dp = readdir(dirp)) {
-               if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
-                       continue;
-               (void) sprintf(ebase, "/%s", dp->d_name);
-               curoff = telldir(dirp);
-               blocks += descend(base, ebase+1);
-               *ebase = 0;
-               if (dirp == NULL) {
-                       dirp = opendir(".");
-                       if (dirp == NULL) {
-                               perror(".");
-                               return (0);
+       total = info.st_blocks;
+       if ((info.st_mode&S_IFMT) == S_IFDIR) {
+               if (info.st_dev != device && !crossmounts)
+                       return(0L);
+               if (chdir(endp) || !(dir = opendir("."))) {
+                       fprintf(stderr, "du: %s: %s\n", path, strerror(errno));
+                       return(total);
+               } 
+               for (; *endp; ++endp);
+               if (endp[-1] != '/')
+                       *endp++ = '/';
+               while (dp = readdir(dir)) {
+                       if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
+                           dp->d_name[1] == '.' && !dp->d_name[2]))
+                               continue;
+                       bcopy(dp->d_name, endp, dp->d_namlen + 1);
+                       if (lstat(dp->d_name, &info)) {
+                               (void)fprintf(stderr, "du: %s: %s\n", path,
+                                   strerror(errno));
+                               continue;
                        }
                        }
-                       seekdir(dirp, curoff);
+                       total += descend(endp);
                }
                }
+               closedir(dir);
+               if (chdir("..")) {
+                       fprintf(stderr, "du: ..: %s\n", strerror(errno));
+                       exit(1);
+               }
+               *--endp = '\0';
+               if (listdirs)
+                       (void)printf("%u\t%s\n", kb(total), path);
        }
        }
-       closedir(dirp);
-       dirp = NULL;
-       if (sflg == 0)
-               printf("%ld\t%s\n", kb(blocks), base);
-       if (chdir("..") < 0) {
-               (void) sprintf(index(base, 0), "/..");
-               perror(base);
-               exit(1);
-       }
-       *ebase0 = 0;
-       return (blocks);
+       else if (listfiles)
+               (void)printf("%u\t%s\n", kb(total), path);
+       return(total);
 }
 }