17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier
47dd7cddfSDavid du Colombier #define MINUTE(x) ((long)(x)*60L)
57dd7cddfSDavid du Colombier #define HOUR(x) (MINUTE(x)*60L)
67dd7cddfSDavid du Colombier #define YEAR(x) (HOUR(x)*24L*360L)
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier int verb;
97dd7cddfSDavid du Colombier int uflag;
107fd46167SDavid du Colombier int force;
117dd7cddfSDavid du Colombier int diff;
127dd7cddfSDavid du Colombier char* sflag;
13*a23bc242SDavid du Colombier char* dargv[20] = {
14*a23bc242SDavid du Colombier "diff",
15*a23bc242SDavid du Colombier };
16*a23bc242SDavid du Colombier int ndargv = 1;
177dd7cddfSDavid du Colombier
18a7529a1dSDavid du Colombier void usage(void);
19f8e525acSDavid du Colombier void ysearch(char*, char*);
207dd7cddfSDavid du Colombier long starttime(char*);
21f8e525acSDavid du Colombier void lastbefore(ulong, char*, char*, char*);
227dd7cddfSDavid du Colombier char* prtime(ulong);
23*a23bc242SDavid du Colombier void darg(char*);
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier void
main(int argc,char * argv[])267dd7cddfSDavid du Colombier main(int argc, char *argv[])
277dd7cddfSDavid du Colombier {
287dd7cddfSDavid du Colombier int i;
29f8e525acSDavid du Colombier char *ndump;
307dd7cddfSDavid du Colombier
31f8e525acSDavid du Colombier ndump = nil;
327dd7cddfSDavid du Colombier ARGBEGIN {
337dd7cddfSDavid du Colombier default:
34a7529a1dSDavid du Colombier usage();
35*a23bc242SDavid du Colombier case 'a':
36*a23bc242SDavid du Colombier darg("-a");
377dd7cddfSDavid du Colombier break;
38*a23bc242SDavid du Colombier case 'b':
39*a23bc242SDavid du Colombier darg("-b");
407fd46167SDavid du Colombier break;
41*a23bc242SDavid du Colombier case 'c':
42*a23bc242SDavid du Colombier darg("-c");
43*a23bc242SDavid du Colombier break;
44*a23bc242SDavid du Colombier case 'e':
45*a23bc242SDavid du Colombier darg("-e");
46*a23bc242SDavid du Colombier break;
47*a23bc242SDavid du Colombier case 'm':
48*a23bc242SDavid du Colombier darg("-m");
49*a23bc242SDavid du Colombier break;
50*a23bc242SDavid du Colombier case 'n':
51*a23bc242SDavid du Colombier darg("-n");
52*a23bc242SDavid du Colombier break;
53*a23bc242SDavid du Colombier case 'w':
54*a23bc242SDavid du Colombier darg("-w");
557dd7cddfSDavid du Colombier break;
567dd7cddfSDavid du Colombier case 'D':
577dd7cddfSDavid du Colombier diff = 1;
587dd7cddfSDavid du Colombier break;
59*a23bc242SDavid du Colombier case 'd':
60*a23bc242SDavid du Colombier ndump = ARGF();
61*a23bc242SDavid du Colombier break;
62*a23bc242SDavid du Colombier case 'f':
63*a23bc242SDavid du Colombier force = 1;
647dd7cddfSDavid du Colombier break;
657dd7cddfSDavid du Colombier case 's':
667dd7cddfSDavid du Colombier sflag = ARGF();
677dd7cddfSDavid du Colombier break;
687dd7cddfSDavid du Colombier case 'u':
697dd7cddfSDavid du Colombier uflag = 1;
707dd7cddfSDavid du Colombier break;
71*a23bc242SDavid du Colombier case 'v':
72*a23bc242SDavid du Colombier verb = 1;
73*a23bc242SDavid du Colombier break;
747dd7cddfSDavid du Colombier } ARGEND
757dd7cddfSDavid du Colombier
76a7529a1dSDavid du Colombier if(argc == 0)
77a7529a1dSDavid du Colombier usage();
787dd7cddfSDavid du Colombier
79f8e525acSDavid du Colombier for(i=0; i<argc; i++)
80f8e525acSDavid du Colombier ysearch(argv[i], ndump);
81f8e525acSDavid du Colombier exits(0);
82f8e525acSDavid du Colombier }
83f8e525acSDavid du Colombier
84f8e525acSDavid du Colombier void
darg(char * a)85*a23bc242SDavid du Colombier darg(char* a)
86*a23bc242SDavid du Colombier {
87*a23bc242SDavid du Colombier if(ndargv >= nelem(dargv)-3)
88*a23bc242SDavid du Colombier return;
89*a23bc242SDavid du Colombier dargv[ndargv++] = a;
90*a23bc242SDavid du Colombier }
91*a23bc242SDavid du Colombier
92*a23bc242SDavid du Colombier void
usage(void)93a7529a1dSDavid du Colombier usage(void)
94a7529a1dSDavid du Colombier {
95a7529a1dSDavid du Colombier fprint(2, "usage: history [-bDfuv] [-d dumpfilesystem] [-s yyyymmdd] files\n");
96a7529a1dSDavid du Colombier exits("usage");
97a7529a1dSDavid du Colombier }
98a7529a1dSDavid du Colombier
99a7529a1dSDavid du Colombier void
ysearch(char * file,char * ndump)100f8e525acSDavid du Colombier ysearch(char *file, char *ndump)
101f8e525acSDavid du Colombier {
102f8e525acSDavid du Colombier char fil[400], buf[500], nbuf[100], pair[2][500], *p;
103f8e525acSDavid du Colombier Tm *tm;
104f8e525acSDavid du Colombier Waitmsg *w;
105f8e525acSDavid du Colombier Dir *dir, *d;
106f8e525acSDavid du Colombier ulong otime, dt;
107f8e525acSDavid du Colombier int toggle, started, missing;
108f8e525acSDavid du Colombier
10959c21d95SDavid du Colombier fil[0] = 0;
11059c21d95SDavid du Colombier if(file[0] != '/') {
11159c21d95SDavid du Colombier getwd(strchr(fil, 0), 100);
11259c21d95SDavid du Colombier strcat(fil, "/");
11359c21d95SDavid du Colombier }
11459c21d95SDavid du Colombier strcat(fil, file);
11524e2e655SDavid du Colombier if(memcmp(fil, "/n/", 3) == 0){
11659c21d95SDavid du Colombier p = strchr(fil+3, '/');
117f8e525acSDavid du Colombier if(p == nil)
11859c21d95SDavid du Colombier p = fil+strlen(fil);
11959c21d95SDavid du Colombier if(ndump == nil){
12059c21d95SDavid du Colombier if(p-fil >= sizeof nbuf-10){
12159c21d95SDavid du Colombier fprint(2, "%s: dump name too long", fil);
122f8e525acSDavid du Colombier return;
123f8e525acSDavid du Colombier }
12459c21d95SDavid du Colombier memmove(nbuf, fil+3, p-(fil+3));
12559c21d95SDavid du Colombier nbuf[p-(fil+3)] = 0;
126f8e525acSDavid du Colombier strcat(nbuf, "dump");
127f8e525acSDavid du Colombier ndump = nbuf;
128f8e525acSDavid du Colombier }
12959c21d95SDavid du Colombier memmove(fil, p, strlen(p)+1);
13059c21d95SDavid du Colombier }
13159c21d95SDavid du Colombier if(ndump == nil)
13259c21d95SDavid du Colombier ndump = "dump";
133f8e525acSDavid du Colombier
1347dd7cddfSDavid du Colombier tm = localtime(time(0));
1354d44ba9bSDavid du Colombier snprint(buf, sizeof buf, "/n/%s/%.4d/", ndump, tm->year+1900);
1369a747e4fSDavid du Colombier if(access(buf, AREAD) < 0) {
1377dd7cddfSDavid du Colombier if(verb)
138f8e525acSDavid du Colombier print("mounting dump %s\n", ndump);
1397dd7cddfSDavid du Colombier if(rfork(RFFDG|RFPROC) == 0) {
140f19e7b74SDavid du Colombier execl("/bin/rc", "rc", "9fs", ndump, nil);
1417dd7cddfSDavid du Colombier exits(0);
1427dd7cddfSDavid du Colombier }
1439a747e4fSDavid du Colombier w = wait();
1449a747e4fSDavid du Colombier if(w == nil){
1459a747e4fSDavid du Colombier fprint(2, "history: wait error: %r\n");
1469a747e4fSDavid du Colombier exits("wait");
1479a747e4fSDavid du Colombier }
1489a747e4fSDavid du Colombier if(w->msg[0] != '\0'){
1499a747e4fSDavid du Colombier fprint(2, "9fs failed: %s\n", w->msg);
1509a747e4fSDavid du Colombier exits(w->msg);
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier free(w);
1537dd7cddfSDavid du Colombier }
1547dd7cddfSDavid du Colombier
1559a747e4fSDavid du Colombier started = 0;
1569a747e4fSDavid du Colombier dir = dirstat(file);
1579a747e4fSDavid du Colombier if(dir == nil)
1589a747e4fSDavid du Colombier fprint(2, "history: warning: %s does not exist\n", file);
1599a747e4fSDavid du Colombier else{
1609a747e4fSDavid du Colombier print("%s %s %lld [%s]\n", prtime(dir->mtime), file, dir->length, dir->muid);
1619a747e4fSDavid du Colombier started = 1;
1624d44ba9bSDavid du Colombier strecpy(pair[1], pair[1]+sizeof pair[1], file);
1639a747e4fSDavid du Colombier }
1649a747e4fSDavid du Colombier free(dir);
1659a747e4fSDavid du Colombier otime = starttime(sflag);
1667dd7cddfSDavid du Colombier toggle = 0;
1677dd7cddfSDavid du Colombier for(;;) {
168f8e525acSDavid du Colombier lastbefore(otime, fil, buf, ndump);
1699a747e4fSDavid du Colombier dir = dirstat(buf);
1707fd46167SDavid du Colombier if(dir == nil) {
1717fd46167SDavid du Colombier if(!force)
1727dd7cddfSDavid du Colombier return;
1737fd46167SDavid du Colombier dir = malloc(sizeof(Dir));
1747fd46167SDavid du Colombier nulldir(dir);
1757fd46167SDavid du Colombier dir->mtime = otime + 1;
1767fd46167SDavid du Colombier }
1777dd7cddfSDavid du Colombier dt = HOUR(12);
1787fd46167SDavid du Colombier missing = 0;
1799a747e4fSDavid du Colombier while(otime <= dir->mtime){
1807dd7cddfSDavid du Colombier if(verb)
1819a747e4fSDavid du Colombier print("backup %ld, %ld\n", dir->mtime, otime-dt);
182f8e525acSDavid du Colombier lastbefore(otime-dt, fil, buf, ndump);
1837fd46167SDavid du Colombier d = dirstat(buf);
1847fd46167SDavid du Colombier if(d == nil){
1857fd46167SDavid du Colombier if(!force)
1867dd7cddfSDavid du Colombier return;
1877fd46167SDavid du Colombier if(!missing)
1887fd46167SDavid du Colombier print("removed %s\n", buf);
1897fd46167SDavid du Colombier missing = 1;
1907fd46167SDavid du Colombier }else{
1917fd46167SDavid du Colombier free(dir);
1927fd46167SDavid du Colombier dir = d;
1937fd46167SDavid du Colombier }
1947dd7cddfSDavid du Colombier dt += HOUR(12);
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier strcpy(pair[toggle], buf);
1977dd7cddfSDavid du Colombier if(diff && started){
1987dd7cddfSDavid du Colombier switch(rfork(RFFDG|RFPROC)){
1997dd7cddfSDavid du Colombier case 0:
200*a23bc242SDavid du Colombier dargv[ndargv] = pair[toggle];
201*a23bc242SDavid du Colombier dargv[ndargv+1] = pair[toggle ^ 1];
202*a23bc242SDavid du Colombier exec("/bin/diff", dargv);
2037dd7cddfSDavid du Colombier fprint(2, "can't exec diff: %r\n");
2047dd7cddfSDavid du Colombier exits(0);
2057dd7cddfSDavid du Colombier case -1:
2067dd7cddfSDavid du Colombier fprint(2, "can't fork diff: %r\n");
2077dd7cddfSDavid du Colombier break;
2087dd7cddfSDavid du Colombier default:
2099a747e4fSDavid du Colombier while(waitpid() != -1)
2107dd7cddfSDavid du Colombier ;
2117dd7cddfSDavid du Colombier break;
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier }
2149a747e4fSDavid du Colombier print("%s %s %lld [%s]\n", prtime(dir->mtime), buf, dir->length, dir->muid);
2157dd7cddfSDavid du Colombier toggle ^= 1;
2167dd7cddfSDavid du Colombier started = 1;
2179a747e4fSDavid du Colombier otime = dir->mtime;
2187fd46167SDavid du Colombier free(dir);
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier
2227dd7cddfSDavid du Colombier void
lastbefore(ulong t,char * f,char * b,char * ndump)223f8e525acSDavid du Colombier lastbefore(ulong t, char *f, char *b, char *ndump)
2247dd7cddfSDavid du Colombier {
2257dd7cddfSDavid du Colombier Tm *tm;
2269a747e4fSDavid du Colombier Dir *dir;
2277dd7cddfSDavid du Colombier int vers, try;
2289a747e4fSDavid du Colombier ulong t0, mtime;
22925747282SDavid du Colombier int i, n, fd;
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier t0 = t;
2327dd7cddfSDavid du Colombier if(verb)
2337dd7cddfSDavid du Colombier print("%ld lastbefore %s\n", t0, f);
2349a747e4fSDavid du Colombier mtime = 0;
235da51d93aSDavid du Colombier for(try=0; try<30; try++) {
2367dd7cddfSDavid du Colombier tm = localtime(t);
2377dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump,
2387dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday);
2399a747e4fSDavid du Colombier dir = dirstat(b);
2409a747e4fSDavid du Colombier if(dir){
2419a747e4fSDavid du Colombier mtime = dir->mtime;
2429a747e4fSDavid du Colombier free(dir);
2439a747e4fSDavid du Colombier }
2449a747e4fSDavid du Colombier if(dir==nil || mtime > t0) {
2457dd7cddfSDavid du Colombier if(verb)
2469a747e4fSDavid du Colombier print("%ld earlier %s\n", mtime, b);
2477dd7cddfSDavid du Colombier t -= HOUR(24);
2487dd7cddfSDavid du Colombier continue;
2497dd7cddfSDavid du Colombier }
25025747282SDavid du Colombier if(strstr(ndump, "snap")){
25125747282SDavid du Colombier fd = open(b, OREAD);
25225747282SDavid du Colombier if(fd < 0)
25325747282SDavid du Colombier continue;
25425747282SDavid du Colombier n = dirreadall(fd, &dir);
25525747282SDavid du Colombier close(fd);
25625747282SDavid du Colombier if(n == 0)
25725747282SDavid du Colombier continue;
25825747282SDavid du Colombier for(i = n-1; i > 0; i--){
25925747282SDavid du Colombier if(dir[i].mtime > t0)
26025747282SDavid du Colombier break;
26125747282SDavid du Colombier }
26225747282SDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d/%s%s", ndump,
26325747282SDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, dir[i].name, f);
26425747282SDavid du Colombier free(dir);
26525747282SDavid du Colombier } else {
2667dd7cddfSDavid du Colombier for(vers=0;; vers++) {
2677dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump,
2687dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, vers+1);
2699a747e4fSDavid du Colombier dir = dirstat(b);
2709a747e4fSDavid du Colombier if(dir){
2719a747e4fSDavid du Colombier mtime = dir->mtime;
2729a747e4fSDavid du Colombier free(dir);
2739a747e4fSDavid du Colombier }
2749a747e4fSDavid du Colombier if(dir==nil || mtime > t0)
2757dd7cddfSDavid du Colombier break;
2767dd7cddfSDavid du Colombier if(verb)
2779a747e4fSDavid du Colombier print("%ld later %s\n", mtime, b);
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump,
2807dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, f);
2817dd7cddfSDavid du Colombier if(vers)
2827dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump,
2837dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, vers, f);
28425747282SDavid du Colombier }
2857dd7cddfSDavid du Colombier return;
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier strcpy(b, "XXX"); /* error */
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier
2907dd7cddfSDavid du Colombier char*
prtime(ulong t)2917dd7cddfSDavid du Colombier prtime(ulong t)
2927dd7cddfSDavid du Colombier {
2937dd7cddfSDavid du Colombier static char buf[100];
2947dd7cddfSDavid du Colombier char *b;
2957dd7cddfSDavid du Colombier Tm *tm;
2967dd7cddfSDavid du Colombier
2977dd7cddfSDavid du Colombier if(uflag)
2987dd7cddfSDavid du Colombier tm = gmtime(t);
2997dd7cddfSDavid du Colombier else
3007dd7cddfSDavid du Colombier tm = localtime(t);
3017dd7cddfSDavid du Colombier b = asctime(tm);
3027dd7cddfSDavid du Colombier memcpy(buf, b+4, 24);
3037dd7cddfSDavid du Colombier buf[24] = 0;
3047dd7cddfSDavid du Colombier return buf;
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier
3077dd7cddfSDavid du Colombier long
starttime(char * s)3087dd7cddfSDavid du Colombier starttime(char *s)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier Tm *tm;
3117dd7cddfSDavid du Colombier long t, dt;
3127dd7cddfSDavid du Colombier int i, yr, mo, da;
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier t = time(0);
3157dd7cddfSDavid du Colombier if(s == 0)
3167dd7cddfSDavid du Colombier return t;
3179a747e4fSDavid du Colombier for(i=0; s[i]; i++)
3187dd7cddfSDavid du Colombier if(s[i] < '0' || s[i] > '9') {
3197dd7cddfSDavid du Colombier fprint(2, "bad start time: %s\n", s);
3207dd7cddfSDavid du Colombier return t;
3217dd7cddfSDavid du Colombier }
3229a747e4fSDavid du Colombier if(strlen(s)==6){
3237dd7cddfSDavid du Colombier yr = (s[0]-'0')*10 + s[1]-'0';
3247dd7cddfSDavid du Colombier mo = (s[2]-'0')*10 + s[3]-'0' - 1;
3257dd7cddfSDavid du Colombier da = (s[4]-'0')*10 + s[5]-'0';
3269a747e4fSDavid du Colombier if(yr < 70)
3279a747e4fSDavid du Colombier yr += 100;
3289a747e4fSDavid du Colombier }else if(strlen(s)==8){
3299a747e4fSDavid du Colombier yr = (((s[0]-'0')*10 + s[1]-'0')*10 + s[2]-'0')*10 + s[3]-'0';
3309a747e4fSDavid du Colombier yr -= 1900;
3319a747e4fSDavid du Colombier mo = (s[4]-'0')*10 + s[5]-'0' - 1;
3329a747e4fSDavid du Colombier da = (s[6]-'0')*10 + s[7]-'0';
3339a747e4fSDavid du Colombier }else{
3349a747e4fSDavid du Colombier fprint(2, "bad start time: %s\n", s);
3359a747e4fSDavid du Colombier return t;
3369a747e4fSDavid du Colombier }
3377dd7cddfSDavid du Colombier t = 0;
3387dd7cddfSDavid du Colombier dt = YEAR(10);
3397dd7cddfSDavid du Colombier for(i=0; i<50; i++) {
3407dd7cddfSDavid du Colombier tm = localtime(t+dt);
3417dd7cddfSDavid du Colombier if(yr > tm->year ||
3427dd7cddfSDavid du Colombier (yr == tm->year && mo > tm->mon) ||
3437dd7cddfSDavid du Colombier (yr == tm->year && mo == tm->mon) && da > tm->mday) {
3447dd7cddfSDavid du Colombier t += dt;
3457dd7cddfSDavid du Colombier continue;
3467dd7cddfSDavid du Colombier }
3477dd7cddfSDavid du Colombier dt /= 2;
3487dd7cddfSDavid du Colombier if(dt == 0)
3497dd7cddfSDavid du Colombier break;
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier t += HOUR(12); /* .5 day to get to noon of argument */
3527dd7cddfSDavid du Colombier return t;
3537dd7cddfSDavid du Colombier }
354