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