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