history.c 6.0 KB

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