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.10 (Berkeley) 03/21/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 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_D: 81 break; 82 case FTS_DP: 83 p->fts_parent->fts_number += 84 p->fts_number += p->fts_statb.st_blocks; 85 /* 86 * If listing each directory, or not listing files 87 * or directories and this is post-order of the 88 * root of a traversal, display the total. 89 */ 90 if (listdirs || !listfiles && !p->fts_level) 91 (void)printf("%ld\t%s\n", kvalue ? 92 howmany(p->fts_number, 2) : 93 p->fts_number, p->fts_path); 94 break; 95 case FTS_DNR: 96 case FTS_ERR: 97 case FTS_NS: 98 (void)fprintf(stderr, 99 "du: %s: %s.\n", p->fts_path, strerror(errno)); 100 break; 101 default: 102 if (p->fts_statb.st_nlink > 1 && linkchk(p)) 103 break; 104 /* 105 * If listing each file, or a non-directory file was 106 * the root of a traversal, display the total. 107 */ 108 if (listfiles || !p->fts_level) 109 (void)printf("%ld\t%s\n", kvalue ? 110 howmany(p->fts_statb.st_blocks, 2) : 111 p->fts_statb.st_blocks, p->fts_path); 112 p->fts_parent->fts_number += p->fts_statb.st_blocks; 113 } 114 exit(0); 115 } 116 117 typedef struct _ID { 118 dev_t dev; 119 ino_t inode; 120 } ID; 121 122 linkchk(p) 123 register FTSENT *p; 124 { 125 static ID *files; 126 static int maxfiles, nfiles; 127 register ID *fp, *start; 128 register ino_t ino; 129 register dev_t dev; 130 131 ino = p->fts_statb.st_ino; 132 dev = p->fts_statb.st_dev; 133 if (start = files) 134 for (fp = start + nfiles - 1; fp >= start; --fp) 135 if (ino == fp->inode && dev == fp->dev) 136 return(1); 137 138 if (nfiles == maxfiles && !(files = (ID *)realloc((char *)files, 139 (u_int)(sizeof(ID) * (maxfiles += 128))))) { 140 (void)fprintf(stderr, "du: %s\n", strerror(errno)); 141 exit(1); 142 } 143 files[nfiles].inode = ino; 144 files[nfiles].dev = dev; 145 ++nfiles; 146 return(0); 147 } 148