history.c 6.2 KB

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