chiark / gitweb /
initial checkin, found stuff
authorian <ian>
Sat, 20 Dec 2003 17:46:03 +0000 (17:46 +0000)
committerian <ian>
Sat, 20 Dec 2003 17:46:03 +0000 (17:46 +0000)
cprogs/summer.c [new file with mode: 0644]

diff --git a/cprogs/summer.c b/cprogs/summer.c
new file mode 100644 (file)
index 0000000..2e169a1
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * usage:
+ *    cat startpoints.list | summer >data.list
+ *    summer startpoints... >data.list
+ *  prints md5sum of data-list to stderr
+ */
+
+#define _GNU_SOURCE
+
+#include <ftw.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "md5.h"
+
+#define MAXFN 2048
+#define MAXDEPTH 1024
+
+static void fn_escaped(FILE *f, const char *fn) {
+  int c;
+  while ((c= *fn++)) {
+    if (c>=33 && c<=126) putc(c,f);
+    else fprintf(f,"\\x%02x",(int)(unsigned char)c);
+  }
+}
+
+static void undoable(const char *path, const char *fmt, ...) {
+  va_list(al);
+  va_start(al,fmt);
+  fputs("summer: ", stderr);
+  vfprintf(stderr, fmt, al);
+  fn_escaped(stderr, path);
+  putc('\n',stderr);
+  exit(4);
+}  
+
+static void unreadable(const char *path, const char *doing) {
+  undoable(path, "unreadable: %s: %s: ", strerror(errno), doing);
+}
+
+static void csum_file(const char *path) {
+  FILE *f;
+  struct MD5Context mc;
+  char db[65536];
+  unsigned char digest[16];
+  size_t r;
+  int i;
+
+  f= fopen(path,"rb");   if (!f) unreadable(path, "open");
+  MD5Init(&mc);
+  for (;;) {
+    r= fread(db,1,sizeof(db),f);
+    if (ferror(f)) unreadable(path, "read");
+    if (!r) { assert(feof(f)); break; }
+    MD5Update(&mc,db,r);
+  }
+  MD5Final(digest,&mc);
+  if (fclose(f)) unreadable(path, "close");
+
+  for (i=0; i<sizeof(digest); i++)
+    printf("%02x", digest[i]);
+}
+
+static void csum_dev(int cb, const struct stat *stab) {
+  printf("%c 0x%08lx %3lu %3lu %3lu %3lu    ", cb,
+        (unsigned long)stab->st_rdev,
+        ((unsigned long)stab->st_rdev & 0x0ff000000U) >> 24,
+        ((unsigned long)stab->st_rdev & 0x000ff0000U) >> 16,
+        ((unsigned long)stab->st_rdev & 0x00000ff00U) >> 8,
+        ((unsigned long)stab->st_rdev & 0x0000000ffU) >> 0);
+}
+
+static void csum_str(const char *s) {
+  printf("%-32s", s);
+}
+
+struct FTW;
+
+static int item(const char *path, const struct stat *stab,
+               int flag, struct FTW *ftws) {
+  switch (flag) {
+  case FTW_D:
+  case FTW_F:
+  case FTW_SL:
+    if (S_ISREG(stab->st_mode)) csum_file(path);
+    else if (S_ISDIR(stab->st_mode)) csum_str("dir");
+    else if (S_ISCHR(stab->st_mode)) csum_dev('c',stab);
+    else if (S_ISBLK(stab->st_mode)) csum_dev('b',stab);
+    else if (S_ISFIFO(stab->st_mode)) csum_str("pipe");
+    else if (S_ISLNK(stab->st_mode)) csum_str("link");
+    else if (S_ISSOCK(stab->st_mode)) csum_str("sock");
+    else undoable(path, "badobj: 0x%lx: ", (unsigned long)stab->st_mode);
+    break;
+
+  case FTW_NS:
+  case FTW_DNR:
+    undoable(path,"inaccessible: %s: ", strerror(errno));
+
+  default:
+    undoable(path,"ftw flag 0x%x: %s: ", flag);
+  }
+
+  printf(" %10lu %4d %4o %10ld %10ld %10lu %10lu %10lu ",
+        (unsigned long)stab->st_size,
+        (int)stab->st_nlink,
+        (unsigned)stab->st_mode & 07777U,
+        (unsigned long)stab->st_uid,
+        (unsigned long)stab->st_gid,
+        (unsigned long)stab->st_atime,
+        (unsigned long)stab->st_mtime,
+        (unsigned long)stab->st_ctime);
+  fn_escaped(stdout, path);
+
+  if (S_ISLNK(stab->st_mode)) {
+    char linktarg[MAXFN+1];
+    int r;
+
+    r= readlink(path, linktarg, sizeof(linktarg)-1);
+    if (r==sizeof(linktarg)) undoable(path,"readlink too big");
+    if (r<0) undoable(path,"readlink: %s: ", strerror(errno));
+
+    linktarg[r]= 0;
+
+    printf(" -> ");
+    fn_escaped(stdout, linktarg);
+  }
+  putchar('\n');
+
+  if (ferror(stdout)) { perror("summer: stdout"); exit(12); }
+  return 0;
+}
+
+static void process(const char *startpoint) {
+  int r;
+  fprintf(stderr,"summer: processing: %s\n",startpoint);
+  r= nftw(startpoint, item, MAXDEPTH, FTW_MOUNT|FTW_PHYS);
+  if (r) { fprintf(stderr, "summer: nftw failed: %s: %s\n",
+                  strerror(errno), startpoint); exit(4); }
+}
+
+static void from_stdin(void) {
+  char buf[MAXFN+2];
+  char *s;
+  int l;
+  
+  fprintf(stderr, "summer: processing stdin lines as startpoints\n");
+  for (;;) {
+    s= fgets(buf,sizeof(buf),stdin);
+    if (ferror(stdin)) { perror("summer: stdin"); exit(12); }
+    if (!s) { if (feof(stdin)) return; else abort(); }
+    l= strlen(buf);
+    assert(l>0);
+    if (buf[l-1]!='\n') { fprintf(stderr,"summer: line too long\n"); exit(8); }
+    buf[l-1]= 0;
+    process(buf);
+  }
+}
+
+int main(int argc, const char *const *argv) {
+  const char *arg;
+  
+  if (!argv[1]) {
+    from_stdin();
+  } else if (argv[1][0]=='h') {
+    fprintf(stderr,
+           "summer: usage: summer startpoint... >data.list\n"
+           "               cat startpoints.list | summer >data.list\n");
+    return 8;
+  } else {
+    fprintf(stderr, "summer: processing command line args as startpoints\n");
+    while ((arg=*++argv)) {
+      process(arg);
+    }
+  }
+  if (ferror(stdout) || fclose(stdout)) {
+    perror("summer: stdout (at end)"); exit(12);
+  }
+  fputs("summer: done.\n", stderr);
+  return 0;
+}