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