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