From: Fredrik Tolf Date: Sat, 10 Jun 2017 03:57:17 +0000 (+0200) Subject: Added a working pdu. X-Git-Url: http://git.dolda2000.com/gitweb/?a=commitdiff_plain;h=d91cef4e2a9099c537505575904e458f489cc947;p=utils.git Added a working pdu. --- diff --git a/pdu.c b/pdu.c new file mode 100644 index 0000000..96fd61b --- /dev/null +++ b/pdu.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct subdir { + struct subdir *parent; + char *path; + off_t sum; + int rv, subjobs, summary; +}; + +static int summary = 0; +static int retval = 0; + +static char *sprintf2(char *fmt, ...) +{ + char *ret; + size_t sz; + FILE *fp; + va_list args; + + fp = open_memstream(&ret, &sz); + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); + fclose(fp); + return(ret); +} + +static void printres(struct subdir *job) +{ + printf("%ji\t%s\n", (intmax_t)(job->sum / 1024), job->path); +} + +static void finish(struct subdir *job) +{ + if(atomic_fetch_sub(&job->subjobs, 1) == 1) { + if(job->summary) + printres(job); + if(job->parent) { + atomic_fetch_add(&job->parent->sum, job->sum); + finish(job->parent); + } + free(job->path); + free(job); + } +} + +static void dodir(void *jobp) +{ + struct subdir *job = jobp; + DIR *dp; + struct dirent *dent, dbuf; + struct stat sb; + struct subdir *nj; + char *ep; + + if((dp = opendir(job->path)) == NULL) { + fprintf(stderr, "pdu: %s: %s\n", job->path, strerror(errno)); + job->rv = 1; + return; + } + job->subjobs = 1; + while(1) { + if(readdir_r(dp, &dbuf, &dent)) { + fprintf(stderr, "pdu: reading %s: %s\n", job->path, strerror(errno)); + job->rv = 1; + break; + } + if(!dent) + break; + if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; + ep = sprintf2("%s/%s", job->path, dent->d_name); + if(stat(ep, &sb)) { + fprintf(stderr, "pdu: stat %s: %s\n", ep, strerror(errno)); + } else { + if(S_ISDIR(sb.st_mode)) { + *(nj = malloc(sizeof(*nj))) = (struct subdir) { + .path = strdup(ep), + .summary = !summary, + .parent = job, + }; + atomic_fetch_add(&job->subjobs, 1); + atomic_fetch_add(&job->sum, (off_t)sb.st_blocks * 512); + submitiowork(dodir, nj); + } else if(S_ISREG(sb.st_mode)) { + atomic_fetch_add(&job->sum, (off_t)sb.st_blocks * 512); + } + } + free(ep); + } + closedir(dp); + finish(job); +} + +static void dodu(char *path) +{ + struct subdir *job; + + *(job = malloc(sizeof(*job))) = (struct subdir) { + .path = strdup(path), + .summary = 1, + }; + submitiowork(dodir, job); +} + +static void usage(FILE *out) +{ + fprintf(out, "usage: pdu [-sh] [DIRECTORY...]\n"); +} + +int main(int argc, char **argv) +{ + int i, c; + + while((c = getopt(argc, argv, "hs")) != -1) { + switch(c) { + case 's': + summary = 1; + break; + case 'h': + usage(stdout); + exit(0); + default: + usage(stderr); + exit(1); + } + } + if(optind < argc) { + for(i = optind; i < argc; i++) + dodu(argv[i]); + } else { + dodu("."); + } + joinwork(); + return(retval); +} + +/* + * Local Variables: + * compile-command: "gcc -Wall -g -o pdu pdu.c -ldpar" + * End: + */