history.c 4.8 KB

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