du.c (3151B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <dirent.h> 3 #include <limits.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <sys/stat.h> 8 #include <sys/types.h> 9 #include <unistd.h> 10 11 #include "util.h" 12 13 static long blksize = 512; 14 static char file[PATH_MAX]; 15 static long depth = -1; 16 static long curdepth = 0; 17 18 static int aflag = 0; 19 static int dflag = 0; 20 static int sflag = 0; 21 static int kflag = 0; 22 static int hflag = 0; 23 24 static long du(const char *); 25 static void print(long n, char *path); 26 27 static void 28 usage(void) 29 { 30 eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [file...]\n", argv0); 31 } 32 33 static char * 34 xrealpath(const char *pathname, char *resolved) 35 { 36 char *r; 37 38 r = realpath(pathname, resolved); 39 if (!r) 40 eprintf("realpath: %s:", pathname); 41 return r; 42 } 43 44 int 45 main(int argc, char *argv[]) 46 { 47 char *bsize; 48 long n; 49 50 ARGBEGIN { 51 case 'a': 52 aflag = 1; 53 break; 54 case 'd': 55 dflag = 1; 56 depth = estrtol(EARGF(usage()), 0); 57 break; 58 case 's': 59 sflag = 1; 60 break; 61 case 'k': 62 kflag = 1; 63 break; 64 case 'h': 65 hflag = 1; 66 break; 67 default: 68 usage(); 69 } ARGEND; 70 71 if ((aflag && sflag) || (dflag && sflag)) 72 usage(); 73 74 bsize = getenv("BLOCKSIZE"); 75 if (bsize) 76 blksize = estrtol(bsize, 0); 77 78 if (kflag) 79 blksize = 1024; 80 81 if (argc < 1) { 82 n = du("."); 83 if (sflag) 84 print(n, xrealpath(".", file)); 85 } else { 86 for (; argc > 0; argc--, argv++) { 87 curdepth = 0; 88 n = du(argv[0]); 89 if (sflag) 90 print(n, xrealpath(argv[0], file)); 91 } 92 } 93 return 0; 94 } 95 96 static void 97 print(long n, char *path) 98 { 99 if (hflag) 100 printf("%s\t%s\n", humansize(n * blksize), path); 101 else 102 printf("%lu\t%s\n", n, path); 103 } 104 105 static char * 106 push(const char *path) 107 { 108 char *cwd; 109 110 cwd = agetcwd(); 111 if (chdir(path) < 0) 112 eprintf("chdir: %s:", path); 113 return cwd; 114 } 115 116 static void 117 pop(char *path) 118 { 119 if (chdir(path) < 0) 120 eprintf("chdir: %s:", path); 121 free(path); 122 } 123 124 static long 125 nblks(struct stat *st) 126 { 127 return (512 * st->st_blocks + blksize - 1) / blksize; 128 } 129 130 static long 131 du(const char *path) 132 { 133 DIR *dp; 134 char *cwd; 135 struct dirent *dent; 136 struct stat st; 137 long n = 0, m, t; 138 int r; 139 140 if (lstat(path, &st) < 0) 141 eprintf("stat: %s:", path); 142 n = nblks(&st); 143 144 if (!S_ISDIR(st.st_mode)) 145 goto done; 146 147 dp = opendir(path); 148 if (!dp) { 149 weprintf("opendir %s:", path); 150 goto done; 151 } 152 153 cwd = push(path); 154 while ((dent = readdir(dp))) { 155 if (strcmp(dent->d_name, ".") == 0 || 156 strcmp(dent->d_name, "..") == 0) 157 continue; 158 if (lstat(dent->d_name, &st) < 0) 159 eprintf("stat: %s:", dent->d_name); 160 if (S_ISDIR(st.st_mode)) { 161 t = curdepth; 162 curdepth++; 163 n += du(dent->d_name); 164 curdepth = t; 165 continue; 166 } 167 m = nblks(&st); 168 n += m; 169 if (aflag && !sflag) { 170 if (S_ISLNK(st.st_mode)) { 171 r = snprintf(file, sizeof(file), "%s/%s", 172 cwd, dent->d_name); 173 if (r >= sizeof(file) || r < 0) 174 eprintf("path too long\n"); 175 } else { 176 xrealpath(dent->d_name, file); 177 } 178 if (!dflag || (depth != -1 && curdepth < depth)) 179 print(m, file); 180 } 181 } 182 pop(cwd); 183 closedir(dp); 184 185 done: 186 if (!sflag && (!dflag || (depth != -1 && curdepth <= depth))) 187 print(n, xrealpath(path, file)); 188 return n; 189 }