1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * 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 char copyright[] = 13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)du.c 5.16 (Berkeley) 03/30/92"; 19 #endif /* not lint */ 20 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <sys/errno.h> 24 #include <dirent.h> 25 #include <stdio.h> 26 #include <fts.h> 27 #include <string.h> 28 #include <stdlib.h> 29 30 void err __P((const char *, ...)); 31 char *getbsize __P((char *, int *, long *)); 32 int linkchk __P((FTSENT *)); 33 void usage __P((void)); 34 35 main(argc, argv) 36 int argc; 37 char *argv[]; 38 { 39 register FTS *fts; 40 register FTSENT *p; 41 register int listdirs, listfiles; 42 long blocksize; 43 int aflag, ch, ftsoptions, notused, sflag; 44 char **save; 45 46 ftsoptions = FTS_PHYSICAL; 47 save = argv; 48 aflag = sflag = 0; 49 while ((ch = getopt(argc, argv, "aksx")) != EOF) 50 switch(ch) { 51 case 'a': 52 aflag = 1; 53 break; 54 case 'k': /* Delete before 4.4BSD. */ 55 (void)fprintf(stderr, "du: -k no longer supported\n"); 56 break; 57 case 's': 58 sflag = 1; 59 break; 60 case 'x': 61 ftsoptions |= FTS_XDEV; 62 break; 63 case '?': 64 default: 65 usage(); 66 } 67 argv += optind; 68 69 if (aflag) { 70 if (sflag) 71 usage(); 72 listdirs = listfiles = 1; 73 } else if (sflag) 74 listdirs = listfiles = 0; 75 else { 76 listfiles = 0; 77 listdirs = 1; 78 } 79 80 if (!*argv) { 81 argv = save; 82 argv[0] = "."; 83 argv[1] = NULL; 84 } 85 86 (void)getbsize("du", ¬used, &blocksize); 87 blocksize /= 512; 88 89 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 90 err("%s", strerror(errno)); 91 92 while (p = fts_read(fts)) 93 switch(p->fts_info) { 94 case FTS_D: 95 break; 96 case FTS_DP: 97 p->fts_parent->fts_number += 98 p->fts_number += p->fts_statp->st_blocks; 99 /* 100 * If listing each directory, or not listing files 101 * or directories and this is post-order of the 102 * root of a traversal, display the total. 103 */ 104 if (listdirs || !listfiles && !p->fts_level) 105 (void)printf("%ld\t%s\n", 106 howmany(p->fts_number, blocksize), 107 p->fts_path); 108 break; 109 case FTS_DNR: 110 case FTS_ERR: 111 case FTS_NS: 112 (void)fprintf(stderr, 113 "du: %s: %s\n", p->fts_path, strerror(errno)); 114 break; 115 case FTS_SL: 116 if (p->fts_level == FTS_ROOTLEVEL) { 117 (void)fts_set(fts, p, FTS_FOLLOW); 118 break; 119 } 120 /* FALLTHROUGH */ 121 default: 122 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 123 break; 124 /* 125 * If listing each file, or a non-directory file was 126 * the root of a traversal, display the total. 127 */ 128 if (listfiles || !p->fts_level) 129 (void)printf("%ld\t%s\n", 130 howmany(p->fts_statp->st_blocks, blocksize), 131 p->fts_path); 132 p->fts_parent->fts_number += p->fts_statp->st_blocks; 133 } 134 if (errno) 135 err("%s", strerror(errno)); 136 exit(0); 137 } 138 139 typedef struct _ID { 140 dev_t dev; 141 ino_t inode; 142 } ID; 143 144 int 145 linkchk(p) 146 register FTSENT *p; 147 { 148 static ID *files; 149 static int maxfiles, nfiles; 150 register ID *fp, *start; 151 register ino_t ino; 152 register dev_t dev; 153 154 ino = p->fts_statp->st_ino; 155 dev = p->fts_statp->st_dev; 156 if (start = files) 157 for (fp = start + nfiles - 1; fp >= start; --fp) 158 if (ino == fp->inode && dev == fp->dev) 159 return(1); 160 161 if (nfiles == maxfiles && (files = realloc((char *)files, 162 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 163 err("%s", strerror(errno)); 164 files[nfiles].inode = ino; 165 files[nfiles].dev = dev; 166 ++nfiles; 167 return(0); 168 } 169 170 void 171 usage() 172 { 173 (void)fprintf(stderr, "usage: du [-a | -s] [-x] [file ...]\n"); 174 exit(1); 175 } 176 177 #if __STDC__ 178 #include <stdarg.h> 179 #else 180 #include <varargs.h> 181 #endif 182 183 void 184 #if __STDC__ 185 err(const char *fmt, ...) 186 #else 187 err(fmt, va_alist) 188 char *fmt; 189 va_dcl 190 #endif 191 { 192 va_list ap; 193 #if __STDC__ 194 va_start(ap, fmt); 195 #else 196 va_start(ap); 197 #endif 198 (void)fprintf(stderr, "du: "); 199 (void)vfprintf(stderr, fmt, ap); 200 va_end(ap); 201 (void)fprintf(stderr, "\n"); 202 exit(1); 203 /* NOTREACHED */ 204 } 205