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 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 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", optarg); 116 usage(); 117 } 118 break; 119 case 'c': 120 cflag = 1; 121 break; 122 case '?': 123 case 'h': 124 default: 125 usage(); 126 } 127 128 argc -= optind; 129 argv += optind; 130 131 /* 132 * XXX 133 * Because of the way that fts(3) works, logical walks will not count 134 * the blocks actually used by symbolic links. We rationalize this by 135 * noting that users computing logical sizes are likely to do logical 136 * copies, so not counting the links is correct. The real reason is 137 * that we'd have to re-implement the kernel's symbolic link traversing 138 * algorithm to get this right. If, for example, you have relative 139 * symbolic links referencing other relative symbolic links, it gets 140 * very nasty, very fast. The bottom line is that it's documented in 141 * the man page, so it's a feature. 142 */ 143 144 if (Hflag + Lflag + Pflag > 1) 145 usage(); 146 147 if (Hflag + Lflag + Pflag == 0) 148 Pflag = 1; /* -P (physical) is default */ 149 150 if (Hflag) 151 ftsoptions |= FTS_COMFOLLOW; 152 153 if (Lflag) 154 ftsoptions |= FTS_LOGICAL; 155 156 if (Pflag) 157 ftsoptions |= FTS_PHYSICAL; 158 159 listall = 0; 160 161 if (aflag) { 162 if (sflag || dflag) 163 usage(); 164 listall = 1; 165 } else if (sflag) { 166 if (dflag) 167 usage(); 168 depth = 0; 169 } 170 171 if (!*argv) { 172 argv = save; 173 argv[0] = "."; 174 argv[1] = NULL; 175 } 176 177 (void) getbsize(¬used, &blocksize); 178 blocksize /= 512; 179 180 rval = 0; 181 182 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 183 err(1, "fts_open"); 184 185 while ((p = fts_read(fts)) != NULL) { 186 switch (p->fts_info) { 187 case FTS_D: /* Ignore. */ 188 break; 189 case FTS_DP: 190 p->fts_parent->fts_number += 191 p->fts_number += p->fts_statp->st_blocks; 192 193 if (p->fts_level <= depth) 194 (void) printf("%ld\t%s\n", 195 howmany(p->fts_number, blocksize), 196 p->fts_path); 197 break; 198 case FTS_DC: /* Ignore. */ 199 break; 200 case FTS_DNR: /* Warn, continue. */ 201 case FTS_ERR: 202 case FTS_NS: 203 warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 204 rval = 1; 205 break; 206 default: 207 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 208 break; 209 210 if (listall || p->fts_level == 0) 211 (void) printf("%qd\t%s\n", 212 howmany(p->fts_statp->st_blocks, blocksize), 213 p->fts_path); 214 215 p->fts_parent->fts_number += p->fts_statp->st_blocks; 216 } 217 savednumber = p->fts_parent->fts_number; 218 } 219 220 if (errno) 221 err(1, "fts_read"); 222 223 if (cflag) 224 (void) printf("%ld\ttotal\n", howmany(savednumber, blocksize)); 225 226 exit(rval); 227 } 228 229 230 typedef struct _ID { 231 dev_t dev; 232 ino_t inode; 233 } ID; 234 235 236 int 237 linkchk(p) 238 FTSENT *p; 239 { 240 static ID *files; 241 static int maxfiles, nfiles; 242 ID *fp, *start; 243 ino_t ino; 244 dev_t dev; 245 246 ino = p->fts_statp->st_ino; 247 dev = p->fts_statp->st_dev; 248 if ((start = files) != NULL) 249 for (fp = start + nfiles - 1; fp >= start; --fp) 250 if (ino == fp->inode && dev == fp->dev) 251 return (1); 252 253 if (nfiles == maxfiles && (files = realloc((char *)files, 254 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 255 err(1, "can't allocate memory"); 256 files[nfiles].inode = ino; 257 files[nfiles].dev = dev; 258 ++nfiles; 259 return (0); 260 } 261 262 static void 263 usage() 264 { 265 (void)fprintf(stderr, 266 "usage: du [-H | -L | -P] [-a | -s | -d depth] [-k] [-x] [file ...]\n"); 267 exit(1); 268 } 269