history.c 5.9 KB

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