/*
+ * 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) {
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;
};
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;
}
}
+ 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)) {
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);
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;
}
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;
struct dirent **namelist, *const *de;
- char *subpathp;
const char *path_or_0= path_or_buf==buf ? 0 : path_or_buf;
int nentries, pathl, esave, buf_want, i;
if (path_or_0) strcpy(buf,path_or_0);
buf[pathl]= '/';
- subpathp= buf+pathl+1;
+ pathl++;
if (nentries < 0) {
- strcpy(subpathp,"\\?"); 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++) {
- fprintf(stderr,
- "buf=%p \"%s\" path=%p \"%s\" subpathp-buf=%ld d_name=\"%s\"\n",
- buf,buf,path_or_0,path_or_0,(long)(subpathp-buf),(*de)->d_name);
- strcpy(subpathp, (*de)->d_name);
- node(buf);
+ strcpy(buf+pathl, (*de)->d_name);
+ node(buf, nodeflags, fs);
free(*de);
}
free(namelist);
errfile= stderr;
- if ((arg=argv[1]) && *arg++=='-') {
+ while ((arg=argv[1]) && *arg++=='-') {
while ((c=*arg++)) {
switch (c) {
case 'h':
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;