chiark / gitweb /
do not die straight away on errors
[chiark-utils.git] / cprogs / summer.c
index 2e169a194d6d23fa3a6329397fc5863423bde776..70b94009bd1be24286db619f6d8da6cc21bb868a 100644 (file)
 
 #define MAXFN 2048
 #define MAXDEPTH 1024
+#define CSUMXL 32
 
 static void fn_escaped(FILE *f, const char *fn) {
   int c;
   while ((c= *fn++)) {
-    if (c>=33 && c<=126) putc(c,f);
+    if (c>=33 && c<=126 && c!='\\') putc(c,f);
     else fprintf(f,"\\x%02x",(int)(unsigned char)c);
   }
 }
 
-static void undoable(const char *path, const char *fmt, ...) {
+static void add_pr(int *pr, int printf_ret) {
+  if (printf_ret == EOF) return;
+  *pr += printf_ret;
+}
+
+static void vproblemx(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)));
+  add_pr(&pr, printf("]"));
+  while (pr++ < padto)
+    putchar(' ');
+}  
+
+static void problem_e(int padto, 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);
-}  
+  vproblemx(padto,1,fmt,al);
+  va_end(al);
+}
 
-static void unreadable(const char *path, const char *doing) {
-  undoable(path, "unreadable: %s: %s: ", strerror(errno), doing);
+static void problem(int padto, const char *fmt, ...) {
+  va_list(al);
+  va_start(al,fmt);
+  vproblemx(padto,0,fmt,al);
+  va_end(al);
 }
 
 static void csum_file(const char *path) {
@@ -53,16 +69,18 @@ static void csum_file(const char *path) {
   size_t r;
   int i;
 
-  f= fopen(path,"rb");   if (!f) unreadable(path, "open");
+  f= fopen(path,"rb");
+  if (!f) { problem_e(sizeof(digest)*2,"open"); return; }
+  
   MD5Init(&mc);
   for (;;) {
     r= fread(db,1,sizeof(db),f);
-    if (ferror(f)) unreadable(path, "read");
+    if (ferror(f)) { problem_e(sizeof(digest)*2,"read"); fclose(f); return; }
     if (!r) { assert(feof(f)); break; }
     MD5Update(&mc,db,r);
   }
   MD5Final(digest,&mc);
-  if (fclose(f)) unreadable(path, "close");
+  if (fclose(f)) { problem_e(sizeof(digest)*2,"close"); return; }
 
   for (i=0; i<sizeof(digest); i++)
     printf("%02x", digest[i]);
@@ -78,13 +96,15 @@ static void csum_dev(int cb, const struct stat *stab) {
 }
 
 static void csum_str(const char *s) {
-  printf("%-32s", s);
+  printf("%-*s", CSUMXL, s);
 }
 
 struct FTW;
 
 static int item(const char *path, const struct stat *stab,
                int flag, struct FTW *ftws) {
+  char linktarg[MAXFN+1];
+
   switch (flag) {
   case FTW_D:
   case FTW_F:
@@ -96,15 +116,28 @@ 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 undoable(path, "badobj: 0x%lx: ", (unsigned long)stab->st_mode);
+    else problem(CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
     break;
 
   case FTW_NS:
   case FTW_DNR:
-    undoable(path,"inaccessible: %s: ", strerror(errno));
+    problem_e(CSUMXL,"inaccessible");
+    break;
 
   default:
-    undoable(path,"ftw flag 0x%x: %s: ", flag);
+    problem(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"); }
+    else assert(r<sizeof(linktarg));
+
+    if (r<0) strcpy(linktarg,"\\?");
+    else linktarg[r]= 0;
   }
 
   printf(" %10lu %4d %4o %10ld %10ld %10lu %10lu %10lu ",
@@ -119,15 +152,6 @@ static int item(const char *path, const struct stat *stab,
   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);
   }