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 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 static char sccsid[] = "@(#)du.c 8.4 (Berkeley) 4/1/94"; 45 #endif /* not lint */ 46 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 50 #include <dirent.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <fts.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 58 int linkchk __P((FTSENT *)); 59 void usage __P((void)); 60 61 int 62 main(argc, argv) 63 int argc; 64 char *argv[]; 65 { 66 FTS *fts; 67 FTSENT *p; 68 long blocksize; 69 int ftsoptions, listdirs, listfiles, depth; 70 int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag, dflag; 71 char **save; 72 73 save = argv; 74 Hflag = Lflag = Pflag = aflag = sflag = dflag = 0; 75 depth = INT_MAX; 76 ftsoptions = FTS_PHYSICAL; 77 while ((ch = getopt(argc, argv, "HLPad:ksx")) != EOF) 78 switch (ch) { 79 case 'H': 80 Hflag = 1; 81 Lflag = Pflag = 0; 82 break; 83 case 'L': 84 Lflag = 1; 85 Hflag = Pflag = 0; 86 break; 87 case 'P': 88 Pflag = 1; 89 Hflag = Lflag = 0; 90 break; 91 case 'a': 92 aflag = 1; 93 break; 94 case 'k': 95 putenv("BLOCKSIZE=1024"); 96 break; 97 case 's': 98 sflag = 1; 99 break; 100 case 'x': 101 ftsoptions |= FTS_XDEV; 102 break; 103 case 'd': 104 dflag = 1; 105 depth=atoi(optarg); 106 if(errno == ERANGE) { 107 (void)fprintf(stderr, "Invalid argument to option d: %s", optarg); 108 usage(); 109 } 110 break; 111 case '?': 112 default: 113 usage(); 114 } 115 argc -= optind; 116 argv += optind; 117 118 /* 119 * XXX 120 * Because of the way that fts(3) works, logical walks will not count 121 * the blocks actually used by symbolic links. We rationalize this by 122 * noting that users computing logical sizes are likely to do logical 123 * copies, so not counting the links is correct. The real reason is 124 * that we'd have to re-implement the kernel's symbolic link traversing 125 * algorithm to get this right. If, for example, you have relative 126 * symbolic links referencing other relative symbolic links, it gets 127 * very nasty, very fast. The bottom line is that it's documented in 128 * the man page, so it's a feature. 129 */ 130 if (Hflag) 131 ftsoptions |= FTS_COMFOLLOW; 132 if (Lflag) { 133 ftsoptions &= ~FTS_PHYSICAL; 134 ftsoptions |= FTS_LOGICAL; 135 } 136 137 if (aflag) { 138 if (sflag || dflag) 139 usage(); 140 listdirs = listfiles = 1; 141 } else if (sflag) { 142 if (dflag) 143 usage(); 144 listdirs = listfiles = 0; 145 } else if (dflag) { 146 listfiles = 0; 147 listdirs = 1; 148 } else { 149 listfiles = 0; 150 listdirs = 1; 151 } 152 153 if (!*argv) { 154 argv = save; 155 argv[0] = "."; 156 argv[1] = NULL; 157 } 158 159 (void)getbsize(¬used, &blocksize); 160 blocksize /= 512; 161 162 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 163 err(1, NULL); 164 165 for (rval = 0; (p = fts_read(fts)) != NULL;) 166 switch (p->fts_info) { 167 case FTS_D: /* Ignore. */ 168 break; 169 case FTS_DP: 170 p->fts_parent->fts_number += 171 p->fts_number += p->fts_statp->st_blocks; 172 /* 173 * If listing each directory, or not listing files 174 * or directories and this is post-order of the 175 * root of a traversal, display the total. 176 */ 177 if ((p->fts_level <= depth && listdirs) || 178 (!listfiles && !p->fts_level)) 179 (void)printf("%ld\t%s\n", 180 howmany(p->fts_number, blocksize), 181 p->fts_path); 182 break; 183 case FTS_DC: /* Ignore. */ 184 break; 185 case FTS_DNR: /* Warn, continue. */ 186 case FTS_ERR: 187 case FTS_NS: 188 warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 189 rval = 1; 190 break; 191 default: 192 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 193 break; 194 /* 195 * If listing each file, or a non-directory file was 196 * the root of a traversal, display the total. 197 */ 198 if (listfiles || !p->fts_level) 199 (void)printf("%qd\t%s\n", 200 howmany(p->fts_statp->st_blocks, blocksize), 201 p->fts_path); 202 p->fts_parent->fts_number += p->fts_statp->st_blocks; 203 } 204 if (errno) 205 err(1, "fts_read"); 206 exit(0); 207 } 208 209 typedef struct _ID { 210 dev_t dev; 211 ino_t inode; 212 } ID; 213 214 int 215 linkchk(p) 216 FTSENT *p; 217 { 218 static ID *files; 219 static int maxfiles, nfiles; 220 ID *fp, *start; 221 ino_t ino; 222 dev_t dev; 223 224 ino = p->fts_statp->st_ino; 225 dev = p->fts_statp->st_dev; 226 if ((start = files) != NULL) 227 for (fp = start + nfiles - 1; fp >= start; --fp) 228 if (ino == fp->inode && dev == fp->dev) 229 return (1); 230 231 if (nfiles == maxfiles && (files = realloc((char *)files, 232 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 233 err(1, ""); 234 files[nfiles].inode = ino; 235 files[nfiles].dev = dev; 236 ++nfiles; 237 return (0); 238 } 239 240 void 241 usage() 242 { 243 244 (void)fprintf(stderr, 245 "usage: du [-H | -L | -P] [-a | -s | -d depth] [-k] [-x] [file ...]\n"); 246 exit(1); 247 } 248