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.22 (Berkeley) 06/02/93"; 19 #endif /* not lint */ 20 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 24 #include <dirent.h> 25 #include <err.h> 26 #include <errno.h> 27 #include <fts.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 int linkchk __P((FTSENT *)); 33 void usage __P((void)); 34 35 int 36 main(argc, argv) 37 int argc; 38 char *argv[]; 39 { 40 register FTS *fts; 41 register FTSENT *p; 42 register int listdirs, listfiles; 43 long blocksize; 44 int aflag, ch, ftsoptions, notused, sflag; 45 char **save; 46 47 ftsoptions = FTS_PHYSICAL; 48 save = argv; 49 aflag = sflag = 0; 50 while ((ch = getopt(argc, argv, "Hahsx")) != EOF) 51 switch(ch) { 52 case 'H': 53 ftsoptions |= FTS_COMFOLLOW; 54 break; 55 case 'a': 56 aflag = 1; 57 break; 58 case 'h': 59 ftsoptions &= ~FTS_PHYSICAL; 60 ftsoptions |= FTS_LOGICAL; 61 break; 62 case 's': 63 sflag = 1; 64 break; 65 case 'x': 66 ftsoptions |= FTS_XDEV; 67 break; 68 case '?': 69 default: 70 usage(); 71 } 72 argv += optind; 73 74 if (aflag) { 75 if (sflag) 76 usage(); 77 listdirs = listfiles = 1; 78 } else if (sflag) 79 listdirs = listfiles = 0; 80 else { 81 listfiles = 0; 82 listdirs = 1; 83 } 84 85 if (!*argv) { 86 argv = save; 87 argv[0] = "."; 88 argv[1] = NULL; 89 } 90 91 (void)getbsize(¬used, &blocksize); 92 blocksize /= 512; 93 94 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 95 err(1, ""); 96 97 while (p = fts_read(fts)) 98 switch(p->fts_info) { 99 case FTS_D: 100 break; 101 case FTS_DP: 102 p->fts_parent->fts_number += 103 p->fts_number += p->fts_statp->st_blocks; 104 /* 105 * If listing each directory, or not listing files 106 * or directories and this is post-order of the 107 * root of a traversal, display the total. 108 */ 109 if (listdirs || !listfiles && !p->fts_level) 110 (void)printf("%ld\t%s\n", 111 howmany(p->fts_number, blocksize), 112 p->fts_path); 113 break; 114 case FTS_DNR: 115 case FTS_ERR: 116 case FTS_NS: 117 warn("%s", p->fts_path); 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(1, ""); 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(1, ""); 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