code: plan9front

Download patch

ref: e55b6a5aff9788b1606a56c3666ecdc87f1712c3
parent: 6d99af6f3455ebc1df29b13f8b1fe7f3338dc074
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Aug 8 12:56:11 EDT 2022

Rewrite history: 9front was first

History was built using a heuristic where a file not present in
the dump in 30 days was considered as a deleted file, without
being important if those days had an actual dump. Having the file
server off 30 days made all the files to be deleted from the
history point of view. This new version is rewriten from scratch
in rc and it does not try to detect deleted files since it can
be derived only with fragile assumptions.

--- /dev/null
+++ b/rc/bin/history
@@ -1,0 +1,73 @@
+#!/bin/rc
+rfork e
+
+nl='
+'
+
+fn prfile {
+	echo -n `{date $flagu -f 'MMM DD hh:mm:ss ZZZ YYYY' `{walk -e m $1}}
+	walk -e psM $1 | awk '{printf " %s %lld [%s]\n", $1,$2,$3,$4}'
+}
+
+fn diffflags {
+	t=()
+	for(f in a b c e m n w) {
+		flagname=flag$f
+		if(~ $$flagname 1)
+			t=(-$f $t)
+	}
+	echo $t
+}
+
+fn ysearch {
+	if(~ $1 /*)
+		file=$1
+	if not
+		file=`{pwd}^/$1
+
+	if(test -f $file)
+		prfile $file
+	if not
+		echo history: warning: $file does not exist >[1=2]
+
+	old=()
+	ls -qr /n/$dump/*/*/$file >[2] /dev/null |
+	sed  's/\(([^ ]*) *([^ ]*) *([^ ]*)\)/\1\2\3/p' |
+	awk '"/n/'$dump/$since'" <= $2 {next}
+	     $1 != qid {
+		qid=$1
+		gsub($1, "")
+		print}' |
+	while(new=`$nl{read}){
+		prfile $new
+		if (~ $flagD 1 && ~ $#old 1)
+			diff `{diffflags} $new $old
+		old=$new
+	}
+}
+
+flagfmt='D,a,b,f,c,e,m,n,w,u,d:dump,s since'
+args='[ -Dabcemnw ] [ -uf ] [ -d dumpfilesystem ] [ -s yyyymmdd ] files ...'
+if(! ifs=() eval `{aux/getflags $*} || 
+   ~ $#* 0 ||
+   ! ~ $#dump 0 && ! ~ $#dump 1 ||
+   ! ~ $#flags 0 && ! ~ $#flags 1) {
+	aux/usage
+	exit usage
+}
+
+if(~ $#dump 0)
+	dump=dump
+
+if(~ $#flags 0)
+	flags=`{date -f 'YYYYMMDD'}
+
+if(~ $#flagu 1)
+	flagu=-u
+
+since=`{date -f 'YYYY\/MMDD' `{seconds -f 'YYYYMMDD' $flags}}
+
+9fs $dump
+
+for(arg in $*)
+	ysearch $arg
--- a/sys/man/1/history
+++ b/sys/man/1/history
@@ -6,7 +6,7 @@
 [
 .B -Dabcemnw
 ] [
-.B -fuv
+.B -fu
 ] [
 .B -d
 .I dumpfilesystem
@@ -38,18 +38,6 @@
 	...
 .EE
 .PP
-When presented with a path of the form
-.BI /n/ fs / path \fR,
-.I history
-will use
-.IB fs dump
-as the name of the dump file system, and will print a history of
-.IR path .
-.PP
-The
-.B -v
-option enables verbose debugging printout.
-.PP
 The 
 .B -D
 option causes
@@ -78,9 +66,8 @@
 .PP
 The
 .B -f
-option forces the search to continue even when the
-file in question does not exist (useful for files that only
-exist intermittently).
+option is accepted
+but ignored by compatibilty with other history implementations.
 .PP
 Finally, the
 .B -s
--- a/sys/src/cmd/history.c
+++ /dev/null
@@ -1,353 +1,0 @@
-#include	<u.h>
-#include	<libc.h>
-
-#define	MINUTE(x)	((long)(x)*60L)
-#define	HOUR(x)		(MINUTE(x)*60L)
-#define	YEAR(x)		(HOUR(x)*24L*360L)
-
-int	verb;
-int	uflag;
-int	force;
-int	diff;
-char*	sflag;
-char*	dargv[20] = {
-	"diff",
-};
-int	ndargv = 1;
-
-void	usage(void);
-void	ysearch(char*, char*);
-long	starttime(char*);
-void	lastbefore(ulong, char*, char*, char*);
-char*	prtime(ulong);
-void	darg(char*);
-
-void
-main(int argc, char *argv[])
-{
-	int i;
-	char *ndump;
-
-	ndump = nil;
-	ARGBEGIN {
-	default:
-		usage();
-	case 'a':
-		darg("-a");
-		break;
-	case 'b':
-		darg("-b");
-		break;
-	case 'c':
-		darg("-c");
-		break;
-	case 'e':
-		darg("-e");
-		break;
-	case 'm':
-		darg("-m");
-		break;
-	case 'n':
-		darg("-n");
-		break;
-	case 'w':
-		darg("-w");
-		break;
-	case 'D':
-		diff = 1;
-		break;
-	case 'd':
-		ndump = ARGF();
-		break;
-	case 'f':
-		force = 1;
-		break;
-	case 's':
-		sflag = ARGF();
-		break;
-	case 'u':
-		uflag = 1;
-		break;
-	case 'v':
-		verb = 1;
-		break;
-	} ARGEND
-
-	if(argc == 0)
-		usage();
-
-	for(i=0; i<argc; i++)
-		ysearch(argv[i], ndump);
-	exits(0);
-}
-
-void
-darg(char* a)
-{
-	if(ndargv >= nelem(dargv)-3)
-		return;
-	dargv[ndargv++] = a;
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: history [-bDfuv] [-d dumpfilesystem] [-s yyyymmdd] files\n");
-	exits("usage");
-}
-
-void
-ysearch(char *file, char *ndump)
-{
-	char fil[400], buf[500], nbuf[100], pair[2][500], *p;
-	Tm *tm;
-	Waitmsg *w;
-	Dir *dir, *d;
-	ulong otime, dt;
-	int toggle, started, missing;
-
-	fil[0] = 0;
-	if(file[0] != '/') {
-		getwd(strchr(fil, 0), 100);
-		strcat(fil, "/");
-	}
-	strcat(fil, file);
-	if(memcmp(fil, "/n/", 3) == 0){
-		p = strchr(fil+3, '/');
-		if(p == nil)
-			p = fil+strlen(fil);
-		if(ndump == nil){
-			if(p-fil >= sizeof nbuf-10){
-				fprint(2, "%s: dump name too long", fil);
-				return;
-			}
-			memmove(nbuf, fil+3, p-(fil+3));
-			nbuf[p-(fil+3)] = 0;
-			strcat(nbuf, "dump");
-			ndump = nbuf;
-		}
-		memmove(fil, p, strlen(p)+1);
-	}
-	if(ndump == nil)
-		ndump = "dump";
-
-	tm = localtime(time(0));
-	snprint(buf, sizeof buf, "/n/%s/%.4d/", ndump, tm->year+1900);
-	if(access(buf, AREAD) < 0) {
-		if(verb)
-			print("mounting dump %s\n", ndump);
-		if(rfork(RFFDG|RFPROC) == 0) {
-			execl("/bin/rc", "rc", "9fs", ndump, nil);
-			exits(0);
-		}
-		w = wait();
-		if(w == nil){
-			fprint(2, "history: wait error: %r\n");
-			exits("wait");
-		}
-		if(w->msg[0] != '\0'){
-			fprint(2, "9fs failed: %s\n", w->msg);
-			exits(w->msg);
-		}
-		free(w);
-	}
-
-	started = 0;
-	dir = dirstat(file);
-	if(dir == nil)
-		fprint(2, "history: warning: %s does not exist\n", file);
-	else{
-		print("%s %s %lld [%s]\n", prtime(dir->mtime), file, dir->length, dir->muid);
-		started = 1;
-		strecpy(pair[1], pair[1]+sizeof pair[1], file);
-	}
-	free(dir);
-	otime = starttime(sflag);
-	toggle = 0;
-	for(;;) {
-		lastbefore(otime, fil, buf, ndump);
-		dir = dirstat(buf);
-		if(dir == nil) {
-			if(!force)
-				return;
-			dir = malloc(sizeof(Dir));
-			nulldir(dir);
-			dir->mtime = otime + 1;
-		}
-		dt = HOUR(12);
-		missing = 0;
-		while(otime <= dir->mtime){
-			if(verb)
-				print("backup %ld, %ld\n", dir->mtime, otime-dt);
-			lastbefore(otime-dt, fil, buf, ndump);
-			d = dirstat(buf);
-			if(d == nil){
-				if(!force)
-					return;
-				if(!missing)
-					print("removed %s\n", buf);
-				missing = 1;
-			}else{
-				free(dir);
-				dir = d;
-			}
-			dt += HOUR(12);
-		}
-		strcpy(pair[toggle], buf);
-		if(diff && started){
-			switch(rfork(RFFDG|RFPROC)){
-			case 0:
-				dargv[ndargv] = pair[toggle];
-				dargv[ndargv+1] = pair[toggle ^ 1];
-				exec("/bin/diff", dargv);
-				fprint(2, "can't exec diff: %r\n");
-				exits(0);
-			case -1:
-				fprint(2, "can't fork diff: %r\n");
-				break;
-			default:
-				while(waitpid() != -1)
-					;
-				break;
-			}
-		}
-		print("%s %s %lld [%s]\n", prtime(dir->mtime), buf, dir->length, dir->muid);
-		toggle ^= 1;
-		started = 1;
-		otime = dir->mtime;
-		free(dir);
-	}
-}
-
-void
-lastbefore(ulong t, char *f, char *b, char *ndump)
-{
-	Tm *tm;
-	Dir *dir;
-	int vers, try;
-	ulong t0, mtime;
-	int i, n, fd;
-
-	t0 = t;
-	if(verb)
-		print("%ld lastbefore %s\n", t0, f);
-	mtime = 0;
-	for(try=0; try<30; try++) {
-		tm = localtime(t);
-		sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump,
-			tm->year+1900, tm->mon+1, tm->mday);
-		dir = dirstat(b);
-		if(dir){
-			mtime = dir->mtime;
-			free(dir);
-		}
-		if(dir==nil || mtime > t0) {
-			if(verb)
-				print("%ld earlier %s\n", mtime, b);
-			t -= HOUR(24);
-			continue;
-		}
-		if(strstr(ndump, "snap")){
-			fd = open(b, OREAD);
-			if(fd < 0)
-				continue;
-			n = dirreadall(fd, &dir);
-			close(fd);
-			if(n == 0)
-				continue;
-			for(i = n-1; i > 0; i--){
-				if(dir[i].mtime > t0)
-					break;
-			}
-			sprint(b, "/n/%s/%.4d/%.2d%.2d/%s%s", ndump,
-				tm->year+1900, tm->mon+1, tm->mday, dir[i].name, f);
-			free(dir);
-		} else {
-			for(vers=0;; vers++) {
-				sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump,
-					tm->year+1900, tm->mon+1, tm->mday, vers+1);
-				dir = dirstat(b);
-				if(dir){
-					mtime = dir->mtime;
-					free(dir);
-				}
-				if(dir==nil || mtime > t0)
-					break;
-				if(verb)
-					print("%ld later %s\n", mtime, b);
-			}
-			sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump,
-				tm->year+1900, tm->mon+1, tm->mday, f);
-			if(vers)
-				sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump,
-					tm->year+1900, tm->mon+1, tm->mday, vers, f);
-		}
-		return;
-	}
-	strcpy(b, "XXX");	/* error */
-}
-
-char*
-prtime(ulong t)
-{
-	static char buf[100];
-	char *b;
-	Tm *tm;
-
-	if(uflag)
-		tm = gmtime(t);
-	else
-		tm = localtime(t);
-	b = asctime(tm);
-	memcpy(buf, b+4, 24);
-	buf[24] = 0;
-	return buf;
-}
-
-long
-starttime(char *s)
-{
-	Tm *tm;
-	long t, dt;
-	int i, yr, mo, da;
-
-	t = time(0);
-	if(s == 0)
-		return t;
-	for(i=0; s[i]; i++)
-		if(s[i] < '0' || s[i] > '9') {
-			fprint(2, "bad start time: %s\n", s);
-			return t;
-		}
-	if(strlen(s)==6){
-		yr = (s[0]-'0')*10 + s[1]-'0';
-		mo = (s[2]-'0')*10 + s[3]-'0' - 1;
-		da = (s[4]-'0')*10 + s[5]-'0';
-		if(yr < 70)
-			yr += 100;
-	}else if(strlen(s)==8){
-		yr = (((s[0]-'0')*10 + s[1]-'0')*10 + s[2]-'0')*10 + s[3]-'0';
-		yr -= 1900;
-		mo = (s[4]-'0')*10 + s[5]-'0' - 1;
-		da = (s[6]-'0')*10 + s[7]-'0';
-	}else{
-		fprint(2, "bad start time: %s\n", s);
-		return t;
-	}
-	t = 0;
-	dt = YEAR(10);
-	for(i=0; i<50; i++) {
-		tm = localtime(t+dt);
-		if(yr > tm->year ||
-		  (yr == tm->year && mo > tm->mon) ||
-		  (yr == tm->year && mo == tm->mon) && da > tm->mday) {
-			t += dt;
-			continue;
-		}
-		dt /= 2;
-		if(dt == 0)
-			break;
-	}
-	t += HOUR(12);	/* .5 day to get to noon of argument */
-	return t;
-}