history.c 5.0 KB

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