chiark / gitweb /
cgi-fcgi-interp: new garbage collection approach, spec
[chiark-utils.git] / cprogs / summer.c
index ada0f14..762b5d6 100644 (file)
@@ -1,9 +1,29 @@
 /*
+ * summer - program for summarising (with md5 checksums) filesystem trees
+ *
  * usage:
  *    cat startpoints.list | summer >data.list
  *    summer startpoints... >data.list
  *  prints md5sum of data-list to stderr
  */
+/*
+ * Copyright (C) 2003,2006-2007 Ian Jackson <ian@davenant.greenend.org.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, consult the Free Software
+ * Foundation's website at www.fsf.org, or the GNU Project website at
+ * www.gnu.org.
+ */
 
 #define _GNU_SOURCE
 
 #define MAXDEPTH 1024
 #define CSUMXL 32
 
-static int quiet=0, hidectime=0, hideatime=0;
-static int hidedirsize=0, hidelinkmtime=0;
+static int quiet=0, hidectime=0, hideatime=0, hidemtime=0;
+static int hidedirsize=0, hidelinkmtime=0, hidextime=0, onefilesystem=0;
 static int filenamefieldsep=' ';
 static FILE *errfile;
 
+#define nodeflag_fsvalid       1u
+
 static void malloc_fail(void) { perror("summer: alloc failed"); exit(12); }
 
 static void *mmalloc(size_t sz) {
@@ -141,6 +163,28 @@ static void linktargpath(const char *linktarg) {
   fn_escaped(stdout, linktarg);
 }
 
+static void pu10(void) { printf(" %10s", "?"); }
+
+#define PTIME(stab, memb)  ((stab) ? ptime((stab), (stab)->memb) : pu10())
+
+static void ptime(const struct stat *stab, unsigned long val) {
+  const char *instead;
+
+  if (!hidextime) goto justprint;
+  else if (S_ISCHR(stab->st_mode)) instead= "char";
+  else if (S_ISBLK(stab->st_mode)) instead= "block";
+  else if (S_ISLNK(stab->st_mode)) instead= "link";
+  else if (S_ISSOCK(stab->st_mode)) instead= "sock";
+  else if (S_ISFIFO(stab->st_mode)) instead= "pipe";
+  else {
+  justprint:
+    printf(" %10lu", val);
+    return;
+  }
+
+  printf(" %10s",instead);
+}
+
 struct hardlink {
   dev_t dev;
   ino_t ino;
@@ -148,22 +192,20 @@ struct hardlink {
 };
 static void *hardlinks;
 
-static void pu10(void) { printf(" %10s", "?"); }
-
 static int hardlink_compar(const void *av, const void *bv) {
   const struct hardlink *a=av, *b=bv;
   if (a->ino != b->ino) return b->ino - a->ino;
   return b->dev - a->dev;
 }
 
-static void recurse(const char *path);
+static void recurse(const char *path, unsigned nodeflags, dev_t fs);
 
-static void node(const char *path) {
+static void node(const char *path, unsigned nodeflags, dev_t fs) {
   char linktarg[MAXFN+1];
   struct hardlink *foundhl;
   const struct stat *stab;
   struct stat stabuf;
-  int r;
+  int r, mountpoint=0;
 
   r= lstat(path, &stabuf);
   stab= r ? 0 : &stabuf;
@@ -185,15 +227,22 @@ static void node(const char *path) {
     }
   }
 
+  if (stab) {
+    if ((nodeflags & nodeflag_fsvalid) && stab->st_dev != fs)
+      mountpoint= 1;
+    fs= stab->st_dev;
+    nodeflags |= nodeflag_fsvalid;
+  }
+
   if (!stab) problem_e(path,CSUMXL,"inaccessible");
   else if (foundhl) csum_str("hardlink");
   else 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("symlink");
   else if (S_ISSOCK(stab->st_mode)) csum_str("sock");
+  else if (S_ISDIR(stab->st_mode)) csum_str(mountpoint ? "mountpoint" : "dir");
   else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
 
   if (stab && S_ISLNK(stab->st_mode)) {
@@ -221,31 +270,19 @@ static void node(const char *path) {
     printf(" %10s %4s %10s %10s", "?","?","?","?");
   }
 
-  if (!hideatime) {
-    if (stab)
-      printf(" %10lu",
-            (unsigned long)stab->st_atime);
-    else
-      pu10();
-  }
+  if (!hideatime)
+    PTIME(stab, st_atime);
 
-  if (stab)
-    if (S_ISLNK(stab->st_mode) && hidelinkmtime)
+  if (!hidemtime) {
+    if (stab && S_ISLNK(stab->st_mode) && hidelinkmtime)
       printf(" %10s","link");
     else
-      printf(" %10lu",
-            (unsigned long)stab->st_mtime);
-  else
-    pu10();
-
-  if (!hidectime) {
-    if (stab)
-      printf(" %10lu",
-            (unsigned long)stab->st_ctime);
-    else
-      pu10();
+      PTIME(stab, st_mtime);
   }
 
+  if (!hidectime)
+    PTIME(stab, st_ctime);
+
   putchar(filenamefieldsep);
   fn_escaped(stdout, path);
 
@@ -256,14 +293,14 @@ static void node(const char *path) {
 
   if (ferror(stdout)) { perror("summer: stdout"); exit(12); }
 
-  if (stab && S_ISDIR(stab->st_mode))
-    recurse(path);
+  if (stab && S_ISDIR(stab->st_mode) && !(mountpoint && onefilesystem))
+    recurse(path, nodeflags, fs);
 }
 
 static void process(const char *startpoint) {
   if (!quiet)
     fprintf(stderr,"summer: processing: %s\n",startpoint);
-  node(startpoint);
+  node(startpoint, 0,0);
   tdestroy(hardlinks,free);
   hardlinks= 0;
 }
@@ -282,12 +319,11 @@ static int recurse_filter(const struct dirent *de) {
   return 1;
 }
 
-static int recurse_compar(const void *av, const void *bv) {
-  const struct dirent *const *a=av, *const *b=bv;
+static int recurse_compar(const struct dirent **a, const struct dirent **b) {
   return strcmp((*a)->d_name, (*b)->d_name);
 }
 
-static void recurse(const char *path_or_buf) {
+static void recurse(const char *path_or_buf, unsigned nodeflags, dev_t fs) {
   static char *buf;
   static int buf_allocd;
   
@@ -312,13 +348,14 @@ static void recurse(const char *path_or_buf) {
   buf[pathl]= '/';
   pathl++;
   if (nentries < 0) {
-    strcpy(buf+pathl,"\\?");  errno= esave;
-    problem_e(buf,-1,"scandir failed");
+    buf[pathl]= 0;  errno= esave;
+    problem_e(buf,CSUMXL+72,"scandir failed");
+    fn_escaped(stdout,buf);  putchar('\n');
     return;
   }
   for (i=0, de=namelist; i<nentries; i++, de++) {
     strcpy(buf+pathl, (*de)->d_name);
-    node(buf);
+    node(buf, nodeflags, fs);
     free(*de);
   }
   free(namelist);
@@ -349,7 +386,7 @@ int main(int argc, const char *const *argv) {
 
   errfile= stderr;
   
-  if ((arg=argv[1]) && *arg++=='-') {
+  while ((arg=argv[1]) && *arg++=='-') {
     while ((c=*arg++)) {
       switch (c) {
       case 'h':
@@ -369,12 +406,21 @@ int main(int argc, const char *const *argv) {
       case 'b':
        hidelinkmtime= 1;
        break;
+      case 'B':
+       hidextime= 1;
+       break;
+      case 'x':
+       onefilesystem= 1;
+       break;
       case 'C':
        hidectime= 1;
        break;
       case 'A':
        hideatime= 1;
        break;
+      case 'M':
+       hidemtime= 1;
+       break;
       case 'f':
        errfile= stdout;
        break;