chiark / gitweb /
options, -q and -f, for summer
[chiark-utils.git] / cprogs / summer.c
index 70b9400..4f42e60 100644 (file)
@@ -24,6 +24,9 @@
 #define MAXDEPTH 1024
 #define CSUMXL 32
 
+static int quiet=0;
+static FILE *errfile;
+
 static void fn_escaped(FILE *f, const char *fn) {
   int c;
   while ((c= *fn++)) {
@@ -37,27 +40,40 @@ static void add_pr(int *pr, int printf_ret) {
   *pr += printf_ret;
 }
 
-static void vproblemx(int padto, int per, const char *fmt, va_list al) {
+static void vproblemx(const char *path, int padto, int per,
+                     const char *fmt, va_list al) {
   int e=errno, pr=0;
-  add_pr(&pr, printf("\\["));
-  add_pr(&pr, vprintf(fmt,al));
-  if (per) add_pr(&pr, printf(": %s",strerror(e)));
+  
+  if (errfile==stderr) fputs("summer: error: ",stderr);
+  else add_pr(&pr, fprintf(errfile,"\\["));
+  
+  add_pr(&pr, vfprintf(errfile,fmt,al));
+  if (per) add_pr(&pr, fprintf(errfile,": %s",strerror(e)));
+
+  if (errfile==stderr) {
+    fputs(": ",stderr);
+    fn_escaped(stderr,path);
+    fputc('\n',stderr);
+    exit(2);
+  }
+
   add_pr(&pr, printf("]"));
+
   while (pr++ < padto)
     putchar(' ');
 }  
 
-static void problem_e(int padto, const char *fmt, ...) {
+static void problem_e(const char *path, int padto, const char *fmt, ...) {
   va_list(al);
   va_start(al,fmt);
-  vproblemx(padto,1,fmt,al);
+  vproblemx(path,padto,1,fmt,al);
   va_end(al);
 }
 
-static void problem(int padto, const char *fmt, ...) {
+static void problem(const char *path, int padto, const char *fmt, ...) {
   va_list(al);
   va_start(al,fmt);
-  vproblemx(padto,0,fmt,al);
+  vproblemx(path,padto,0,fmt,al);
   va_end(al);
 }
 
@@ -70,17 +86,20 @@ static void csum_file(const char *path) {
   int i;
 
   f= fopen(path,"rb");
-  if (!f) { problem_e(sizeof(digest)*2,"open"); return; }
+  if (!f) { problem_e(path,sizeof(digest)*2,"open"); return; }
   
   MD5Init(&mc);
   for (;;) {
     r= fread(db,1,sizeof(db),f);
-    if (ferror(f)) { problem_e(sizeof(digest)*2,"read"); fclose(f); return; }
+    if (ferror(f)) {
+      problem_e(path,sizeof(digest)*2,"read");
+      fclose(f); return;
+    }
     if (!r) { assert(feof(f)); break; }
     MD5Update(&mc,db,r);
   }
   MD5Final(digest,&mc);
-  if (fclose(f)) { problem_e(sizeof(digest)*2,"close"); return; }
+  if (fclose(f)) { problem_e(path,sizeof(digest)*2,"close"); return; }
 
   for (i=0; i<sizeof(digest); i++)
     printf("%02x", digest[i]);
@@ -116,24 +135,24 @@ static int item(const char *path, const struct stat *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 problem(CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
+    else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
     break;
 
   case FTW_NS:
   case FTW_DNR:
-    problem_e(CSUMXL,"inaccessible");
+    problem_e(path,CSUMXL,"inaccessible");
     break;
 
   default:
-    problem(CSUMXL,"ftw flag 0x%x: %s",flag);
+    problem(path,CSUMXL,"ftw flag 0x%x: %s",flag);
   }
 
   if (S_ISLNK(stab->st_mode)) {
     int r;
 
     r= readlink(path, linktarg, sizeof(linktarg)-1);
-    if (r==sizeof(linktarg)) { problem(-1,"readlink too big"); r=-1; }
-    else if (r<0) { problem_e(-1,"readlink"); }
+    if (r==sizeof(linktarg)) { problem(path,-1,"readlink too big"); r=-1; }
+    else if (r<0) { problem_e(path,-1,"readlink"); }
     else assert(r<sizeof(linktarg));
 
     if (r<0) strcpy(linktarg,"\\?");
@@ -163,7 +182,8 @@ static int item(const char *path, const struct stat *stab,
 
 static void process(const char *startpoint) {
   int r;
-  fprintf(stderr,"summer: processing: %s\n",startpoint);
+  if (!quiet)
+    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); }
@@ -173,8 +193,9 @@ static void from_stdin(void) {
   char buf[MAXFN+2];
   char *s;
   int l;
-  
-  fprintf(stderr, "summer: processing stdin lines as startpoints\n");
+
+  if (!quiet)
+    fprintf(stderr, "summer: processing stdin lines as startpoints\n");
   for (;;) {
     s= fgets(buf,sizeof(buf),stdin);
     if (ferror(stdin)) { perror("summer: stdin"); exit(12); }
@@ -189,16 +210,37 @@ static void from_stdin(void) {
 
 int main(int argc, const char *const *argv) {
   const char *arg;
+  int c;
+
+  errfile= stderr;
   
+  if ((arg=argv[1]) && *arg++=='-') {
+    while ((c=*arg++)) {
+      switch (c) {
+      case 'h':
+       fprintf(stderr,
+               "summer: usage: summer startpoint... >data.list\n"
+               "               cat startpoints.list | summer >data.list\n");
+       exit(8);
+      case 'q':
+       quiet= 1;
+       break;
+      case 'f':
+       errfile= stdout;
+       break;
+      default:
+       fprintf(stderr,"summer: bad usage, try -h\n");
+       exit(8);
+      }
+    }
+    argv++;
+  }
+
   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");
+    if (!quiet)
+      fprintf(stderr, "summer: processing command line args as startpoints\n");
     while ((arg=*++argv)) {
       process(arg);
     }
@@ -206,6 +248,7 @@ int main(int argc, const char *const *argv) {
   if (ferror(stdout) || fclose(stdout)) {
     perror("summer: stdout (at end)"); exit(12);
   }
-  fputs("summer: done.\n", stderr);
+  if (!quiet)
+    fputs("summer: done.\n", stderr);
   return 0;
 }