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 int diffb; 137dd7cddfSDavid du Colombier char* sflag; 147dd7cddfSDavid du Colombier 15f8e525acSDavid du Colombier void ysearch(char*, char*); 167dd7cddfSDavid du Colombier long starttime(char*); 17f8e525acSDavid du Colombier void lastbefore(ulong, char*, char*, char*); 187dd7cddfSDavid du Colombier char* prtime(ulong); 197dd7cddfSDavid du Colombier 207dd7cddfSDavid du Colombier void 217dd7cddfSDavid du Colombier main(int argc, char *argv[]) 227dd7cddfSDavid du Colombier { 237dd7cddfSDavid du Colombier int i; 24f8e525acSDavid du Colombier char *ndump; 257dd7cddfSDavid du Colombier 26f8e525acSDavid du Colombier ndump = nil; 277dd7cddfSDavid du Colombier ARGBEGIN { 287dd7cddfSDavid du Colombier default: 297dd7cddfSDavid du Colombier goto usage; 307dd7cddfSDavid du Colombier case 'v': 317dd7cddfSDavid du Colombier verb = 1; 327dd7cddfSDavid du Colombier break; 337fd46167SDavid du Colombier case 'f': 347fd46167SDavid du Colombier force = 1; 357fd46167SDavid du Colombier break; 367dd7cddfSDavid du Colombier case 'd': 377dd7cddfSDavid du Colombier ndump = ARGF(); 387dd7cddfSDavid du Colombier break; 397dd7cddfSDavid du Colombier case 'D': 407dd7cddfSDavid du Colombier diff = 1; 417dd7cddfSDavid du Colombier break; 427dd7cddfSDavid du Colombier case 'b': 437dd7cddfSDavid du Colombier diffb = 1; 447dd7cddfSDavid du Colombier break; 457dd7cddfSDavid du Colombier case 's': 467dd7cddfSDavid du Colombier sflag = ARGF(); 477dd7cddfSDavid du Colombier break; 487dd7cddfSDavid du Colombier case 'u': 497dd7cddfSDavid du Colombier uflag = 1; 507dd7cddfSDavid du Colombier break; 517dd7cddfSDavid du Colombier } ARGEND 527dd7cddfSDavid du Colombier 537dd7cddfSDavid du Colombier if(argc == 0) { 547dd7cddfSDavid du Colombier usage: 5524e2e655SDavid du Colombier fprint(2, "usage: history [-bDfuv] [-d 9fsname] [-s yyyymmdd] files\n"); 567dd7cddfSDavid du Colombier exits(0); 577dd7cddfSDavid du Colombier } 587dd7cddfSDavid du Colombier 59f8e525acSDavid du Colombier for(i=0; i<argc; i++) 60f8e525acSDavid du Colombier ysearch(argv[i], ndump); 61f8e525acSDavid du Colombier exits(0); 62f8e525acSDavid du Colombier } 63f8e525acSDavid du Colombier 64f8e525acSDavid du Colombier void 65f8e525acSDavid du Colombier ysearch(char *file, char *ndump) 66f8e525acSDavid du Colombier { 67f8e525acSDavid du Colombier char fil[400], buf[500], nbuf[100], pair[2][500], *p; 68f8e525acSDavid du Colombier Tm *tm; 69f8e525acSDavid du Colombier Waitmsg *w; 70f8e525acSDavid du Colombier Dir *dir, *d; 71f8e525acSDavid du Colombier ulong otime, dt; 72f8e525acSDavid du Colombier int toggle, started, missing; 73f8e525acSDavid du Colombier 7459c21d95SDavid du Colombier fil[0] = 0; 7559c21d95SDavid du Colombier if(file[0] != '/') { 7659c21d95SDavid du Colombier getwd(strchr(fil, 0), 100); 7759c21d95SDavid du Colombier strcat(fil, "/"); 7859c21d95SDavid du Colombier } 7959c21d95SDavid du Colombier strcat(fil, file); 8024e2e655SDavid du Colombier if(memcmp(fil, "/n/", 3) == 0){ 8159c21d95SDavid du Colombier p = strchr(fil+3, '/'); 82f8e525acSDavid du Colombier if(p == nil) 8359c21d95SDavid du Colombier p = fil+strlen(fil); 8459c21d95SDavid du Colombier if(ndump == nil){ 8559c21d95SDavid du Colombier if(p-fil >= sizeof nbuf-10){ 8659c21d95SDavid du Colombier fprint(2, "%s: dump name too long", fil); 87f8e525acSDavid du Colombier return; 88f8e525acSDavid du Colombier } 8959c21d95SDavid du Colombier memmove(nbuf, fil+3, p-(fil+3)); 9059c21d95SDavid du Colombier nbuf[p-(fil+3)] = 0; 91f8e525acSDavid du Colombier strcat(nbuf, "dump"); 92f8e525acSDavid du Colombier ndump = nbuf; 93f8e525acSDavid du Colombier } 9459c21d95SDavid du Colombier memmove(fil, p, strlen(p)+1); 9559c21d95SDavid du Colombier } 9659c21d95SDavid du Colombier if(ndump == nil) 9759c21d95SDavid du Colombier ndump = "dump"; 98f8e525acSDavid du Colombier 997dd7cddfSDavid du Colombier tm = localtime(time(0)); 100*4d44ba9bSDavid du Colombier snprint(buf, sizeof buf, "/n/%s/%.4d/", ndump, tm->year+1900); 1019a747e4fSDavid du Colombier if(access(buf, AREAD) < 0) { 1027dd7cddfSDavid du Colombier if(verb) 103f8e525acSDavid du Colombier print("mounting dump %s\n", ndump); 1047dd7cddfSDavid du Colombier if(rfork(RFFDG|RFPROC) == 0) { 1057dd7cddfSDavid du Colombier execl("/bin/rc", "rc", "9fs", ndump, 0); 1067dd7cddfSDavid du Colombier exits(0); 1077dd7cddfSDavid du Colombier } 1089a747e4fSDavid du Colombier w = wait(); 1099a747e4fSDavid du Colombier if(w == nil){ 1109a747e4fSDavid du Colombier fprint(2, "history: wait error: %r\n"); 1119a747e4fSDavid du Colombier exits("wait"); 1129a747e4fSDavid du Colombier } 1139a747e4fSDavid du Colombier if(w->msg[0] != '\0'){ 1149a747e4fSDavid du Colombier fprint(2, "9fs failed: %s\n", w->msg); 1159a747e4fSDavid du Colombier exits(w->msg); 1169a747e4fSDavid du Colombier } 1179a747e4fSDavid du Colombier free(w); 1187dd7cddfSDavid du Colombier } 1197dd7cddfSDavid du Colombier 1209a747e4fSDavid du Colombier started = 0; 1219a747e4fSDavid du Colombier dir = dirstat(file); 1229a747e4fSDavid du Colombier if(dir == nil) 1239a747e4fSDavid du Colombier fprint(2, "history: warning: %s does not exist\n", file); 1249a747e4fSDavid du Colombier else{ 1259a747e4fSDavid du Colombier print("%s %s %lld [%s]\n", prtime(dir->mtime), file, dir->length, dir->muid); 1269a747e4fSDavid du Colombier started = 1; 127*4d44ba9bSDavid du Colombier strecpy(pair[1], pair[1]+sizeof pair[1], file); 1289a747e4fSDavid du Colombier } 1299a747e4fSDavid du Colombier free(dir); 1309a747e4fSDavid du Colombier otime = starttime(sflag); 1317dd7cddfSDavid du Colombier toggle = 0; 1327dd7cddfSDavid du Colombier for(;;) { 133f8e525acSDavid du Colombier lastbefore(otime, fil, buf, ndump); 1349a747e4fSDavid du Colombier dir = dirstat(buf); 1357fd46167SDavid du Colombier if(dir == nil) { 1367fd46167SDavid du Colombier if(!force) 1377dd7cddfSDavid du Colombier return; 1387fd46167SDavid du Colombier dir = malloc(sizeof(Dir)); 1397fd46167SDavid du Colombier nulldir(dir); 1407fd46167SDavid du Colombier dir->mtime = otime + 1; 1417fd46167SDavid du Colombier } 1427dd7cddfSDavid du Colombier dt = HOUR(12); 1437fd46167SDavid du Colombier missing = 0; 1449a747e4fSDavid du Colombier while(otime <= dir->mtime){ 1457dd7cddfSDavid du Colombier if(verb) 1469a747e4fSDavid du Colombier print("backup %ld, %ld\n", dir->mtime, otime-dt); 147f8e525acSDavid du Colombier lastbefore(otime-dt, fil, buf, ndump); 1487fd46167SDavid du Colombier d = dirstat(buf); 1497fd46167SDavid du Colombier if(d == nil){ 1507fd46167SDavid du Colombier if(!force) 1517dd7cddfSDavid du Colombier return; 1527fd46167SDavid du Colombier if(!missing) 1537fd46167SDavid du Colombier print("removed %s\n", buf); 1547fd46167SDavid du Colombier missing = 1; 1557fd46167SDavid du Colombier }else{ 1567fd46167SDavid du Colombier free(dir); 1577fd46167SDavid du Colombier dir = d; 1587fd46167SDavid du Colombier } 1597dd7cddfSDavid du Colombier dt += HOUR(12); 1607dd7cddfSDavid du Colombier } 1617dd7cddfSDavid du Colombier strcpy(pair[toggle], buf); 1627dd7cddfSDavid du Colombier if(diff && started){ 1637dd7cddfSDavid du Colombier switch(rfork(RFFDG|RFPROC)){ 1647dd7cddfSDavid du Colombier case 0: 1657dd7cddfSDavid du Colombier if(diffb) 16659cc4ca5SDavid du Colombier execl("/bin/diff", "diff", "-nb", pair[toggle ^ 1], pair[toggle], 0); 1677dd7cddfSDavid du Colombier else 16859cc4ca5SDavid du Colombier execl("/bin/diff", "diff", "-n", pair[toggle ^ 1], pair[toggle], 0); 1697dd7cddfSDavid du Colombier fprint(2, "can't exec diff: %r\n"); 1707dd7cddfSDavid du Colombier exits(0); 1717dd7cddfSDavid du Colombier case -1: 1727dd7cddfSDavid du Colombier fprint(2, "can't fork diff: %r\n"); 1737dd7cddfSDavid du Colombier break; 1747dd7cddfSDavid du Colombier default: 1759a747e4fSDavid du Colombier while(waitpid() != -1) 1767dd7cddfSDavid du Colombier ; 1777dd7cddfSDavid du Colombier break; 1787dd7cddfSDavid du Colombier } 1797dd7cddfSDavid du Colombier } 1809a747e4fSDavid du Colombier print("%s %s %lld [%s]\n", prtime(dir->mtime), buf, dir->length, dir->muid); 1817dd7cddfSDavid du Colombier toggle ^= 1; 1827dd7cddfSDavid du Colombier started = 1; 1839a747e4fSDavid du Colombier otime = dir->mtime; 1847fd46167SDavid du Colombier free(dir); 1857dd7cddfSDavid du Colombier } 1867dd7cddfSDavid du Colombier } 1877dd7cddfSDavid du Colombier 1887dd7cddfSDavid du Colombier void 189f8e525acSDavid du Colombier lastbefore(ulong t, char *f, char *b, char *ndump) 1907dd7cddfSDavid du Colombier { 1917dd7cddfSDavid du Colombier Tm *tm; 1929a747e4fSDavid du Colombier Dir *dir; 1937dd7cddfSDavid du Colombier int vers, try; 1949a747e4fSDavid du Colombier ulong t0, mtime; 19525747282SDavid du Colombier int i, n, fd; 1967dd7cddfSDavid du Colombier 1977dd7cddfSDavid du Colombier t0 = t; 1987dd7cddfSDavid du Colombier if(verb) 1997dd7cddfSDavid du Colombier print("%ld lastbefore %s\n", t0, f); 2009a747e4fSDavid du Colombier mtime = 0; 201da51d93aSDavid du Colombier for(try=0; try<30; try++) { 2027dd7cddfSDavid du Colombier tm = localtime(t); 2037dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump, 2047dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday); 2059a747e4fSDavid du Colombier dir = dirstat(b); 2069a747e4fSDavid du Colombier if(dir){ 2079a747e4fSDavid du Colombier mtime = dir->mtime; 2089a747e4fSDavid du Colombier free(dir); 2099a747e4fSDavid du Colombier } 2109a747e4fSDavid du Colombier if(dir==nil || mtime > t0) { 2117dd7cddfSDavid du Colombier if(verb) 2129a747e4fSDavid du Colombier print("%ld earlier %s\n", mtime, b); 2137dd7cddfSDavid du Colombier t -= HOUR(24); 2147dd7cddfSDavid du Colombier continue; 2157dd7cddfSDavid du Colombier } 21625747282SDavid du Colombier if(strstr(ndump, "snap")){ 21725747282SDavid du Colombier fd = open(b, OREAD); 21825747282SDavid du Colombier if(fd < 0) 21925747282SDavid du Colombier continue; 22025747282SDavid du Colombier n = dirreadall(fd, &dir); 22125747282SDavid du Colombier close(fd); 22225747282SDavid du Colombier if(n == 0) 22325747282SDavid du Colombier continue; 22425747282SDavid du Colombier for(i = n-1; i > 0; i--){ 22525747282SDavid du Colombier if(dir[i].mtime > t0) 22625747282SDavid du Colombier break; 22725747282SDavid du Colombier } 22825747282SDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d/%s%s", ndump, 22925747282SDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, dir[i].name, f); 23025747282SDavid du Colombier free(dir); 23125747282SDavid du Colombier } else { 2327dd7cddfSDavid du Colombier for(vers=0;; vers++) { 2337dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump, 2347dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, vers+1); 2359a747e4fSDavid du Colombier dir = dirstat(b); 2369a747e4fSDavid du Colombier if(dir){ 2379a747e4fSDavid du Colombier mtime = dir->mtime; 2389a747e4fSDavid du Colombier free(dir); 2399a747e4fSDavid du Colombier } 2409a747e4fSDavid du Colombier if(dir==nil || mtime > t0) 2417dd7cddfSDavid du Colombier break; 2427dd7cddfSDavid du Colombier if(verb) 2439a747e4fSDavid du Colombier print("%ld later %s\n", mtime, b); 2447dd7cddfSDavid du Colombier } 2457dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump, 2467dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, f); 2477dd7cddfSDavid du Colombier if(vers) 2487dd7cddfSDavid du Colombier sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump, 2497dd7cddfSDavid du Colombier tm->year+1900, tm->mon+1, tm->mday, vers, f); 25025747282SDavid du Colombier } 2517dd7cddfSDavid du Colombier return; 2527dd7cddfSDavid du Colombier } 2537dd7cddfSDavid du Colombier strcpy(b, "XXX"); /* error */ 2547dd7cddfSDavid du Colombier } 2557dd7cddfSDavid du Colombier 2567dd7cddfSDavid du Colombier char* 2577dd7cddfSDavid du Colombier prtime(ulong t) 2587dd7cddfSDavid du Colombier { 2597dd7cddfSDavid du Colombier static char buf[100]; 2607dd7cddfSDavid du Colombier char *b; 2617dd7cddfSDavid du Colombier Tm *tm; 2627dd7cddfSDavid du Colombier 2637dd7cddfSDavid du Colombier if(uflag) 2647dd7cddfSDavid du Colombier tm = gmtime(t); 2657dd7cddfSDavid du Colombier else 2667dd7cddfSDavid du Colombier tm = localtime(t); 2677dd7cddfSDavid du Colombier b = asctime(tm); 2687dd7cddfSDavid du Colombier memcpy(buf, b+4, 24); 2697dd7cddfSDavid du Colombier buf[24] = 0; 2707dd7cddfSDavid du Colombier return buf; 2717dd7cddfSDavid du Colombier } 2727dd7cddfSDavid du Colombier 2737dd7cddfSDavid du Colombier long 2747dd7cddfSDavid du Colombier starttime(char *s) 2757dd7cddfSDavid du Colombier { 2767dd7cddfSDavid du Colombier Tm *tm; 2777dd7cddfSDavid du Colombier long t, dt; 2787dd7cddfSDavid du Colombier int i, yr, mo, da; 2797dd7cddfSDavid du Colombier 2807dd7cddfSDavid du Colombier t = time(0); 2817dd7cddfSDavid du Colombier if(s == 0) 2827dd7cddfSDavid du Colombier return t; 2839a747e4fSDavid du Colombier for(i=0; s[i]; i++) 2847dd7cddfSDavid du Colombier if(s[i] < '0' || s[i] > '9') { 2857dd7cddfSDavid du Colombier fprint(2, "bad start time: %s\n", s); 2867dd7cddfSDavid du Colombier return t; 2877dd7cddfSDavid du Colombier } 2889a747e4fSDavid du Colombier if(strlen(s)==6){ 2897dd7cddfSDavid du Colombier yr = (s[0]-'0')*10 + s[1]-'0'; 2907dd7cddfSDavid du Colombier mo = (s[2]-'0')*10 + s[3]-'0' - 1; 2917dd7cddfSDavid du Colombier da = (s[4]-'0')*10 + s[5]-'0'; 2929a747e4fSDavid du Colombier if(yr < 70) 2939a747e4fSDavid du Colombier yr += 100; 2949a747e4fSDavid du Colombier }else if(strlen(s)==8){ 2959a747e4fSDavid du Colombier yr = (((s[0]-'0')*10 + s[1]-'0')*10 + s[2]-'0')*10 + s[3]-'0'; 2969a747e4fSDavid du Colombier yr -= 1900; 2979a747e4fSDavid du Colombier mo = (s[4]-'0')*10 + s[5]-'0' - 1; 2989a747e4fSDavid du Colombier da = (s[6]-'0')*10 + s[7]-'0'; 2999a747e4fSDavid du Colombier }else{ 3009a747e4fSDavid du Colombier fprint(2, "bad start time: %s\n", s); 3019a747e4fSDavid du Colombier return t; 3029a747e4fSDavid du Colombier } 3037dd7cddfSDavid du Colombier t = 0; 3047dd7cddfSDavid du Colombier dt = YEAR(10); 3057dd7cddfSDavid du Colombier for(i=0; i<50; i++) { 3067dd7cddfSDavid du Colombier tm = localtime(t+dt); 3077dd7cddfSDavid du Colombier if(yr > tm->year || 3087dd7cddfSDavid du Colombier (yr == tm->year && mo > tm->mon) || 3097dd7cddfSDavid du Colombier (yr == tm->year && mo == tm->mon) && da > tm->mday) { 3107dd7cddfSDavid du Colombier t += dt; 3117dd7cddfSDavid du Colombier continue; 3127dd7cddfSDavid du Colombier } 3137dd7cddfSDavid du Colombier dt /= 2; 3147dd7cddfSDavid du Colombier if(dt == 0) 3157dd7cddfSDavid du Colombier break; 3167dd7cddfSDavid du Colombier } 3177dd7cddfSDavid du Colombier t += HOUR(12); /* .5 day to get to noon of argument */ 3187dd7cddfSDavid du Colombier return t; 3197dd7cddfSDavid du Colombier } 320