du.c revision 19120
1109998Smarkm/* 2109998Smarkm * Copyright (c) 1989, 1993, 1994 3238405Sjkim * The Regents of the University of California. All rights reserved. 4109998Smarkm * 5109998Smarkm * This code is derived from software contributed to Berkeley by 6109998Smarkm * Chris Newcomb. 7109998Smarkm * 8109998Smarkm * Redistribution and use in source and binary forms, with or without 9109998Smarkm * modification, are permitted provided that the following conditions 10280304Sjkim * are met: 11109998Smarkm * 1. Redistributions of source code must retain the above copyright 12109998Smarkm * notice, this list of conditions and the following disclaimer. 13109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 14109998Smarkm * notice, this list of conditions and the following disclaimer in the 15109998Smarkm * documentation and/or other materials provided with the distribution. 16109998Smarkm * 3. All advertising materials mentioning features or use of this software 17109998Smarkm * must display the following acknowledgement: 18109998Smarkm * This product includes software developed by the University of 19109998Smarkm * California, Berkeley and its contributors. 20109998Smarkm * 4. Neither the name of the University nor the names of its contributors 21109998Smarkm * may be used to endorse or promote products derived from this software 22109998Smarkm * without specific prior written permission. 23109998Smarkm * 24109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27109998Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28109998Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29109998Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32109998Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33109998Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34109998Smarkm * SUCH DAMAGE. 35109998Smarkm */ 36109998Smarkm 37109998Smarkm#ifndef lint 38109998Smarkmstatic char copyright[] = 39109998Smarkm"@(#) Copyright (c) 1989, 1993, 1994\n\ 40109998Smarkm The Regents of the University of California. All rights reserved.\n"; 41109998Smarkm#endif /* not lint */ 42109998Smarkm 43109998Smarkm#ifndef lint 44109998Smarkmstatic char sccsid[] = "@(#)du.c 8.4 (Berkeley) 4/1/94"; 45109998Smarkm#endif /* not lint */ 46109998Smarkm 47109998Smarkm#include <sys/param.h> 48109998Smarkm#include <sys/stat.h> 49109998Smarkm 50109998Smarkm#include <dirent.h> 51109998Smarkm#include <err.h> 52109998Smarkm#include <errno.h> 53109998Smarkm#include <fts.h> 54109998Smarkm#include <stdio.h> 55109998Smarkm#include <stdlib.h> 56280304Sjkim#include <string.h> 57280304Sjkim 58109998Smarkmint linkchk __P((FTSENT *)); 59109998Smarkmvoid usage __P((void)); 60109998Smarkm 61109998Smarkmint 62109998Smarkmmain(argc, argv) 63109998Smarkm int argc; 64109998Smarkm char *argv[]; 65109998Smarkm{ 66109998Smarkm FTS *fts; 67109998Smarkm FTSENT *p; 68160814Ssimon long blocksize; 69280304Sjkim int ftsoptions, listdirs, listfiles, depth; 70280304Sjkim int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag, dflag; 71160814Ssimon char **save; 72280304Sjkim 73280304Sjkim save = argv; 74280304Sjkim Hflag = Lflag = Pflag = aflag = sflag = dflag = 0; 75280304Sjkim depth = INT_MAX; 76280304Sjkim ftsoptions = FTS_PHYSICAL; 77280304Sjkim while ((ch = getopt(argc, argv, "HLPad:ksx")) != EOF) 78280304Sjkim switch (ch) { 79280304Sjkim case 'H': 80280304Sjkim Hflag = 1; 81280304Sjkim Lflag = Pflag = 0; 82280304Sjkim break; 83280304Sjkim case 'L': 84280304Sjkim Lflag = 1; 85280304Sjkim Hflag = Pflag = 0; 86280304Sjkim break; 87280304Sjkim case 'P': 88280304Sjkim Pflag = 1; 89280304Sjkim Hflag = Lflag = 0; 90280304Sjkim break; 91280304Sjkim case 'a': 92280304Sjkim aflag = 1; 93280304Sjkim break; 94280304Sjkim case 'k': 95280304Sjkim putenv("BLOCKSIZE=1024"); 96280304Sjkim break; 97280304Sjkim case 's': 98280304Sjkim sflag = 1; 99280304Sjkim break; 100280304Sjkim case 'x': 101280304Sjkim ftsoptions |= FTS_XDEV; 102280304Sjkim break; 103280304Sjkim case 'd': 104280304Sjkim dflag = 1; 105280304Sjkim depth=atoi(optarg); 106280304Sjkim if(errno == ERANGE) { 107280304Sjkim (void)fprintf(stderr, "Invalid argument to option d: %s", optarg); 108280304Sjkim usage(); 109280304Sjkim } 110280304Sjkim break; 111280304Sjkim case '?': 112280304Sjkim default: 113280304Sjkim usage(); 114280304Sjkim } 115280304Sjkim argc -= optind; 116280304Sjkim argv += optind; 117280304Sjkim 118280304Sjkim /* 119280304Sjkim * XXX 120280304Sjkim * Because of the way that fts(3) works, logical walks will not count 121280304Sjkim * the blocks actually used by symbolic links. We rationalize this by 122280304Sjkim * noting that users computing logical sizes are likely to do logical 123280304Sjkim * copies, so not counting the links is correct. The real reason is 124280304Sjkim * that we'd have to re-implement the kernel's symbolic link traversing 125280304Sjkim * algorithm to get this right. If, for example, you have relative 126280304Sjkim * symbolic links referencing other relative symbolic links, it gets 127280304Sjkim * very nasty, very fast. The bottom line is that it's documented in 128280304Sjkim * the man page, so it's a feature. 129280304Sjkim */ 130280304Sjkim if (Hflag) 131280304Sjkim ftsoptions |= FTS_COMFOLLOW; 132280304Sjkim if (Lflag) { 133280304Sjkim ftsoptions &= ~FTS_PHYSICAL; 134280304Sjkim ftsoptions |= FTS_LOGICAL; 135280304Sjkim } 136280304Sjkim 137280304Sjkim if (aflag) { 138280304Sjkim if (sflag || dflag) 139280304Sjkim usage(); 140280304Sjkim listdirs = listfiles = 1; 141280304Sjkim } else if (sflag) { 142280304Sjkim if (dflag) 143280304Sjkim usage(); 144280304Sjkim listdirs = listfiles = 0; 145280304Sjkim } else if (dflag) { 146280304Sjkim listfiles = 0; 147280304Sjkim listdirs = 1; 148280304Sjkim } else { 149280304Sjkim listfiles = 0; 150280304Sjkim listdirs = 1; 151280304Sjkim } 152280304Sjkim 153280304Sjkim if (!*argv) { 154280304Sjkim argv = save; 155280304Sjkim argv[0] = "."; 156280304Sjkim argv[1] = NULL; 157280304Sjkim } 158280304Sjkim 159280304Sjkim (void)getbsize(¬used, &blocksize); 160280304Sjkim blocksize /= 512; 161280304Sjkim 162280304Sjkim if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 163280304Sjkim err(1, NULL); 164280304Sjkim 165280304Sjkim for (rval = 0; (p = fts_read(fts)) != NULL;) 166280304Sjkim switch (p->fts_info) { 167280304Sjkim case FTS_D: /* Ignore. */ 168280304Sjkim break; 169280304Sjkim case FTS_DP: 170280304Sjkim p->fts_parent->fts_number += 171280304Sjkim p->fts_number += p->fts_statp->st_blocks; 172280304Sjkim /* 173280304Sjkim * If listing each directory, or not listing files 174280304Sjkim * or directories and this is post-order of the 175280304Sjkim * root of a traversal, display the total. 176280304Sjkim */ 177280304Sjkim if ((p->fts_level <= depth && listdirs) || 178280304Sjkim (!listfiles && !p->fts_level)) 179280304Sjkim (void)printf("%ld\t%s\n", 180280304Sjkim howmany(p->fts_number, blocksize), 181280304Sjkim p->fts_path); 182280304Sjkim break; 183280304Sjkim case FTS_DC: /* Ignore. */ 184280304Sjkim break; 185280304Sjkim case FTS_DNR: /* Warn, continue. */ 186280304Sjkim case FTS_ERR: 187280304Sjkim case FTS_NS: 188280304Sjkim warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 189280304Sjkim rval = 1; 190280304Sjkim break; 191280304Sjkim default: 192280304Sjkim if (p->fts_statp->st_nlink > 1 && linkchk(p)) 193280304Sjkim break; 194280304Sjkim /* 195280304Sjkim * If listing each file, or a non-directory file was 196280304Sjkim * the root of a traversal, display the total. 197280304Sjkim */ 198280304Sjkim if (listfiles || !p->fts_level) 199280304Sjkim (void)printf("%qd\t%s\n", 200280304Sjkim howmany(p->fts_statp->st_blocks, blocksize), 201280304Sjkim p->fts_path); 202280304Sjkim p->fts_parent->fts_number += p->fts_statp->st_blocks; 203280304Sjkim } 204280304Sjkim if (errno) 205280304Sjkim err(1, "fts_read"); 206280304Sjkim exit(0); 207280304Sjkim} 208280304Sjkim 209280304Sjkimtypedef struct _ID { 210280304Sjkim dev_t dev; 211280304Sjkim ino_t inode; 212280304Sjkim} ID; 213280304Sjkim 214280304Sjkimint 215280304Sjkimlinkchk(p) 216280304Sjkim FTSENT *p; 217280304Sjkim{ 218280304Sjkim static ID *files; 219280304Sjkim static int maxfiles, nfiles; 220280304Sjkim ID *fp, *start; 221280304Sjkim ino_t ino; 222280304Sjkim dev_t dev; 223280304Sjkim 224280304Sjkim ino = p->fts_statp->st_ino; 225280304Sjkim dev = p->fts_statp->st_dev; 226280304Sjkim if ((start = files) != NULL) 227280304Sjkim for (fp = start + nfiles - 1; fp >= start; --fp) 228280304Sjkim if (ino == fp->inode && dev == fp->dev) 229280304Sjkim return (1); 230280304Sjkim 231280304Sjkim if (nfiles == maxfiles && (files = realloc((char *)files, 232280304Sjkim (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 233280304Sjkim err(1, ""); 234280304Sjkim files[nfiles].inode = ino; 235280304Sjkim files[nfiles].dev = dev; 236280304Sjkim ++nfiles; 237280304Sjkim return (0); 238280304Sjkim} 239280304Sjkim 240280304Sjkimvoid 241280304Sjkimusage() 242280304Sjkim{ 243280304Sjkim 244280304Sjkim (void)fprintf(stderr, 245280304Sjkim "usage: du [-H | -L | -P] [-a | -s | -d depth] [-k] [-x] [file ...]\n"); 246280304Sjkim exit(1); 247280304Sjkim} 248280304Sjkim