1 #include <u.h> 2 #include <libc.h> 3 4 #define MINUTE(x) ((long)(x)*60L) 5 #define HOUR(x) (MINUTE(x)*60L) 6 #define YEAR(x) (HOUR(x)*24L*360L) 7 8 int verb; 9 int uflag; 10 int diff; 11 int diffb; 12 char* ndump; 13 char* sflag; 14 15 void ysearch(char*); 16 long starttime(char*); 17 void lastbefore(ulong, char*, char*); 18 char* prtime(ulong); 19 20 void 21 main(int argc, char *argv[]) 22 { 23 char buf[100]; 24 Tm *tm; 25 Dir dir; 26 Waitmsg w; 27 int i; 28 29 ndump = "dump"; 30 ARGBEGIN { 31 default: 32 goto usage; 33 case 'v': 34 verb = 1; 35 break; 36 case 'd': 37 ndump = ARGF(); 38 break; 39 case 'D': 40 diff = 1; 41 break; 42 case 'b': 43 diffb = 1; 44 break; 45 case 's': 46 sflag = ARGF(); 47 break; 48 case 'u': 49 uflag = 1; 50 break; 51 } ARGEND 52 53 if(argc == 0) { 54 usage: 55 fprint(2, "usage: history [-vuD] [-d 9fsname] [-s yymmdd] files\n"); 56 exits(0); 57 } 58 59 tm = localtime(time(0)); 60 sprint(buf, "/n/%s/%.4d/", ndump, tm->year+1900); 61 if(dirstat(buf, &dir)) { 62 if(verb) 63 print("mounting dump\n"); 64 if(rfork(RFFDG|RFPROC) == 0) { 65 execl("/bin/rc", "rc", "9fs", ndump, 0); 66 exits(0); 67 } 68 while(wait(&w) != -1) 69 ; 70 } 71 72 for(i=0; i<argc; i++) 73 ysearch(argv[i]); 74 exits(0); 75 } 76 77 void 78 ysearch(char *file) 79 { 80 char fil[400], buf[500], pair[2][500]; 81 Dir dir; 82 ulong otime, dt; 83 int toggle, started; 84 85 fil[0] = 0; 86 if(file[0] != '/') { 87 getwd(strchr(fil, 0), 100); 88 strcat(fil, "/"); 89 } 90 strcat(fil, file); 91 dir.mtime = starttime(sflag); 92 started = 0; 93 toggle = 0; 94 for(;;) { 95 otime = dir.mtime; 96 lastbefore(otime, fil, buf); 97 if(dirstat(buf, &dir)) 98 return; 99 dt = HOUR(12); 100 while(otime <= dir.mtime) { 101 if(verb) 102 print("backup %ld, %ld\n", dir.mtime, otime-dt); 103 lastbefore(otime-dt, fil, buf); 104 if(dirstat(buf, &dir)) 105 return; 106 dt += HOUR(12); 107 } 108 strcpy(pair[toggle], buf); 109 if(diff && started){ 110 switch(rfork(RFFDG|RFPROC)){ 111 case 0: 112 if(diffb) 113 execl("/bin/diff", "diff", "-b", pair[toggle ^ 1], pair[toggle], 0); 114 else 115 execl("/bin/diff", "diff", pair[toggle ^ 1], pair[toggle], 0); 116 fprint(2, "can't exec diff: %r\n"); 117 exits(0); 118 case -1: 119 fprint(2, "can't fork diff: %r\n"); 120 break; 121 default: 122 while(wait(nil) != -1) 123 ; 124 break; 125 } 126 } 127 print("%s %s %lld\n", prtime(dir.mtime), buf, dir.length); 128 toggle ^= 1; 129 started = 1; 130 } 131 } 132 133 void 134 lastbefore(ulong t, char *f, char *b) 135 { 136 Tm *tm; 137 Dir dir; 138 int vers, try; 139 ulong t0; 140 141 t0 = t; 142 if(verb) 143 print("%ld lastbefore %s\n", t0, f); 144 for(try=0; try<10; try++) { 145 tm = localtime(t); 146 sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump, 147 tm->year+1900, tm->mon+1, tm->mday); 148 if(dirstat(b, &dir) || dir.mtime > t0) { 149 if(verb) 150 print("%ld earlier %s\n", dir.mtime, b); 151 t -= HOUR(24); 152 continue; 153 } 154 for(vers=0;; vers++) { 155 sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump, 156 tm->year+1900, tm->mon+1, tm->mday, vers+1); 157 if(dirstat(b, &dir) || dir.mtime > t0) 158 break; 159 if(verb) 160 print("%ld later %s\n", dir.mtime, b); 161 } 162 sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump, 163 tm->year+1900, tm->mon+1, tm->mday, f); 164 if(vers) 165 sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump, 166 tm->year+1900, tm->mon+1, tm->mday, vers, f); 167 return; 168 } 169 strcpy(b, "XXX"); /* error */ 170 } 171 172 char* 173 prtime(ulong t) 174 { 175 static char buf[100]; 176 char *b; 177 Tm *tm; 178 179 if(uflag) 180 tm = gmtime(t); 181 else 182 tm = localtime(t); 183 b = asctime(tm); 184 memcpy(buf, b+4, 24); 185 buf[24] = 0; 186 return buf; 187 } 188 189 long 190 starttime(char *s) 191 { 192 Tm *tm; 193 long t, dt; 194 int i, yr, mo, da; 195 196 t = time(0); 197 if(s == 0) 198 return t; 199 for(i=0; i<6; i++) 200 if(s[i] < '0' || s[i] > '9') { 201 fprint(2, "bad start time: %s\n", s); 202 return t; 203 } 204 yr = (s[0]-'0')*10 + s[1]-'0'; 205 mo = (s[2]-'0')*10 + s[3]-'0' - 1; 206 da = (s[4]-'0')*10 + s[5]-'0'; 207 208 t = 0; 209 dt = YEAR(10); 210 for(i=0; i<50; i++) { 211 tm = localtime(t+dt); 212 if(yr > tm->year || 213 (yr == tm->year && mo > tm->mon) || 214 (yr == tm->year && mo == tm->mon) && da > tm->mday) { 215 t += dt; 216 continue; 217 } 218 dt /= 2; 219 if(dt == 0) 220 break; 221 } 222 t += HOUR(12); /* .5 day to get to noon of argument */ 223 return t; 224 } 225