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.20 (Berkeley) 03/07/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 char *getbsize __P((char *, int *, long *)); 33 int linkchk __P((FTSENT *)); 34 void usage __P((void)); 35 36 int 37 main(argc, argv) 38 int argc; 39 char *argv[]; 40 { 41 register FTS *fts; 42 register FTSENT *p; 43 register int listdirs, listfiles; 44 long blocksize; 45 int aflag, ch, ftsoptions, notused, sflag; 46 char **save; 47 48 ftsoptions = FTS_PHYSICAL; 49 save = argv; 50 aflag = sflag = 0; 51 while ((ch = getopt(argc, argv, "Hahsx")) != EOF) 52 switch(ch) { 53 case 'H': 54 ftsoptions |= FTS_COMFOLLOW; 55 break; 56 case 'a': 57 aflag = 1; 58 break; 59 case 'h': 60 ftsoptions &= ~FTS_PHYSICAL; 61 ftsoptions |= FTS_LOGICAL; 62 break; 63 case 's': 64 sflag = 1; 65 break; 66 case 'x': 67 ftsoptions |= FTS_XDEV; 68 break; 69 case '?': 70 default: 71 usage(); 72 } 73 argv += optind; 74 75 if (aflag) { 76 if (sflag) 77 usage(); 78 listdirs = listfiles = 1; 79 } else if (sflag) 80 listdirs = listfiles = 0; 81 else { 82 listfiles = 0; 83 listdirs = 1; 84 } 85 86 if (!*argv) { 87 argv = save; 88 argv[0] = "."; 89 argv[1] = NULL; 90 } 91 92 (void)getbsize("du", ¬used, &blocksize); 93 blocksize /= 512; 94 95 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) 96 err(1, ""); 97 98 while (p = fts_read(fts)) 99 switch(p->fts_info) { 100 case FTS_D: 101 break; 102 case FTS_DP: 103 p->fts_parent->fts_number += 104 p->fts_number += p->fts_statp->st_blocks; 105 /* 106 * If listing each directory, or not listing files 107 * or directories and this is post-order of the 108 * root of a traversal, display the total. 109 */ 110 if (listdirs || !listfiles && !p->fts_level) 111 (void)printf("%ld\t%s\n", 112 howmany(p->fts_number, blocksize), 113 p->fts_path); 114 break; 115 case FTS_DNR: 116 case FTS_ERR: 117 case FTS_NS: 118 warn("%s", p->fts_path); 119 break; 120 default: 121 if (p->fts_statp->st_nlink > 1 && linkchk(p)) 122 break; 123 /* 124 * If listing each file, or a non-directory file was 125 * the root of a traversal, display the total. 126 */ 127 if (listfiles || !p->fts_level) 128 (void)printf("%qd\t%s\n", 129 howmany(p->fts_statp->st_blocks, blocksize), 130 p->fts_path); 131 p->fts_parent->fts_number += p->fts_statp->st_blocks; 132 } 133 if (errno) 134 err(1, ""); 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 err(1, ""); 163 files[nfiles].inode = ino; 164 files[nfiles].dev = dev; 165 ++nfiles; 166 return(0); 167 } 168 169 void 170 usage() 171 { 172 (void)fprintf(stderr, "usage: du [-a | -s] [-Hhx] [file ...]\n"); 173 exit(1); 174 } 175