#include <stdarg.h>
#include <limits.h>
#include <assert.h>
+#include <stdlib.h>
-#include "md5.h"
+#include "nettle/md5-compat.h"
#define MAXFN 2048
#define MAXDEPTH 1024
+#define CSUMXL 32
+
+static int quiet=0, hidectime=0, hideatime=0;
+static int hidedirsizelinkcount=0, hidelinkmtime=0;
+static int filenamefieldsep=' ';
+static FILE *errfile;
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(const char *path, int padto, int per,
+ const char *fmt, va_list al) {
+ int e=errno, pr=0;
+
+ 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(const char *path, 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(path,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(const char *path, int padto, const char *fmt, ...) {
+ va_list(al);
+ va_start(al,fmt);
+ vproblemx(path,padto,0,fmt,al);
+ va_end(al);
}
static void csum_file(const char *path) {
FILE *f;
- struct MD5Context mc;
+ MD5_CTX mc;
char db[65536];
unsigned char digest[16];
size_t r;
int i;
- f= fopen(path,"rb"); if (!f) unreadable(path, "open");
+ f= fopen(path,"rb");
+ if (!f) { problem_e(path,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(path,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(path,sizeof(digest)*2,"close"); return; }
for (i=0; i<sizeof(digest); i++)
printf("%02x", digest[i]);
}
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:
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(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
break;
case FTW_NS:
case FTW_DNR:
- undoable(path,"inaccessible: %s: ", strerror(errno));
+ problem_e(path,CSUMXL,"inaccessible");
+ break;
default:
- undoable(path,"ftw flag 0x%x: %s: ", flag);
+ problem(path,CSUMXL,"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));
+ 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,"\\?");
+ else linktarg[r]= 0;
+ }
+
+ if (S_ISDIR(stab->st_mode) && hidedirsizelinkcount)
+ printf(" %10s %4s","dir","dir");
+ else
+ printf(" %10lu %4d",
+ (unsigned long)stab->st_size,
+ (int)stab->st_nlink);
+
+ printf(" %4o %10ld %10ld",
+ (unsigned)stab->st_mode & 07777U,
+ (unsigned long)stab->st_uid,
+ (unsigned long)stab->st_gid);
+
+ if (!hideatime)
+ printf(" %10lu",
+ (unsigned long)stab->st_atime);
- linktarg[r]= 0;
+ if (S_ISLNK(stab->st_mode) && hidelinkmtime)
+ printf(" %10s","link");
+ else
+ printf(" %10lu",
+ (unsigned long)stab->st_mtime);
+ if (!hidectime)
+ printf(" %10lu",
+ (unsigned long)stab->st_ctime);
+ putchar(filenamefieldsep);
+ fn_escaped(stdout, path);
+
+ if (S_ISLNK(stab->st_mode)) {
printf(" -> ");
fn_escaped(stdout, linktarg);
}
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); }
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); }
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 't':
+ filenamefieldsep= '\t';
+ break;
+ case 'D':
+ hidedirsizelinkcount= 1;
+ break;
+ case 'b':
+ hidelinkmtime= 1;
+ break;
+ case 'C':
+ hidectime= 1;
+ break;
+ case 'A':
+ hideatime= 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);
}
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;
}