netlib_history.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. #include <bio.h>
  12. #include "httpd.h"
  13. #include "httpsrv.h"
  14. Hio *HO;
  15. int diffb;
  16. enum{ DAY = 24*60*60 };
  17. void
  18. lastbefore(uint32_t t, char *f, char *b)
  19. {
  20. Tm *tm;
  21. Dir *dir;
  22. int try;
  23. uint32_t t0, mtime;
  24. t0 = t;
  25. for(try=0; try<10; try++) {
  26. tm = localtime(t);
  27. t -= DAY;
  28. sprint(b,"%.4d/%.2d%.2d/netlib/pub/%s",tm->year+1900,tm->mon+1,tm->mday,f);
  29. dir = dirstat(b);
  30. if(dir == nil)
  31. continue;
  32. mtime = dir->mtime;
  33. free(dir);
  34. if(mtime > t0)
  35. continue;
  36. return;
  37. }
  38. strcpy(b, "filenotfound");
  39. }
  40. // create explicit file for diff, which otherwise would create a
  41. // mode 0600 file that it couldn't read (because running as none)
  42. void
  43. gunzip(char *f, char *tmp)
  44. {
  45. int fd = open(tmp, OWRITE);
  46. if(fd < 0) // can't happen
  47. return;
  48. switch(fork()){
  49. case 0:
  50. dup(fd, 1);
  51. close(fd);
  52. close(0);
  53. execl("/bin/gunzip", "gunzip", "-c", f, nil);
  54. hprint(HO, "can't exec gunzip: %r\n");
  55. break;
  56. case -1:
  57. hprint(HO, "fork failed: %r\n");
  58. default:
  59. while(waitpid() != -1)
  60. ;
  61. break;
  62. }
  63. close(fd);
  64. }
  65. void
  66. netlibhistory(char *file)
  67. {
  68. char buf[500], pair[2][500], tmpf[2][30], *f;
  69. int toggle = 0, started = 0, limit;
  70. Dir *dir;
  71. uint32_t otime, dt;
  72. int i, fd, tmpcnt;
  73. if(strncmp(file, "../", 3) == 0 || strstr(file, "/../") ||
  74. strlen(file) >= sizeof(buf) - strlen("1997/0204/netlib/pub/0"))
  75. return;
  76. limit = 50;
  77. if(diffb){
  78. limit = 10;
  79. // create two tmp files for gunzip
  80. for(i = 0, tmpcnt = 0; i < 2 && tmpcnt < 20; tmpcnt++){
  81. snprint(tmpf[i], sizeof(tmpf[0]), "/tmp/d%x", tmpcnt);
  82. if(access(buf, AEXIST) == 0)
  83. continue;
  84. fd = create(tmpf[i], OWRITE, 0666);
  85. if(fd < 0)
  86. goto done;
  87. close(fd);
  88. i++;
  89. }
  90. }
  91. otime = time(0);
  92. hprint(HO,"<UL>\n");
  93. while(limit--){
  94. lastbefore(otime, file, buf);
  95. dir = dirstat(buf);
  96. if(dir == nil)
  97. goto done;
  98. dt = DAY/2;
  99. while(otime <= dir->mtime){
  100. lastbefore(otime-dt, file, buf);
  101. free(dir);
  102. dir = dirstat(buf);
  103. if(dir == nil)
  104. goto done;
  105. dt += DAY/2;
  106. }
  107. f = pair[toggle];
  108. strcpy(f, buf);
  109. if(diffb && strcmp(f+strlen(f)-3, ".gz") == 0){
  110. gunzip(f, tmpf[toggle]);
  111. strcpy(f, tmpf[toggle]);
  112. }
  113. if(diffb && started){
  114. hprint(HO, "<PRE>\n");
  115. hflush(HO);
  116. switch(fork()){
  117. case 0:
  118. execl("/bin/diff", "diff", "-nb",
  119. pair[1-toggle], pair[toggle], nil);
  120. hprint(HO, "can't exec diff: %r\n");
  121. break;
  122. case -1:
  123. hprint(HO, "fork failed: %r\n");
  124. break;
  125. default:
  126. while(waitpid() != -1)
  127. ;
  128. break;
  129. }
  130. hprint(HO, "</PRE>\n");
  131. }
  132. hprint(HO,"<LI><A HREF=\"/historic/%s\">%s</A> %lld bytes\n",
  133. buf, 4+asctime(gmtime(dir->mtime)), dir->length);
  134. if(diffb)
  135. hprint(HO," <FONT SIZE=-1>(%s)</FONT>\n", pair[toggle]);
  136. toggle = 1-toggle;
  137. started = 1;
  138. otime = dir->mtime;
  139. free(dir);
  140. }
  141. hprint(HO,"<LI>...\n");
  142. done:
  143. hprint(HO,"</UL>\n");
  144. if(diffb){
  145. remove(tmpf[0]);
  146. remove(tmpf[1]);
  147. }
  148. }
  149. int
  150. send(HConnect *c)
  151. {
  152. char *file, *s;
  153. HSPairs *q;
  154. if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
  155. return hunallowed(c, "GET, HEAD");
  156. if(c->head.expectother || c->head.expectcont)
  157. return hfail(c, HExpectFail, nil);
  158. if(c->req.search == nil || !*c->req.search)
  159. return hfail(c, HNoData, "netlib_history");
  160. s = c->req.search;
  161. while((s = strchr(s, '+')) != nil)
  162. *s++ = ' ';
  163. file = nil;
  164. for(q = hparsequery(c, hstrdup(c, c->req.search)); q; q = q->next){
  165. if(strcmp(q->s, "file") == 0)
  166. file = q->t;
  167. else if(strcmp(q->s, "diff") == 0)
  168. diffb = 1;
  169. }
  170. if(file == nil)
  171. return hfail(c, HNoData, "netlib_history missing file field");
  172. logit(c, "netlib_hist %s%s", file, diffb?" DIFF":"");
  173. if(c->req.vermaj){
  174. hokheaders(c);
  175. hprint(HO, "Content-type: text/html\r\n");
  176. hprint(HO, "\r\n");
  177. }
  178. if(strcmp(c->req.meth, "HEAD") == 0){
  179. writelog(c, "Reply: 200 netlib_history 0\n");
  180. hflush(HO);
  181. exits(nil);
  182. }
  183. hprint(HO, "<HEAD><TITLE>%s history</TITLE></HEAD>\n<BODY>\n",file);
  184. hprint(HO, "<H2>%s history</H2>\n",file);
  185. hprint(HO, "<I>Netlib's copy of %s was changed\n", file);
  186. hprint(HO, "on the dates shown. <BR>Click on the date link\n");
  187. hprint(HO, "to retrieve the corresponding version.</I>\n");
  188. if(diffb){
  189. hprint(HO, "<BR><I>Lines beginning with &lt; are for the\n");
  190. hprint(HO, "newer of the two versions.</I>\n");
  191. }
  192. if(chdir("/usr/web/historic") < 0)
  193. hprint(HO, "chdir failed: %r\n");
  194. netlibhistory(file);
  195. hprint(HO, "<BR><A HREF=\"http://cm.bell-labs.com/who/ehg\">Eric Grosse</A>\n");
  196. hprint(HO, "</BODY></HTML>\n");
  197. hflush(HO);
  198. writelog(c, "Reply: 200 netlib_history %ld %ld\n", HO->seek, HO->seek);
  199. return 1;
  200. }
  201. void
  202. main(int argc, char **argv)
  203. {
  204. HConnect *c;
  205. c = init(argc, argv);
  206. HO = &c->hout;
  207. if(hparseheaders(c, HSTIMEOUT) >= 0)
  208. send(c);
  209. exits(nil);
  210. }