du.c revision 1590
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 441590Srgrimesstatic char sccsid[] = "@(#)du.c 8.4 (Berkeley) 4/1/94"; 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> 571590Srgrimes 581590Srgrimesint linkchk __P((FTSENT *)); 591590Srgrimesvoid usage __P((void)); 601590Srgrimes 611590Srgrimesint 621590Srgrimesmain(argc, argv) 631590Srgrimes int argc; 641590Srgrimes char *argv[]; 651590Srgrimes{ 661590Srgrimes FTS *fts; 671590Srgrimes FTSENT *p; 681590Srgrimes long blocksize; 691590Srgrimes int ftsoptions, listdirs, listfiles; 701590Srgrimes int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag; 711590Srgrimes char **save; 721590Srgrimes 731590Srgrimes save = argv; 741590Srgrimes Hflag = Lflag = Pflag = aflag = sflag = 0; 751590Srgrimes ftsoptions = FTS_PHYSICAL; 761590Srgrimes while ((ch = getopt(argc, argv, "HLPasx")) != EOF) 771590Srgrimes switch (ch) { 781590Srgrimes case 'H': 791590Srgrimes Hflag = 1; 801590Srgrimes Lflag = Pflag = 0; 811590Srgrimes break; 821590Srgrimes case 'L': 831590Srgrimes Lflag = 1; 841590Srgrimes Hflag = Pflag = 0; 851590Srgrimes break; 861590Srgrimes case 'P': 871590Srgrimes Pflag = 1; 881590Srgrimes Hflag = Lflag = 0; 891590Srgrimes break; 901590Srgrimes case 'a': 911590Srgrimes aflag = 1; 921590Srgrimes break; 931590Srgrimes case 's': 941590Srgrimes sflag = 1; 951590Srgrimes break; 961590Srgrimes case 'x': 971590Srgrimes ftsoptions |= FTS_XDEV; 981590Srgrimes break; 991590Srgrimes case '?': 1001590Srgrimes default: 1011590Srgrimes usage(); 1021590Srgrimes } 1031590Srgrimes argc -= optind; 1041590Srgrimes argv += optind; 1051590Srgrimes 1061590Srgrimes /* 1071590Srgrimes * XXX 1081590Srgrimes * Because of the way that fts(3) works, logical walks will not count 1091590Srgrimes * the blocks actually used by symbolic links. We rationalize this by 1101590Srgrimes * noting that users computing logical sizes are likely to do logical 1111590Srgrimes * copies, so not counting the links is correct. The real reason is 1121590Srgrimes * that we'd have to re-implement the kernel's symbolic link traversing 1131590Srgrimes * algorithm to get this right. If, for example, you have relative 1141590Srgrimes * symbolic links referencing other relative symbolic links, it gets 1151590Srgrimes * very nasty, very fast. The bottom line is that it's documented in 1161590Srgrimes * the man page, so it's a feature. 1171590Srgrimes */ 1181590Srgrimes if (Hflag) 1191590Srgrimes ftsoptions |= FTS_COMFOLLOW; 1201590Srgrimes if (Lflag) { 1211590Srgrimes ftsoptions &= ~FTS_PHYSICAL; 1221590Srgrimes ftsoptions |= FTS_LOGICAL; 1231590Srgrimes } 1241590Srgrimes 1251590Srgrimes if (aflag) { 1261590Srgrimes if (sflag) 1271590Srgrimes usage(); 1281590Srgrimes listdirs = listfiles = 1; 1291590Srgrimes } else if (sflag) 1301590Srgrimes listdirs = listfiles = 0; 1311590Srgrimes else { 1321590Srgrimes listfiles = 0; 1331590Srgrimes listdirs = 1; 1341590Srgrimes } 1351590Srgrimes 1361590Srgrimes if (!*argv) { 1371590Srgrimes argv = save; 1381590Srgrimes argv[0] = "."; 1391590Srgrimes argv[1] = NULL; 1401590Srgrimes } 1411590Srgrimes 1421590Srgrimes (void)getbsize(¬used, &blocksize); 1431590Srgrimes blocksize /= 512; 1441590Srgrimes 1451590Srgrimes if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 1461590Srgrimes err(1, NULL); 1471590Srgrimes 1481590Srgrimes for (rval = 0; (p = fts_read(fts)) != NULL;) 1491590Srgrimes switch (p->fts_info) { 1501590Srgrimes case FTS_D: /* Ignore. */ 1511590Srgrimes break; 1521590Srgrimes case FTS_DP: 1531590Srgrimes p->fts_parent->fts_number += 1541590Srgrimes p->fts_number += p->fts_statp->st_blocks; 1551590Srgrimes /* 1561590Srgrimes * If listing each directory, or not listing files 1571590Srgrimes * or directories and this is post-order of the 1581590Srgrimes * root of a traversal, display the total. 1591590Srgrimes */ 1601590Srgrimes if (listdirs || !listfiles && !p->fts_level) 1611590Srgrimes (void)printf("%ld\t%s\n", 1621590Srgrimes howmany(p->fts_number, blocksize), 1631590Srgrimes p->fts_path); 1641590Srgrimes break; 1651590Srgrimes case FTS_DC: /* Ignore. */ 1661590Srgrimes break; 1671590Srgrimes case FTS_DNR: /* Warn, continue. */ 1681590Srgrimes case FTS_ERR: 1691590Srgrimes case FTS_NS: 1701590Srgrimes warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 1711590Srgrimes rval = 1; 1721590Srgrimes break; 1731590Srgrimes default: 1741590Srgrimes if (p->fts_statp->st_nlink > 1 && linkchk(p)) 1751590Srgrimes break; 1761590Srgrimes /* 1771590Srgrimes * If listing each file, or a non-directory file was 1781590Srgrimes * the root of a traversal, display the total. 1791590Srgrimes */ 1801590Srgrimes if (listfiles || !p->fts_level) 1811590Srgrimes (void)printf("%qd\t%s\n", 1821590Srgrimes howmany(p->fts_statp->st_blocks, blocksize), 1831590Srgrimes p->fts_path); 1841590Srgrimes p->fts_parent->fts_number += p->fts_statp->st_blocks; 1851590Srgrimes } 1861590Srgrimes if (errno) 1871590Srgrimes err(1, "fts_read"); 1881590Srgrimes exit(0); 1891590Srgrimes} 1901590Srgrimes 1911590Srgrimestypedef struct _ID { 1921590Srgrimes dev_t dev; 1931590Srgrimes ino_t inode; 1941590Srgrimes} ID; 1951590Srgrimes 1961590Srgrimesint 1971590Srgrimeslinkchk(p) 1981590Srgrimes FTSENT *p; 1991590Srgrimes{ 2001590Srgrimes static ID *files; 2011590Srgrimes static int maxfiles, nfiles; 2021590Srgrimes ID *fp, *start; 2031590Srgrimes ino_t ino; 2041590Srgrimes dev_t dev; 2051590Srgrimes 2061590Srgrimes ino = p->fts_statp->st_ino; 2071590Srgrimes dev = p->fts_statp->st_dev; 2081590Srgrimes if ((start = files) != NULL) 2091590Srgrimes for (fp = start + nfiles - 1; fp >= start; --fp) 2101590Srgrimes if (ino == fp->inode && dev == fp->dev) 2111590Srgrimes return (1); 2121590Srgrimes 2131590Srgrimes if (nfiles == maxfiles && (files = realloc((char *)files, 2141590Srgrimes (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 2151590Srgrimes err(1, ""); 2161590Srgrimes files[nfiles].inode = ino; 2171590Srgrimes files[nfiles].dev = dev; 2181590Srgrimes ++nfiles; 2191590Srgrimes return (0); 2201590Srgrimes} 2211590Srgrimes 2221590Srgrimesvoid 2231590Srgrimesusage() 2241590Srgrimes{ 2251590Srgrimes 2261590Srgrimes (void)fprintf(stderr, 2271590Srgrimes "usage: du [-H | -L | -P] [-a | -s] [-x] [file ...]\n"); 2281590Srgrimes exit(1); 2291590Srgrimes} 230