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.19 (Berkeley) 06/22/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, "Hahsx")) != EOF) 50 switch(ch) { 51 case 'H': 52 ftsoptions |= FTS_COMFOLLOW; 53 break; 54 case 'a': 55 aflag = 1; 56 break; 57 case 'h': 58 ftsoptions &= ~FTS_PHYSICAL; 59 ftsoptions |= FTS_LOGICAL; 60 break; 61 case 's': 62 sflag = 1; 63 break; 64 case 'x': 65 ftsoptions |= FTS_XDEV; 66 break; 67 case '?': 68 default: 69 usage(); 70 } 71 argv += optind; 72 73 if (aflag) { 74 if (sflag) 75 usage(); 76 listdirs = listfiles = 1; 77 } else if (sflag) 78 listdirs = listfiles = 0; 79 else { 80 listfiles = 0; 81 listdirs = 1; 82 } 83 84 if (!*argv) { 85 argv = save; 86 argv[0] = "."; 87 argv[1] = NULL; 88 } 89 90 (void)getbsize("du", ¬used, &blocksize); 91 blocksize /= 512; 92 93 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 94 err("%s", strerror(errno)); 95 96 while (p = fts_read(fts)) 97 switch(p->fts_info) { 98 case FTS_D: 99 break; 100 case FTS_DP: 101 p->fts_parent->fts_number += 102 p->fts_number += p->fts_statp->st_blocks; 103 /* 104 * If listing each directory, or not listing files 105 * or directories and this is post-order of the 106 * root of a traversal, display the total. 107 */ 108 if (listdirs || !listfiles && !p->fts_level) 109 (void)printf("%ld\t%s\n", 110 howmany(p->fts_number, blocksize), 111 p->fts_path); 112 break; 113 case FTS_DNR: 114 case FTS_ERR: 115 case FTS_NS: 116 (void)fprintf(stderr, 117 "du: %s: %s\n", p->fts_path, strerror(errno)); 118 break; 119 default: 120 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 121 break; 122 /* 123 * If listing each file, or a non-directory file was 124 * the root of a traversal, display the total. 125 */ 126 if (listfiles || !p->fts_level) 127 (void)printf("%qd\t%s\n", 128 howmany(p->fts_statp->st_blocks, blocksize), 129 p->fts_path); 130 p->fts_parent->fts_number += p->fts_statp->st_blocks; 131 } 132 if (errno) 133 err("%s", strerror(errno)); 134 exit(0); 135 } 136 137 typedef struct _ID { 138 dev_t dev; 139 ino_t inode; 140 } ID; 141 142 int 143 linkchk(p) 144 register FTSENT *p; 145 { 146 static ID *files; 147 static int maxfiles, nfiles; 148 register ID *fp, *start; 149 register ino_t ino; 150 register dev_t dev; 151 152 ino = p->fts_statp->st_ino; 153 dev = p->fts_statp->st_dev; 154 if (start = files) 155 for (fp = start + nfiles - 1; fp >= start; --fp) 156 if (ino == fp->inode && dev == fp->dev) 157 return(1); 158 159 if (nfiles == maxfiles && (files = realloc((char *)files, 160 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) 161 err("%s", strerror(errno)); 162 files[nfiles].inode = ino; 163 files[nfiles].dev = dev; 164 ++nfiles; 165 return(0); 166 } 167 168 void 169 usage() 170 { 171 (void)fprintf(stderr, "usage: du [-a | -s] [-Hhx] [file ...]\n"); 172 exit(1); 173 } 174 175 #if __STDC__ 176 #include <stdarg.h> 177 #else 178 #include <varargs.h> 179 #endif 180 181 void 182 #if __STDC__ 183 err(const char *fmt, ...) 184 #else 185 err(fmt, va_alist) 186 char *fmt; 187 va_dcl 188 #endif 189 { 190 va_list ap; 191 #if __STDC__ 192 va_start(ap, fmt); 193 #else 194 va_start(ap); 195 #endif 196 (void)fprintf(stderr, "du: "); 197 (void)vfprintf(stderr, fmt, ap); 198 va_end(ap); 199 (void)fprintf(stderr, "\n"); 200 exit(1); 201 /* NOTREACHED */ 202 } 203