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