xref: /original-bsd/usr.bin/du/du.c (revision b193be73)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Newcomb.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)du.c	5.15 (Berkeley) 03/09/92";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <sys/errno.h>
24 #include <dirent.h>
25 #include <stdio.h>
26 #include <fts.h>
27 #include <string.h>
28 #include <stdlib.h>
29 
30 char	*getbsize __P((char *, int *, long *));
31 int	 linkchk __P((FTSENT *));
32 void	 usage __P((void));
33 
34 main(argc, argv)
35 	int argc;
36 	char *argv[];
37 {
38 	register FTS *fts;
39 	register FTSENT *p;
40 	register int listdirs, listfiles;
41 	long blocksize;
42 	int aflag, ch, ftsoptions, notused, sflag;
43 	char **save;
44 
45 	ftsoptions = FTS_PHYSICAL;
46 	save = argv;
47 	aflag = sflag = 0;
48 	while ((ch = getopt(argc, argv, "aksx")) != EOF)
49 		switch(ch) {
50 		case 'a':
51 			aflag = 1;
52 			break;
53 		case 'k':		/* Delete before 4.4BSD. */
54 			(void)fprintf(stderr, "du: -k no longer supported\n");
55 			break;
56 		case 's':
57 			sflag = 1;
58 			break;
59 		case 'x':
60 			ftsoptions |= FTS_XDEV;
61 			break;
62 		case '?':
63 		default:
64 			usage();
65 		}
66 	argv += optind;
67 
68 	if (aflag) {
69 		if (sflag)
70 			usage();
71 		listdirs = listfiles = 1;
72 	} else if (sflag)
73 		listdirs = listfiles = 0;
74 	else {
75 		listfiles = 0;
76 		listdirs = 1;
77 	}
78 
79 	if (!*argv) {
80 		argv = save;
81 		argv[0] = ".";
82 		argv[1] = NULL;
83 	}
84 
85 	(void)getbsize("du", &notused, &blocksize);
86 	blocksize /= 512;
87 
88 	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) {
89 		(void)fprintf(stderr, "du: %s\n", strerror(errno));
90 		exit(1);
91 	}
92 
93 	while (p = fts_read(fts))
94 		switch(p->fts_info) {
95 		case FTS_D:
96 			break;
97 		case FTS_DP:
98 			p->fts_parent->fts_number +=
99 			    p->fts_number += p->fts_statp->st_blocks;
100 			/*
101 			 * If listing each directory, or not listing files
102 			 * or directories and this is post-order of the
103 			 * root of a traversal, display the total.
104 			 */
105 			if (listdirs || !listfiles && !p->fts_level)
106 				(void)printf("%ld\t%s\n",
107 				    howmany(p->fts_number, blocksize),
108 				    p->fts_path);
109 			break;
110 		case FTS_DNR:
111 		case FTS_ERR:
112 		case FTS_NS:
113 			(void)fprintf(stderr,
114 			    "du: %s: %s\n", p->fts_path, strerror(errno));
115 			break;
116 		case FTS_SL:
117 			if (p->fts_level == FTS_ROOTLEVEL) {
118 				(void)fts_set(fts, p, FTS_FOLLOW);
119 				break;
120 			}
121 			/* FALLTHROUGH */
122 		default:
123 			if (p->fts_statp->st_nlink > 1 && linkchk(p))
124 				break;
125 			/*
126 			 * If listing each file, or a non-directory file was
127 			 * the root of a traversal, display the total.
128 			 */
129 			if (listfiles || !p->fts_level)
130 				(void)printf("%ld\t%s\n",
131 				    howmany(p->fts_statp->st_blocks, blocksize),
132 				    p->fts_path);
133 			p->fts_parent->fts_number += p->fts_statp->st_blocks;
134 		}
135 	exit(0);
136 }
137 
138 typedef struct _ID {
139 	dev_t	dev;
140 	ino_t	inode;
141 } ID;
142 
143 int
144 linkchk(p)
145 	register FTSENT *p;
146 {
147 	static ID *files;
148 	static int maxfiles, nfiles;
149 	register ID *fp, *start;
150 	register ino_t ino;
151 	register dev_t dev;
152 
153 	ino = p->fts_statp->st_ino;
154 	dev = p->fts_statp->st_dev;
155 	if (start = files)
156 		for (fp = start + nfiles - 1; fp >= start; --fp)
157 			if (ino == fp->inode && dev == fp->dev)
158 				return(1);
159 
160 	if (nfiles == maxfiles && (files = realloc((char *)files,
161 	    (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) {
162 		(void)fprintf(stderr, "du: %s\n", strerror(errno));
163 		exit(1);
164 	}
165 	files[nfiles].inode = ino;
166 	files[nfiles].dev = dev;
167 	++nfiles;
168 	return(0);
169 }
170 
171 void
172 usage()
173 {
174 	(void)fprintf(stderr, "usage: du [-a | -s] [-x] [file ...]\n");
175 	exit(1);
176 }
177