du.c revision 56597
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1989, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Chris Newcomb. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 3. All advertising materials mentioning features or use of this software 171590Srgrimes * must display the following acknowledgement: 181590Srgrimes * This product includes software developed by the University of 191590Srgrimes * California, Berkeley and its contributors. 201590Srgrimes * 4. Neither the name of the University nor the names of its contributors 211590Srgrimes * may be used to endorse or promote products derived from this software 221590Srgrimes * without specific prior written permission. 231590Srgrimes * 241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341590Srgrimes * SUCH DAMAGE. 351590Srgrimes */ 361590Srgrimes 371590Srgrimes#ifndef lint 3841568Sarchiestatic const char copyright[] = 391590Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\ 401590Srgrimes The Regents of the University of California. All rights reserved.\n"; 411590Srgrimes#endif /* not lint */ 421590Srgrimes 431590Srgrimes#ifndef lint 4456597Smharo#if 0 4541568Sarchiestatic const char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; 4656597Smharo#endif 4756597Smharostatic const char rcsid[] = "$FreeBSD: head/usr.bin/du/du.c 56597 2000-01-25 17:46:59Z mharo $"; 481590Srgrimes#endif /* not lint */ 491590Srgrimes 5032097Sjkh 511590Srgrimes#include <sys/param.h> 521590Srgrimes#include <sys/stat.h> 531590Srgrimes 541590Srgrimes#include <dirent.h> 551590Srgrimes#include <err.h> 561590Srgrimes#include <errno.h> 571590Srgrimes#include <fts.h> 5856597Smharo#include <math.h> 591590Srgrimes#include <stdio.h> 601590Srgrimes#include <stdlib.h> 611590Srgrimes#include <string.h> 6256597Smharo#include <sysexits.h> 6323693Speter#include <unistd.h> 641590Srgrimes 6556597Smharo#define KILO_SZ(n) (n) 6656597Smharo#define MEGA_SZ(n) ((n) * (n)) 6756597Smharo#define GIGA_SZ(n) ((n) * (n) * (n)) 6856597Smharo#define TERA_SZ(n) ((n) * (n) * (n) * (n)) 6956597Smharo#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n)) 7056597Smharo 7156597Smharo#define KILO_2_SZ (KILO_SZ(1024ULL)) 7256597Smharo#define MEGA_2_SZ (MEGA_SZ(1024ULL)) 7356597Smharo#define GIGA_2_SZ (GIGA_SZ(1024ULL)) 7456597Smharo#define TERA_2_SZ (TERA_SZ(1024ULL)) 7556597Smharo#define PETA_2_SZ (PETA_SZ(1024ULL)) 7656597Smharo 7756597Smharo#define KILO_SI_SZ (KILO_SZ(1000ULL)) 7856597Smharo#define MEGA_SI_SZ (MEGA_SZ(1000ULL)) 7956597Smharo#define GIGA_SI_SZ (GIGA_SZ(1000ULL)) 8056597Smharo#define TERA_SI_SZ (TERA_SZ(1000ULL)) 8156597Smharo#define PETA_SI_SZ (PETA_SZ(1000ULL)) 8256597Smharo 8356597Smharounsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ}; 8456597Smharounsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ}; 8556597Smharounsigned long long *valp; 8656597Smharo 8756597Smharotypedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t; 8856597Smharo 8956597Smharoint unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA }; 9056597Smharo 9132097Sjkhint linkchk __P((FTSENT *)); 9232097Sjkhstatic void usage __P((void)); 9356597Smharovoid prthumanval __P((double)); 9456597Smharounit_t unit_adjust __P((double *)); 951590Srgrimes 961590Srgrimesint 971590Srgrimesmain(argc, argv) 981590Srgrimes int argc; 991590Srgrimes char *argv[]; 1001590Srgrimes{ 10132097Sjkh FTS *fts; 10232097Sjkh FTSENT *p; 10337952Sdes long blocksize, savednumber = 0; 10432097Sjkh int ftsoptions; 10532097Sjkh int listall; 10632097Sjkh int depth; 10756597Smharo int Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, hflag, ch, notused, rval; 10832097Sjkh char **save; 1091590Srgrimes 11056597Smharo Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag = 0; 11132097Sjkh 1121590Srgrimes save = argv; 11332097Sjkh ftsoptions = 0; 11419120Sscrappy depth = INT_MAX; 11532097Sjkh 11656597Smharo while ((ch = getopt(argc, argv, "HLPasd:chkrx")) != -1) 1171590Srgrimes switch (ch) { 11832097Sjkh case 'H': 11932097Sjkh Hflag = 1; 12032097Sjkh break; 12132097Sjkh case 'L': 12232097Sjkh if (Pflag) 12332097Sjkh usage(); 12432097Sjkh Lflag = 1; 12532097Sjkh break; 12632097Sjkh case 'P': 12732097Sjkh if (Lflag) 12832097Sjkh usage(); 12932097Sjkh Pflag = 1; 13032097Sjkh break; 13132097Sjkh case 'a': 13232097Sjkh aflag = 1; 13332097Sjkh break; 13432097Sjkh case 's': 13532097Sjkh sflag = 1; 13632097Sjkh break; 13732097Sjkh case 'd': 13832097Sjkh dflag = 1; 13932097Sjkh errno = 0; 14032097Sjkh depth = atoi(optarg); 14132097Sjkh if (errno == ERANGE || depth < 0) { 14240926Srnordier (void) fprintf(stderr, "Invalid argument to option d: %s\n", optarg); 14332097Sjkh usage(); 14432097Sjkh } 14532097Sjkh break; 14632097Sjkh case 'c': 14732097Sjkh cflag = 1; 14832097Sjkh break; 14956597Smharo case 'h': 15056597Smharo putenv("BLOCKSIZE=512"); 15156597Smharo hflag = 1; 15256597Smharo valp = vals_base2; 15356597Smharo break; 15456597Smharo case 'k': 15556597Smharo putenv("BLOCKSIZE=1024"); 15656597Smharo break; 15756597Smharo case 'r': /* Compatibility. */ 15856597Smharo break; 15956597Smharo case 'x': 16056597Smharo ftsoptions |= FTS_XDEV; 16156597Smharo break; 16232097Sjkh case '?': 16332097Sjkh default: 16419120Sscrappy usage(); 1651590Srgrimes } 16632097Sjkh 1671590Srgrimes argc -= optind; 1681590Srgrimes argv += optind; 1691590Srgrimes 1701590Srgrimes /* 1711590Srgrimes * XXX 1721590Srgrimes * Because of the way that fts(3) works, logical walks will not count 1731590Srgrimes * the blocks actually used by symbolic links. We rationalize this by 1741590Srgrimes * noting that users computing logical sizes are likely to do logical 1751590Srgrimes * copies, so not counting the links is correct. The real reason is 1761590Srgrimes * that we'd have to re-implement the kernel's symbolic link traversing 1771590Srgrimes * algorithm to get this right. If, for example, you have relative 1781590Srgrimes * symbolic links referencing other relative symbolic links, it gets 1791590Srgrimes * very nasty, very fast. The bottom line is that it's documented in 1801590Srgrimes * the man page, so it's a feature. 1811590Srgrimes */ 18232097Sjkh 18332097Sjkh if (Hflag + Lflag + Pflag > 1) 18432097Sjkh usage(); 18532097Sjkh 18632097Sjkh if (Hflag + Lflag + Pflag == 0) 18732097Sjkh Pflag = 1; /* -P (physical) is default */ 18832097Sjkh 1891590Srgrimes if (Hflag) 1901590Srgrimes ftsoptions |= FTS_COMFOLLOW; 19132097Sjkh 19232097Sjkh if (Lflag) 1931590Srgrimes ftsoptions |= FTS_LOGICAL; 1941590Srgrimes 19532097Sjkh if (Pflag) 19632097Sjkh ftsoptions |= FTS_PHYSICAL; 19732097Sjkh 19832097Sjkh listall = 0; 19932097Sjkh 2001590Srgrimes if (aflag) { 20119120Sscrappy if (sflag || dflag) 2021590Srgrimes usage(); 20332097Sjkh listall = 1; 20419120Sscrappy } else if (sflag) { 20519120Sscrappy if (dflag) 20619120Sscrappy usage(); 20732097Sjkh depth = 0; 2081590Srgrimes } 2091590Srgrimes 2101590Srgrimes if (!*argv) { 2111590Srgrimes argv = save; 2121590Srgrimes argv[0] = "."; 2131590Srgrimes argv[1] = NULL; 2141590Srgrimes } 2151590Srgrimes 21632097Sjkh (void) getbsize(¬used, &blocksize); 2171590Srgrimes blocksize /= 512; 2181590Srgrimes 21932097Sjkh rval = 0; 22032097Sjkh 2211590Srgrimes if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 22232097Sjkh err(1, "fts_open"); 2231590Srgrimes 22432097Sjkh while ((p = fts_read(fts)) != NULL) { 2251590Srgrimes switch (p->fts_info) { 22632097Sjkh case FTS_D: /* Ignore. */ 2271590Srgrimes break; 22832097Sjkh case FTS_DP: 22932097Sjkh p->fts_parent->fts_number += 23032097Sjkh p->fts_number += p->fts_statp->st_blocks; 23132097Sjkh 23232097Sjkh if (p->fts_level <= depth) 23356597Smharo if (hflag) { 23456597Smharo (void) prthumanval(howmany(savednumber, blocksize)); 23556597Smharo (void) printf("\t%s\n", p->fts_path); 23656597Smharo } else { 23732097Sjkh (void) printf("%ld\t%s\n", 23832097Sjkh howmany(p->fts_number, blocksize), 23932097Sjkh p->fts_path); 24056597Smharo } 24132097Sjkh break; 24232097Sjkh case FTS_DC: /* Ignore. */ 24332097Sjkh break; 24432097Sjkh case FTS_DNR: /* Warn, continue. */ 24532097Sjkh case FTS_ERR: 24632097Sjkh case FTS_NS: 24732097Sjkh warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 24832097Sjkh rval = 1; 24932097Sjkh break; 25032097Sjkh default: 25132097Sjkh if (p->fts_statp->st_nlink > 1 && linkchk(p)) 25232097Sjkh break; 25332097Sjkh 25432097Sjkh if (listall || p->fts_level == 0) 25556597Smharo if (hflag) { 25656597Smharo (void) prthumanval(howmany(p->fts_statp->st_blocks, 25756597Smharo blocksize)); 25856597Smharo (void) printf("\t%s\n", p->fts_path); 25956597Smharo } else { 26056597Smharo (void) printf("%qd\t%s\n", 26156597Smharo howmany(p->fts_statp->st_blocks, blocksize), 26256597Smharo p->fts_path); 26356597Smharo } 26432097Sjkh 26532097Sjkh p->fts_parent->fts_number += p->fts_statp->st_blocks; 2661590Srgrimes } 26739076Sdes savednumber = p->fts_parent->fts_number; 26832097Sjkh } 26932097Sjkh 2701590Srgrimes if (errno) 2711590Srgrimes err(1, "fts_read"); 27232097Sjkh 27337952Sdes if (cflag) 27456597Smharo if (hflag) { 27556597Smharo (void) prthumanval(howmany(savednumber, blocksize)); 27656597Smharo (void) printf("\ttotal\n"); 27756597Smharo } else { 27856597Smharo (void) printf("%ld\ttotal\n", howmany(savednumber, blocksize)); 27956597Smharo } 28032097Sjkh 28128891Swosch exit(rval); 2821590Srgrimes} 2831590Srgrimes 28432097Sjkh 2851590Srgrimestypedef struct _ID { 2861590Srgrimes dev_t dev; 2871590Srgrimes ino_t inode; 2881590Srgrimes} ID; 2891590Srgrimes 29032097Sjkh 2911590Srgrimesint 2921590Srgrimeslinkchk(p) 2931590Srgrimes FTSENT *p; 2941590Srgrimes{ 2951590Srgrimes static ID *files; 2961590Srgrimes static int maxfiles, nfiles; 2971590Srgrimes ID *fp, *start; 2981590Srgrimes ino_t ino; 2991590Srgrimes dev_t dev; 3001590Srgrimes 3011590Srgrimes ino = p->fts_statp->st_ino; 3021590Srgrimes dev = p->fts_statp->st_dev; 3031590Srgrimes if ((start = files) != NULL) 3041590Srgrimes for (fp = start + nfiles - 1; fp >= start; --fp) 3051590Srgrimes if (ino == fp->inode && dev == fp->dev) 3061590Srgrimes return (1); 3071590Srgrimes 3081590Srgrimes if (nfiles == maxfiles && (files = realloc((char *)files, 3091590Srgrimes (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 31027099Scharnier err(1, "can't allocate memory"); 3111590Srgrimes files[nfiles].inode = ino; 3121590Srgrimes files[nfiles].dev = dev; 3131590Srgrimes ++nfiles; 3141590Srgrimes return (0); 3151590Srgrimes} 3161590Srgrimes 31756597Smharo/* 31856597Smharo * Output in "human-readable" format. Uses 3 digits max and puts 31956597Smharo * unit suffixes at the end. Makes output compact and easy to read, 32056597Smharo * especially on huge disks. 32156597Smharo * 32256597Smharo */ 32356597Smharounit_t 32456597Smharounit_adjust(val) 32556597Smharo double *val; 32656597Smharo{ 32756597Smharo double abval; 32856597Smharo unit_t unit; 32956597Smharo unsigned int unit_sz; 33056597Smharo 33156597Smharo abval = fabs(*val); 33256597Smharo 33356597Smharo unit_sz = abval ? ilogb(abval) / 10 : 0; 33456597Smharo 33556597Smharo if (unit_sz >= UNIT_MAX) { 33656597Smharo unit = NONE; 33756597Smharo } else { 33856597Smharo unit = unitp[unit_sz]; 33956597Smharo *val /= (double)valp[unit_sz]; 34056597Smharo } 34156597Smharo 34256597Smharo return (unit); 34356597Smharo} 34456597Smharo 34556597Smharovoid 34656597Smharoprthumanval(bytes) 34756597Smharo double bytes; 34856597Smharo{ 34956597Smharo unit_t unit; 35056597Smharo 35156597Smharo bytes *= 512; 35256597Smharo unit = unit_adjust(&bytes); 35356597Smharo 35456597Smharo if (bytes == 0) 35556597Smharo (void)printf(" 0B"); 35656597Smharo else if (bytes > 10) 35756597Smharo (void)printf("%3.0f%c", bytes, "BKMGTPE"[unit]); 35856597Smharo else 35956597Smharo (void)printf("%3.1f%c", bytes, "BKMGTPE"[unit]); 36056597Smharo} 36156597Smharo 36227099Scharnierstatic void 3631590Srgrimesusage() 3641590Srgrimes{ 3651590Srgrimes (void)fprintf(stderr, 36656597Smharo "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k] [-x] [file ...]\n"); 36756597Smharo exit(EX_USAGE); 3681590Srgrimes} 369