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