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.8 (Berkeley) 11/21/90"; 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 ch, ftsoptions; 39 char **save; 40 41 ftsoptions = FTS_PHYSICAL; 42 kvalue = listfiles = 0; 43 listdirs = 1; 44 save = argv; 45 while ((ch = getopt(argc, argv, "aksx")) != EOF) 46 switch(ch) { 47 case 'a': 48 listfiles = 1; 49 break; 50 case 'k': 51 kvalue = 1; 52 break; 53 case 's': 54 listfiles = listdirs = 0; 55 break; 56 case 'x': 57 ftsoptions |= FTS_XDEV; 58 break; 59 case '?': 60 default: 61 (void)fprintf(stderr, 62 "usage: du [-aksx] [name ...]\n"); 63 exit(1); 64 } 65 argv += optind; 66 67 if (!*argv) { 68 argv = save; 69 argv[0] = "."; 70 argv[1] = NULL; 71 } 72 73 if (!(fts = fts_open(argv, ftsoptions, (int (*)())NULL))) { 74 (void)fprintf(stderr, "du: %s.\n", strerror(errno)); 75 exit(1); 76 } 77 78 while (p = fts_read(fts)) 79 switch(p->fts_info) { 80 case FTS_DNR: 81 (void)fprintf(stderr, 82 "du: %s: unable to read.\n", p->fts_path); 83 break; 84 case FTS_DNX: 85 (void)fprintf(stderr, 86 "du: %s: unable to search.\n", p->fts_path); 87 break; 88 case FTS_D: 89 case FTS_DC: 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_ERR: 105 (void)fprintf(stderr, 106 "du: %s: %s.\n", p->fts_path, strerror(errno)); 107 exit(1); 108 case FTS_NS: 109 (void)fprintf(stderr, 110 "du: unable to stat: %s.\n", p->fts_path); 111 break; 112 default: 113 if (p->fts_statb.st_nlink > 1 && linkchk(p)) 114 break; 115 /* 116 * If listing each file, or a non-directory file was 117 * the root of a traversal, display the total. 118 */ 119 if (listfiles || !p->fts_level) 120 (void)printf("%ld\t%s\n", kvalue ? 121 howmany(p->fts_statb.st_blocks, 2) : 122 p->fts_statb.st_blocks, p->fts_path); 123 p->fts_parent->fts_number += p->fts_statb.st_blocks; 124 } 125 exit(0); 126 } 127 128 typedef struct _ID { 129 dev_t dev; 130 ino_t inode; 131 } ID; 132 133 linkchk(p) 134 register FTSENT *p; 135 { 136 static ID *files; 137 static int maxfiles, nfiles; 138 register ID *fp, *start; 139 register ino_t ino; 140 register dev_t dev; 141 142 ino = p->fts_statb.st_ino; 143 dev = p->fts_statb.st_dev; 144 if (start = files) 145 for (fp = start + nfiles - 1; fp >= start; --fp) 146 if (ino == fp->inode && dev == fp->dev) 147 return(1); 148 149 if (nfiles == maxfiles && !(files = (ID *)realloc((char *)files, 150 (u_int)(sizeof(ID) * (maxfiles += 128))))) { 151 (void)fprintf(stderr, "du: %s\n", strerror(errno)); 152 exit(1); 153 } 154 files[nfiles].inode = ino; 155 files[nfiles].dev = dev; 156 ++nfiles; 157 return(0); 158 } 159