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.15 (Berkeley) 03/09/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 char *getbsize __P((char *, int *, long *)); 31 int linkchk __P((FTSENT *)); 32 void usage __P((void)); 33 34 main(argc, argv) 35 int argc; 36 char *argv[]; 37 { 38 register FTS *fts; 39 register FTSENT *p; 40 register int listdirs, listfiles; 41 long blocksize; 42 int aflag, ch, ftsoptions, notused, sflag; 43 char **save; 44 45 ftsoptions = FTS_PHYSICAL; 46 save = argv; 47 aflag = sflag = 0; 48 while ((ch = getopt(argc, argv, "aksx")) != EOF) 49 switch(ch) { 50 case 'a': 51 aflag = 1; 52 break; 53 case 'k': /* Delete before 4.4BSD. */ 54 (void)fprintf(stderr, "du: -k no longer supported\n"); 55 break; 56 case 's': 57 sflag = 1; 58 break; 59 case 'x': 60 ftsoptions |= FTS_XDEV; 61 break; 62 case '?': 63 default: 64 usage(); 65 } 66 argv += optind; 67 68 if (aflag) { 69 if (sflag) 70 usage(); 71 listdirs = listfiles = 1; 72 } else if (sflag) 73 listdirs = listfiles = 0; 74 else { 75 listfiles = 0; 76 listdirs = 1; 77 } 78 79 if (!*argv) { 80 argv = save; 81 argv[0] = "."; 82 argv[1] = NULL; 83 } 84 85 (void)getbsize("du", ¬used, &blocksize); 86 blocksize /= 512; 87 88 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) { 89 (void)fprintf(stderr, "du: %s\n", strerror(errno)); 90 exit(1); 91 } 92 93 while (p = fts_read(fts)) 94 switch(p->fts_info) { 95 case FTS_D: 96 break; 97 case FTS_DP: 98 p->fts_parent->fts_number += 99 p->fts_number += p->fts_statp->st_blocks; 100 /* 101 * If listing each directory, or not listing files 102 * or directories and this is post-order of the 103 * root of a traversal, display the total. 104 */ 105 if (listdirs || !listfiles && !p->fts_level) 106 (void)printf("%ld\t%s\n", 107 howmany(p->fts_number, blocksize), 108 p->fts_path); 109 break; 110 case FTS_DNR: 111 case FTS_ERR: 112 case FTS_NS: 113 (void)fprintf(stderr, 114 "du: %s: %s\n", p->fts_path, strerror(errno)); 115 break; 116 case FTS_SL: 117 if (p->fts_level == FTS_ROOTLEVEL) { 118 (void)fts_set(fts, p, FTS_FOLLOW); 119 break; 120 } 121 /* FALLTHROUGH */ 122 default: 123 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 124 break; 125 /* 126 * If listing each file, or a non-directory file was 127 * the root of a traversal, display the total. 128 */ 129 if (listfiles || !p->fts_level) 130 (void)printf("%ld\t%s\n", 131 howmany(p->fts_statp->st_blocks, blocksize), 132 p->fts_path); 133 p->fts_parent->fts_number += p->fts_statp->st_blocks; 134 } 135 exit(0); 136 } 137 138 typedef struct _ID { 139 dev_t dev; 140 ino_t inode; 141 } ID; 142 143 int 144 linkchk(p) 145 register FTSENT *p; 146 { 147 static ID *files; 148 static int maxfiles, nfiles; 149 register ID *fp, *start; 150 register ino_t ino; 151 register dev_t dev; 152 153 ino = p->fts_statp->st_ino; 154 dev = p->fts_statp->st_dev; 155 if (start = files) 156 for (fp = start + nfiles - 1; fp >= start; --fp) 157 if (ino == fp->inode && dev == fp->dev) 158 return(1); 159 160 if (nfiles == maxfiles && (files = realloc((char *)files, 161 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) { 162 (void)fprintf(stderr, "du: %s\n", strerror(errno)); 163 exit(1); 164 } 165 files[nfiles].inode = ino; 166 files[nfiles].dev = dev; 167 ++nfiles; 168 return(0); 169 } 170 171 void 172 usage() 173 { 174 (void)fprintf(stderr, "usage: du [-a | -s] [-x] [file ...]\n"); 175 exit(1); 176 } 177