Added a working pdu.
authorFredrik Tolf <fredrik@dolda2000.com>
Sat, 10 Jun 2017 03:57:17 +0000 (05:57 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Sat, 10 Jun 2017 03:57:17 +0000 (05:57 +0200)
pdu.c [new file with mode: 0644]

diff --git a/pdu.c b/pdu.c
new file mode 100644 (file)
index 0000000..96fd61b
--- /dev/null
+++ b/pdu.c
@@ -0,0 +1,152 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <dpar.h>
+#include <stdatomic.h>
+
+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:
+ */