du.c revision 27099
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 381590Srgrimesstatic 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 4423693Speterstatic char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; 451590Srgrimes#endif /* not lint */ 461590Srgrimes 471590Srgrimes#include <sys/param.h> 481590Srgrimes#include <sys/stat.h> 491590Srgrimes 501590Srgrimes#include <dirent.h> 511590Srgrimes#include <err.h> 521590Srgrimes#include <errno.h> 531590Srgrimes#include <fts.h> 541590Srgrimes#include <stdio.h> 551590Srgrimes#include <stdlib.h> 561590Srgrimes#include <string.h> 5723693Speter#include <unistd.h> 581590Srgrimes 591590Srgrimesint linkchk __P((FTSENT *)); 6027099Scharnierstatic void usage __P((void)); 611590Srgrimes 621590Srgrimesint 631590Srgrimesmain(argc, argv) 641590Srgrimes int argc; 651590Srgrimes char *argv[]; 661590Srgrimes{ 671590Srgrimes FTS *fts; 681590Srgrimes FTSENT *p; 691590Srgrimes long blocksize; 7019120Sscrappy int ftsoptions, listdirs, listfiles, depth; 7119120Sscrappy int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag, dflag; 721590Srgrimes char **save; 731590Srgrimes 741590Srgrimes save = argv; 7519120Sscrappy Hflag = Lflag = Pflag = aflag = sflag = dflag = 0; 7619120Sscrappy depth = INT_MAX; 771590Srgrimes ftsoptions = FTS_PHYSICAL; 7824360Simp while ((ch = getopt(argc, argv, "HLPad:ksx")) != -1) 791590Srgrimes switch (ch) { 801590Srgrimes case 'H': 811590Srgrimes Hflag = 1; 821590Srgrimes Lflag = Pflag = 0; 831590Srgrimes break; 841590Srgrimes case 'L': 851590Srgrimes Lflag = 1; 861590Srgrimes Hflag = Pflag = 0; 871590Srgrimes break; 881590Srgrimes case 'P': 891590Srgrimes Pflag = 1; 901590Srgrimes Hflag = Lflag = 0; 911590Srgrimes break; 921590Srgrimes case 'a': 931590Srgrimes aflag = 1; 941590Srgrimes break; 952009Swollman case 'k': 962040Sdg putenv("BLOCKSIZE=1024"); 972009Swollman break; 981590Srgrimes case 's': 991590Srgrimes sflag = 1; 1001590Srgrimes break; 1011590Srgrimes case 'x': 1021590Srgrimes ftsoptions |= FTS_XDEV; 1031590Srgrimes break; 10419120Sscrappy case 'd': 10519120Sscrappy dflag = 1; 10619120Sscrappy depth=atoi(optarg); 10719120Sscrappy if(errno == ERANGE) { 10819120Sscrappy (void)fprintf(stderr, "Invalid argument to option d: %s", optarg); 10919120Sscrappy usage(); 11019120Sscrappy } 11119120Sscrappy break; 1121590Srgrimes case '?': 1131590Srgrimes default: 1141590Srgrimes usage(); 1151590Srgrimes } 1161590Srgrimes argc -= optind; 1171590Srgrimes argv += optind; 1181590Srgrimes 1191590Srgrimes /* 1201590Srgrimes * XXX 1211590Srgrimes * Because of the way that fts(3) works, logical walks will not count 1221590Srgrimes * the blocks actually used by symbolic links. We rationalize this by 1231590Srgrimes * noting that users computing logical sizes are likely to do logical 1241590Srgrimes * copies, so not counting the links is correct. The real reason is 1251590Srgrimes * that we'd have to re-implement the kernel's symbolic link traversing 1261590Srgrimes * algorithm to get this right. If, for example, you have relative 1271590Srgrimes * symbolic links referencing other relative symbolic links, it gets 1281590Srgrimes * very nasty, very fast. The bottom line is that it's documented in 1291590Srgrimes * the man page, so it's a feature. 1301590Srgrimes */ 1311590Srgrimes if (Hflag) 1321590Srgrimes ftsoptions |= FTS_COMFOLLOW; 1331590Srgrimes if (Lflag) { 1341590Srgrimes ftsoptions &= ~FTS_PHYSICAL; 1351590Srgrimes ftsoptions |= FTS_LOGICAL; 1361590Srgrimes } 1371590Srgrimes 1381590Srgrimes if (aflag) { 13919120Sscrappy if (sflag || dflag) 1401590Srgrimes usage(); 1411590Srgrimes listdirs = listfiles = 1; 14219120Sscrappy } else if (sflag) { 14319120Sscrappy if (dflag) 14419120Sscrappy usage(); 1451590Srgrimes listdirs = listfiles = 0; 14619120Sscrappy } else if (dflag) { 1471590Srgrimes listfiles = 0; 1481590Srgrimes listdirs = 1; 14919120Sscrappy } else { 15019120Sscrappy listfiles = 0; 15119120Sscrappy listdirs = 1; 1521590Srgrimes } 1531590Srgrimes 1541590Srgrimes if (!*argv) { 1551590Srgrimes argv = save; 1561590Srgrimes argv[0] = "."; 1571590Srgrimes argv[1] = NULL; 1581590Srgrimes } 1591590Srgrimes 1601590Srgrimes (void)getbsize(¬used, &blocksize); 1611590Srgrimes blocksize /= 512; 1621590Srgrimes 1631590Srgrimes if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 1641590Srgrimes err(1, NULL); 1651590Srgrimes 1661590Srgrimes for (rval = 0; (p = fts_read(fts)) != NULL;) 1671590Srgrimes switch (p->fts_info) { 1681590Srgrimes case FTS_D: /* Ignore. */ 1691590Srgrimes break; 1701590Srgrimes case FTS_DP: 1718874Srgrimes p->fts_parent->fts_number += 1721590Srgrimes p->fts_number += p->fts_statp->st_blocks; 1731590Srgrimes /* 1741590Srgrimes * If listing each directory, or not listing files 1751590Srgrimes * or directories and this is post-order of the 1761590Srgrimes * root of a traversal, display the total. 1771590Srgrimes */ 17819120Sscrappy if ((p->fts_level <= depth && listdirs) || 17919120Sscrappy (!listfiles && !p->fts_level)) 1801590Srgrimes (void)printf("%ld\t%s\n", 1811590Srgrimes howmany(p->fts_number, blocksize), 1821590Srgrimes p->fts_path); 1831590Srgrimes break; 1841590Srgrimes case FTS_DC: /* Ignore. */ 1851590Srgrimes break; 1861590Srgrimes case FTS_DNR: /* Warn, continue. */ 1871590Srgrimes case FTS_ERR: 1881590Srgrimes case FTS_NS: 1891590Srgrimes warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 1901590Srgrimes rval = 1; 1911590Srgrimes break; 1921590Srgrimes default: 1931590Srgrimes if (p->fts_statp->st_nlink > 1 && linkchk(p)) 1941590Srgrimes break; 1951590Srgrimes /* 1961590Srgrimes * If listing each file, or a non-directory file was 1971590Srgrimes * the root of a traversal, display the total. 1981590Srgrimes */ 1991590Srgrimes if (listfiles || !p->fts_level) 2001590Srgrimes (void)printf("%qd\t%s\n", 2011590Srgrimes howmany(p->fts_statp->st_blocks, blocksize), 2021590Srgrimes p->fts_path); 2031590Srgrimes p->fts_parent->fts_number += p->fts_statp->st_blocks; 2041590Srgrimes } 2051590Srgrimes if (errno) 2061590Srgrimes err(1, "fts_read"); 2071590Srgrimes exit(0); 2081590Srgrimes} 2091590Srgrimes 2101590Srgrimestypedef struct _ID { 2111590Srgrimes dev_t dev; 2121590Srgrimes ino_t inode; 2131590Srgrimes} ID; 2141590Srgrimes 2151590Srgrimesint 2161590Srgrimeslinkchk(p) 2171590Srgrimes FTSENT *p; 2181590Srgrimes{ 2191590Srgrimes static ID *files; 2201590Srgrimes static int maxfiles, nfiles; 2211590Srgrimes ID *fp, *start; 2221590Srgrimes ino_t ino; 2231590Srgrimes dev_t dev; 2241590Srgrimes 2251590Srgrimes ino = p->fts_statp->st_ino; 2261590Srgrimes dev = p->fts_statp->st_dev; 2271590Srgrimes if ((start = files) != NULL) 2281590Srgrimes for (fp = start + nfiles - 1; fp >= start; --fp) 2291590Srgrimes if (ino == fp->inode && dev == fp->dev) 2301590Srgrimes return (1); 2311590Srgrimes 2321590Srgrimes if (nfiles == maxfiles && (files = realloc((char *)files, 2331590Srgrimes (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 23427099Scharnier err(1, "can't allocate memory"); 2351590Srgrimes files[nfiles].inode = ino; 2361590Srgrimes files[nfiles].dev = dev; 2371590Srgrimes ++nfiles; 2381590Srgrimes return (0); 2391590Srgrimes} 2401590Srgrimes 24127099Scharnierstatic void 2421590Srgrimesusage() 2431590Srgrimes{ 2441590Srgrimes (void)fprintf(stderr, 24519120Sscrappy "usage: du [-H | -L | -P] [-a | -s | -d depth] [-k] [-x] [file ...]\n"); 2461590Srgrimes exit(1); 2471590Srgrimes} 248