Commit | Line | Data |
---|---|---|
d91cef4e FT |
1 | #include <stdlib.h> |
2 | #include <stdio.h> | |
3 | #include <string.h> | |
4 | #include <unistd.h> | |
5 | #include <errno.h> | |
6 | #include <dirent.h> | |
7 | #include <stdarg.h> | |
8 | #include <stdint.h> | |
9 | #include <sys/stat.h> | |
10 | #include <dpar.h> | |
11 | #include <stdatomic.h> | |
12 | ||
13 | struct subdir { | |
14 | struct subdir *parent; | |
15 | char *path; | |
16 | off_t sum; | |
17 | int rv, subjobs, summary; | |
18 | }; | |
19 | ||
20 | static int summary = 0; | |
21 | static int retval = 0; | |
22 | ||
23 | static char *sprintf2(char *fmt, ...) | |
24 | { | |
25 | char *ret; | |
26 | size_t sz; | |
27 | FILE *fp; | |
28 | va_list args; | |
29 | ||
30 | fp = open_memstream(&ret, &sz); | |
31 | va_start(args, fmt); | |
32 | vfprintf(fp, fmt, args); | |
33 | va_end(args); | |
34 | fclose(fp); | |
35 | return(ret); | |
36 | } | |
37 | ||
38 | static void printres(struct subdir *job) | |
39 | { | |
40 | printf("%ji\t%s\n", (intmax_t)(job->sum / 1024), job->path); | |
41 | } | |
42 | ||
43 | static void finish(struct subdir *job) | |
44 | { | |
45 | if(atomic_fetch_sub(&job->subjobs, 1) == 1) { | |
46 | if(job->summary) | |
47 | printres(job); | |
48 | if(job->parent) { | |
49 | atomic_fetch_add(&job->parent->sum, job->sum); | |
50 | finish(job->parent); | |
51 | } | |
52 | free(job->path); | |
53 | free(job); | |
54 | } | |
55 | } | |
56 | ||
57 | static void dodir(void *jobp) | |
58 | { | |
59 | struct subdir *job = jobp; | |
60 | DIR *dp; | |
61 | struct dirent *dent, dbuf; | |
62 | struct stat sb; | |
63 | struct subdir *nj; | |
64 | char *ep; | |
65 | ||
66 | if((dp = opendir(job->path)) == NULL) { | |
67 | fprintf(stderr, "pdu: %s: %s\n", job->path, strerror(errno)); | |
68 | job->rv = 1; | |
69 | return; | |
70 | } | |
71 | job->subjobs = 1; | |
72 | while(1) { | |
73 | if(readdir_r(dp, &dbuf, &dent)) { | |
74 | fprintf(stderr, "pdu: reading %s: %s\n", job->path, strerror(errno)); | |
75 | job->rv = 1; | |
76 | break; | |
77 | } | |
78 | if(!dent) | |
79 | break; | |
80 | if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) | |
81 | continue; | |
82 | ep = sprintf2("%s/%s", job->path, dent->d_name); | |
83 | if(stat(ep, &sb)) { | |
84 | fprintf(stderr, "pdu: stat %s: %s\n", ep, strerror(errno)); | |
85 | } else { | |
86 | if(S_ISDIR(sb.st_mode)) { | |
87 | *(nj = malloc(sizeof(*nj))) = (struct subdir) { | |
88 | .path = strdup(ep), | |
89 | .summary = !summary, | |
90 | .parent = job, | |
91 | }; | |
92 | atomic_fetch_add(&job->subjobs, 1); | |
93 | atomic_fetch_add(&job->sum, (off_t)sb.st_blocks * 512); | |
94 | submitiowork(dodir, nj); | |
95 | } else if(S_ISREG(sb.st_mode)) { | |
96 | atomic_fetch_add(&job->sum, (off_t)sb.st_blocks * 512); | |
97 | } | |
98 | } | |
99 | free(ep); | |
100 | } | |
101 | closedir(dp); | |
102 | finish(job); | |
103 | } | |
104 | ||
105 | static void dodu(char *path) | |
106 | { | |
107 | struct subdir *job; | |
108 | ||
109 | *(job = malloc(sizeof(*job))) = (struct subdir) { | |
110 | .path = strdup(path), | |
111 | .summary = 1, | |
112 | }; | |
113 | submitiowork(dodir, job); | |
114 | } | |
115 | ||
116 | static void usage(FILE *out) | |
117 | { | |
118 | fprintf(out, "usage: pdu [-sh] [DIRECTORY...]\n"); | |
119 | } | |
120 | ||
121 | int main(int argc, char **argv) | |
122 | { | |
123 | int i, c; | |
124 | ||
125 | while((c = getopt(argc, argv, "hs")) != -1) { | |
126 | switch(c) { | |
127 | case 's': | |
128 | summary = 1; | |
129 | break; | |
130 | case 'h': | |
131 | usage(stdout); | |
132 | exit(0); | |
133 | default: | |
134 | usage(stderr); | |
135 | exit(1); | |
136 | } | |
137 | } | |
138 | if(optind < argc) { | |
139 | for(i = optind; i < argc; i++) | |
140 | dodu(argv[i]); | |
141 | } else { | |
142 | dodu("."); | |
143 | } | |
144 | joinwork(); | |
145 | return(retval); | |
146 | } | |
147 | ||
148 | /* | |
149 | * Local Variables: | |
150 | * compile-command: "gcc -Wall -g -o pdu pdu.c -ldpar" | |
151 | * End: | |
152 | */ |