1 /* 2 * Copyright (c) 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Newcomb. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static const char copyright[] = 39 "@(#) Copyright (c) 1989, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 static const char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; 45 #endif /* not lint */ 46 47 48 #include <sys/param.h> 49 #include <sys/stat.h> 50 51 #include <dirent.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <fts.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 int linkchk __P((FTSENT *)); 61 static void usage __P((void)); 62 63 int 64 main(argc, argv) 65 int argc; 66 char *argv[]; 67 { 68 FTS *fts; 69 FTSENT *p; 70 long blocksize, savednumber = 0; 71 int ftsoptions; 72 int listall; 73 int depth; 74 int Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, ch, notused, rval; 75 char **save; 76 77 Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = 0; 78 79 save = argv; 80 ftsoptions = 0; 81 depth = INT_MAX; 82 83 while ((ch = getopt(argc, argv, "HLPad:ksxc")) != -1) 84 switch (ch) { 85 case 'H': 86 Hflag = 1; 87 break; 88 case 'L': 89 if (Pflag) 90 usage(); 91 Lflag = 1; 92 break; 93 case 'P': 94 if (Lflag) 95 usage(); 96 Pflag = 1; 97 break; 98 case 'a': 99 aflag = 1; 100 break; 101 case 'k': 102 putenv("BLOCKSIZE=1024"); 103 break; 104 case 's': 105 sflag = 1; 106 break; 107 case 'x': 108 ftsoptions |= FTS_XDEV; 109 break; 110 case 'd': 111 dflag = 1; 112 errno = 0; 113 depth = atoi(optarg); 114 if (errno == ERANGE || depth < 0) { 115 (void) fprintf(stderr, "Invalid argument to option d: %s\n", optarg); 116 usage(); 117 } 118 break; 119 case 'c': 120 cflag = 1; 121 break; 122 case '?': 123 default: 124 usage(); 125 } 126 127 argc -= optind; 128 argv += optind; 129 130 /* 131 * XXX 132 * Because of the way that fts(3) works, logical walks will not count 133 * the blocks actually used by symbolic links. We rationalize this by 134 * noting that users computing logical sizes are likely to do logical 135 * copies, so not counting the links is correct. The real reason is 136 * that we'd have to re-implement the kernel's symbolic link traversing 137 * algorithm to get this right. If, for example, you have relative 138 * symbolic links referencing other relative symbolic links, it gets 139 * very nasty, very fast. The bottom line is that it's documented in 140 * the man page, so it's a feature. 141 */ 142 143 if (Hflag + Lflag + Pflag > 1) 144 usage(); 145 146 if (Hflag + Lflag + Pflag == 0) 147 Pflag = 1; /* -P (physical) is default */ 148 149 if (Hflag) 150 ftsoptions |= FTS_COMFOLLOW; 151 152 if (Lflag) 153 ftsoptions |= FTS_LOGICAL; 154 155 if (Pflag) 156 ftsoptions |= FTS_PHYSICAL; 157 158 listall = 0; 159 160 if (aflag) { 161 if (sflag || dflag) 162 usage(); 163 listall = 1; 164 } else if (sflag) { 165 if (dflag) 166 usage(); 167 depth = 0; 168 } 169 170 if (!*argv) { 171 argv = save; 172 argv[0] = "."; 173 argv[1] = NULL; 174 } 175 176 (void) getbsize(¬used, &blocksize); 177 blocksize /= 512; 178 179 rval = 0; 180 181 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 182 err(1, "fts_open"); 183 184 while ((p = fts_read(fts)) != NULL) { 185 switch (p->fts_info) { 186 case FTS_D: /* Ignore. */ 187 break; 188 case FTS_DP: 189 p->fts_parent->fts_number += 190 p->fts_number += p->fts_statp->st_blocks; 191 192 if (p->fts_level <= depth) 193 (void) printf("%ld\t%s\n", 194 howmany(p->fts_number, blocksize), 195 p->fts_path); 196 break; 197 case FTS_DC: /* Ignore. */ 198 break; 199 case FTS_DNR: /* Warn, continue. */ 200 case FTS_ERR: 201 case FTS_NS: 202 warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 203 rval = 1; 204 break; 205 default: 206 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 207 break; 208 209 if (listall || p->fts_level == 0) 210 (void) printf("%qd\t%s\n", 211 howmany(p->fts_statp->st_blocks, blocksize), 212 p->fts_path); 213 214 p->fts_parent->fts_number += p->fts_statp->st_blocks; 215 } 216 savednumber = p->fts_parent->fts_number; 217 } 218 219 if (errno) 220 err(1, "fts_read"); 221 222 if (cflag) 223 (void) printf("%ld\ttotal\n", howmany(savednumber, blocksize)); 224 225 exit(rval); 226 } 227 228 229 typedef struct _ID { 230 dev_t dev; 231 ino_t inode; 232 } ID; 233 234 235 int 236 linkchk(p) 237 FTSENT *p; 238 { 239 static ID *files; 240 static int maxfiles, nfiles; 241 ID *fp, *start; 242 ino_t ino; 243 dev_t dev; 244 245 ino = p->fts_statp->st_ino; 246 dev = p->fts_statp->st_dev; 247 if ((start = files) != NULL) 248 for (fp = start + nfiles - 1; fp >= start; --fp) 249 if (ino == fp->inode && dev == fp->dev) 250 return (1); 251 252 if (nfiles == maxfiles && (files = realloc((char *)files, 253 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 254 err(1, "can't allocate memory"); 255 files[nfiles].inode = ino; 256 files[nfiles].dev = dev; 257 ++nfiles; 258 return (0); 259 } 260 261 static void 262 usage() 263 { 264 (void)fprintf(stderr, 265 "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-k] [-x] [file ...]\n"); 266 exit(1); 267 } 268