history.c 6.7 KB

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