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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char copyright[] = 13 "@(#) Copyright (c) 1989, 1993, 1994\n\ 14 The Regents of the University of California. All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)du.c 8.4 (Berkeley) 04/01/94"; 19 #endif /* not lint */ 20 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 24 #include <dirent.h> 25 #include <err.h> 26 #include <errno.h> 27 #include <fts.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 int linkchk __P((FTSENT *)); 33 void usage __P((void)); 34 35 int 36 main(argc, argv) 37 int argc; 38 char *argv[]; 39 { 40 FTS *fts; 41 FTSENT *p; 42 long blocksize; 43 int ftsoptions, listdirs, listfiles; 44 int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag; 45 char **save; 46 47 save = argv; 48 Hflag = Lflag = Pflag = aflag = sflag = 0; 49 ftsoptions = FTS_PHYSICAL; 50 while ((ch = getopt(argc, argv, "HLPasx")) != EOF) 51 switch (ch) { 52 case 'H': 53 Hflag = 1; 54 Lflag = Pflag = 0; 55 break; 56 case 'L': 57 Lflag = 1; 58 Hflag = Pflag = 0; 59 break; 60 case 'P': 61 Pflag = 1; 62 Hflag = Lflag = 0; 63 break; 64 case 'a': 65 aflag = 1; 66 break; 67 case 's': 68 sflag = 1; 69 break; 70 case 'x': 71 ftsoptions |= FTS_XDEV; 72 break; 73 case '?': 74 default: 75 usage(); 76 } 77 argc -= optind; 78 argv += optind; 79 80 /* 81 * XXX 82 * Because of the way that fts(3) works, logical walks will not count 83 * the blocks actually used by symbolic links. We rationalize this by 84 * noting that users computing logical sizes are likely to do logical 85 * copies, so not counting the links is correct. The real reason is 86 * that we'd have to re-implement the kernel's symbolic link traversing 87 * algorithm to get this right. If, for example, you have relative 88 * symbolic links referencing other relative symbolic links, it gets 89 * very nasty, very fast. The bottom line is that it's documented in 90 * the man page, so it's a feature. 91 */ 92 if (Hflag) 93 ftsoptions |= FTS_COMFOLLOW; 94 if (Lflag) { 95 ftsoptions &= ~FTS_PHYSICAL; 96 ftsoptions |= FTS_LOGICAL; 97 } 98 99 if (aflag) { 100 if (sflag) 101 usage(); 102 listdirs = listfiles = 1; 103 } else if (sflag) 104 listdirs = listfiles = 0; 105 else { 106 listfiles = 0; 107 listdirs = 1; 108 } 109 110 if (!*argv) { 111 argv = save; 112 argv[0] = "."; 113 argv[1] = NULL; 114 } 115 116 (void)getbsize(¬used, &blocksize); 117 blocksize /= 512; 118 119 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 120 err(1, NULL); 121 122 for (rval = 0; (p = fts_read(fts)) != NULL;) 123 switch (p->fts_info) { 124 case FTS_D: /* Ignore. */ 125 break; 126 case FTS_DP: 127 p->fts_parent->fts_number += 128 p->fts_number += p->fts_statp->st_blocks; 129 /* 130 * If listing each directory, or not listing files 131 * or directories and this is post-order of the 132 * root of a traversal, display the total. 133 */ 134 if (listdirs || !listfiles && !p->fts_level) 135 (void)printf("%ld\t%s\n", 136 howmany(p->fts_number, blocksize), 137 p->fts_path); 138 break; 139 case FTS_DC: /* Ignore. */ 140 break; 141 case FTS_DNR: /* Warn, continue. */ 142 case FTS_ERR: 143 case FTS_NS: 144 warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 145 rval = 1; 146 break; 147 default: 148 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 149 break; 150 /* 151 * If listing each file, or a non-directory file was 152 * the root of a traversal, display the total. 153 */ 154 if (listfiles || !p->fts_level) 155 (void)printf("%qd\t%s\n", 156 howmany(p->fts_statp->st_blocks, blocksize), 157 p->fts_path); 158 p->fts_parent->fts_number += p->fts_statp->st_blocks; 159 } 160 if (errno) 161 err(1, "fts_read"); 162 exit(0); 163 } 164 165 typedef struct _ID { 166 dev_t dev; 167 ino_t inode; 168 } ID; 169 170 int 171 linkchk(p) 172 FTSENT *p; 173 { 174 static ID *files; 175 static int maxfiles, nfiles; 176 ID *fp, *start; 177 ino_t ino; 178 dev_t dev; 179 180 ino = p->fts_statp->st_ino; 181 dev = p->fts_statp->st_dev; 182 if ((start = files) != NULL) 183 for (fp = start + nfiles - 1; fp >= start; --fp) 184 if (ino == fp->inode && dev == fp->dev) 185 return (1); 186 187 if (nfiles == maxfiles && (files = realloc((char *)files, 188 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 189 err(1, ""); 190 files[nfiles].inode = ino; 191 files[nfiles].dev = dev; 192 ++nfiles; 193 return (0); 194 } 195 196 void 197 usage() 198 { 199 200 (void)fprintf(stderr, 201 "usage: du [-H | -L | -P] [-a | -s] [-x] [file ...]\n"); 202 exit(1); 203 } 204