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 #if 0 45 static const char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; 46 #endif 47 static const char rcsid[] = 48 "$FreeBSD$"; 49 #endif /* not lint */ 50 51 52 #include <sys/param.h> 53 #include <sys/stat.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <fts.h> 58 #include <math.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <sysexits.h> 63 #include <unistd.h> 64 65 #define KILO_SZ(n) (n) 66 #define MEGA_SZ(n) ((n) * (n)) 67 #define GIGA_SZ(n) ((n) * (n) * (n)) 68 #define TERA_SZ(n) ((n) * (n) * (n) * (n)) 69 #define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n)) 70 71 #define KILO_2_SZ (KILO_SZ(1024ULL)) 72 #define MEGA_2_SZ (MEGA_SZ(1024ULL)) 73 #define GIGA_2_SZ (GIGA_SZ(1024ULL)) 74 #define TERA_2_SZ (TERA_SZ(1024ULL)) 75 #define PETA_2_SZ (PETA_SZ(1024ULL)) 76 77 #define KILO_SI_SZ (KILO_SZ(1000ULL)) 78 #define MEGA_SI_SZ (MEGA_SZ(1000ULL)) 79 #define GIGA_SI_SZ (GIGA_SZ(1000ULL)) 80 #define TERA_SI_SZ (TERA_SZ(1000ULL)) 81 #define PETA_SI_SZ (PETA_SZ(1000ULL)) 82 83 unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ}; 84 unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ}; 85 unsigned long long *valp; 86 87 typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t; 88 89 int unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA }; 90 91 int linkchk __P((FTSENT *)); 92 static void usage __P((void)); 93 void prthumanval __P((double)); 94 unit_t unit_adjust __P((double *)); 95 96 int 97 main(argc, argv) 98 int argc; 99 char *argv[]; 100 { 101 FTS *fts; 102 FTSENT *p; 103 long blocksize, savednumber = 0; 104 int ftsoptions; 105 int listall; 106 int depth; 107 int Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, hflag, ch, notused, rval; 108 char **save; 109 110 Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag = 0; 111 112 save = argv; 113 ftsoptions = 0; 114 depth = INT_MAX; 115 116 while ((ch = getopt(argc, argv, "HLPasd:chkrx")) != -1) 117 switch (ch) { 118 case 'H': 119 Hflag = 1; 120 break; 121 case 'L': 122 if (Pflag) 123 usage(); 124 Lflag = 1; 125 break; 126 case 'P': 127 if (Lflag) 128 usage(); 129 Pflag = 1; 130 break; 131 case 'a': 132 aflag = 1; 133 break; 134 case 's': 135 sflag = 1; 136 break; 137 case 'd': 138 dflag = 1; 139 errno = 0; 140 depth = atoi(optarg); 141 if (errno == ERANGE || depth < 0) { 142 warnx("invalid argument to option d: %s", optarg); 143 usage(); 144 } 145 break; 146 case 'c': 147 cflag = 1; 148 break; 149 case 'h': 150 putenv("BLOCKSIZE=512"); 151 hflag = 1; 152 valp = vals_base2; 153 break; 154 case 'k': 155 putenv("BLOCKSIZE=1024"); 156 break; 157 case 'r': /* Compatibility. */ 158 break; 159 case 'x': 160 ftsoptions |= FTS_XDEV; 161 break; 162 case '?': 163 default: 164 usage(); 165 } 166 167 argc -= optind; 168 argv += optind; 169 170 /* 171 * XXX 172 * Because of the way that fts(3) works, logical walks will not count 173 * the blocks actually used by symbolic links. We rationalize this by 174 * noting that users computing logical sizes are likely to do logical 175 * copies, so not counting the links is correct. The real reason is 176 * that we'd have to re-implement the kernel's symbolic link traversing 177 * algorithm to get this right. If, for example, you have relative 178 * symbolic links referencing other relative symbolic links, it gets 179 * very nasty, very fast. The bottom line is that it's documented in 180 * the man page, so it's a feature. 181 */ 182 183 if (Hflag + Lflag + Pflag > 1) 184 usage(); 185 186 if (Hflag + Lflag + Pflag == 0) 187 Pflag = 1; /* -P (physical) is default */ 188 189 if (Hflag) 190 ftsoptions |= FTS_COMFOLLOW; 191 192 if (Lflag) 193 ftsoptions |= FTS_LOGICAL; 194 195 if (Pflag) 196 ftsoptions |= FTS_PHYSICAL; 197 198 listall = 0; 199 200 if (aflag) { 201 if (sflag || dflag) 202 usage(); 203 listall = 1; 204 } else if (sflag) { 205 if (dflag) 206 usage(); 207 depth = 0; 208 } 209 210 if (!*argv) { 211 argv = save; 212 argv[0] = "."; 213 argv[1] = NULL; 214 } 215 216 (void) getbsize(¬used, &blocksize); 217 blocksize /= 512; 218 219 rval = 0; 220 221 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 222 err(1, "fts_open"); 223 224 while ((p = fts_read(fts)) != NULL) { 225 switch (p->fts_info) { 226 case FTS_D: /* Ignore. */ 227 break; 228 case FTS_DP: 229 p->fts_parent->fts_number += 230 p->fts_number += p->fts_statp->st_blocks; 231 232 if (p->fts_level <= depth) { 233 if (hflag) { 234 (void) prthumanval(howmany(p->fts_number, blocksize)); 235 (void) printf("\t%s\n", p->fts_path); 236 } else { 237 (void) printf("%ld\t%s\n", 238 howmany(p->fts_number, blocksize), 239 p->fts_path); 240 } 241 } 242 break; 243 case FTS_DC: /* Ignore. */ 244 break; 245 case FTS_DNR: /* Warn, continue. */ 246 case FTS_ERR: 247 case FTS_NS: 248 warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 249 rval = 1; 250 break; 251 default: 252 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 253 break; 254 255 if (listall || p->fts_level == 0) { 256 if (hflag) { 257 (void) prthumanval(howmany(p->fts_statp->st_blocks, 258 blocksize)); 259 (void) printf("\t%s\n", p->fts_path); 260 } else { 261 (void) printf("%qd\t%s\n", 262 howmany(p->fts_statp->st_blocks, blocksize), 263 p->fts_path); 264 } 265 } 266 267 p->fts_parent->fts_number += p->fts_statp->st_blocks; 268 } 269 savednumber = p->fts_parent->fts_number; 270 } 271 272 if (errno) 273 err(1, "fts_read"); 274 275 if (cflag) { 276 if (hflag) { 277 (void) prthumanval(howmany(savednumber, blocksize)); 278 (void) printf("\ttotal\n"); 279 } else { 280 (void) printf("%ld\ttotal\n", howmany(savednumber, blocksize)); 281 } 282 } 283 284 exit(rval); 285 } 286 287 288 typedef struct _ID { 289 dev_t dev; 290 ino_t inode; 291 } ID; 292 293 294 int 295 linkchk(p) 296 FTSENT *p; 297 { 298 static ID *files; 299 static int maxfiles, nfiles; 300 ID *fp, *start; 301 ino_t ino; 302 dev_t dev; 303 304 ino = p->fts_statp->st_ino; 305 dev = p->fts_statp->st_dev; 306 if ((start = files) != NULL) 307 for (fp = start + nfiles - 1; fp >= start; --fp) 308 if (ino == fp->inode && dev == fp->dev) 309 return (1); 310 311 if (nfiles == maxfiles && (files = realloc((char *)files, 312 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 313 errx(1, "can't allocate memory"); 314 files[nfiles].inode = ino; 315 files[nfiles].dev = dev; 316 ++nfiles; 317 return (0); 318 } 319 320 /* 321 * Output in "human-readable" format. Uses 3 digits max and puts 322 * unit suffixes at the end. Makes output compact and easy to read, 323 * especially on huge disks. 324 * 325 */ 326 unit_t 327 unit_adjust(val) 328 double *val; 329 { 330 double abval; 331 unit_t unit; 332 unsigned int unit_sz; 333 334 abval = fabs(*val); 335 336 unit_sz = abval ? ilogb(abval) / 10 : 0; 337 338 if (unit_sz >= UNIT_MAX) { 339 unit = NONE; 340 } else { 341 unit = unitp[unit_sz]; 342 *val /= (double)valp[unit_sz]; 343 } 344 345 return (unit); 346 } 347 348 void 349 prthumanval(bytes) 350 double bytes; 351 { 352 unit_t unit; 353 354 bytes *= 512; 355 unit = unit_adjust(&bytes); 356 357 if (bytes == 0) 358 (void)printf(" 0B"); 359 else if (bytes > 10) 360 (void)printf("%3.0f%c", bytes, "BKMGTPE"[unit]); 361 else 362 (void)printf("%3.1f%c", bytes, "BKMGTPE"[unit]); 363 } 364 365 static void 366 usage() 367 { 368 (void)fprintf(stderr, 369 "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k] [-x] [file ...]\n"); 370 exit(EX_USAGE); 371 } 372