]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/httpd/netlib_history.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / ip / httpd / netlib_history.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "httpd.h"
5 #include "httpsrv.h"
6
7 Hio *HO;
8 int diffb;
9
10 enum{ DAY = 24*60*60 };
11
12 void
13 lastbefore(ulong t, char *f, char *b)
14 {
15         Tm *tm;
16         Dir *dir;
17         int try;
18         ulong t0, mtime;
19
20         t0 = t;
21         for(try=0; try<10; try++) {
22                 tm = localtime(t);
23                 t -= DAY;
24                 sprint(b,"%.4d/%.2d%.2d/netlib/pub/%s",tm->year+1900,tm->mon+1,tm->mday,f);
25                 dir = dirstat(b);
26                 if(dir == nil)
27                         continue;
28                 mtime = dir->mtime;
29                 free(dir);
30                 if(mtime > t0)
31                         continue;
32                 return;
33         }
34         strcpy(b, "filenotfound");
35 }
36
37 // create explicit file for diff, which otherwise would create a
38 // mode 0600 file that it couldn't read (because running as none)
39 void
40 gunzip(char *f, char *tmp)
41 {
42         int fd = open(tmp, OWRITE);
43
44         if(fd < 0)  // can't happen
45                 return;
46         switch(fork()){
47         case 0:
48                 dup(fd, 1);
49                 close(fd);
50                 close(0);
51                 execl("/bin/gunzip", "gunzip", "-c", f, nil);
52                 hprint(HO, "can't exec gunzip: %r\n");
53                 break;
54         case -1:
55                 hprint(HO, "fork failed: %r\n");
56         default:
57                 while(waitpid() != -1)
58                         ;
59                 break;
60         }
61         close(fd);
62 }
63
64 void
65 netlibhistory(char *file)
66 {
67         char buf[500], pair[2][500], tmpf[2][30], *f;
68         int toggle = 0, started = 0, limit;
69         Dir *dir;
70         ulong otime, dt;
71         int i, fd, tmpcnt;
72
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
150 int
151 send(HConnect *c)
152 {
153         char *file, *s;
154         HSPairs *q;
155
156         if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
157                 return hunallowed(c, "GET, HEAD");
158         if(c->head.expectother || c->head.expectcont)
159                 return hfail(c, HExpectFail, nil);
160         if(c->req.search == nil || !*c->req.search)
161                 return hfail(c, HNoData, "netlib_history");
162         s = c->req.search;
163         while((s = strchr(s, '+')) != nil)
164                 *s++ = ' ';
165         file = nil;
166         for(q = hparsequery(c, hstrdup(c, c->req.search)); q; q = q->next){
167                 if(strcmp(q->s, "file") == 0)
168                         file = q->t;
169                 else if(strcmp(q->s, "diff") == 0)
170                         diffb = 1;
171         }
172         if(file == nil)
173                 return hfail(c, HNoData, "netlib_history missing file field");
174         logit(c, "netlib_hist %s%s", file, diffb?" DIFF":"");
175
176         if(c->req.vermaj){
177                 hokheaders(c);
178                 hprint(HO, "Content-type: text/html\r\n");
179                 hprint(HO, "\r\n");
180         }
181         if(strcmp(c->req.meth, "HEAD") == 0){
182                 writelog(c, "Reply: 200 netlib_history 0\n");
183                 hflush(HO);
184                 exits(nil);
185         }
186
187         hprint(HO, "<HEAD><TITLE>%s history</TITLE></HEAD>\n<BODY>\n",file);
188         hprint(HO, "<H2>%s history</H2>\n",file);
189         hprint(HO, "<I>Netlib's copy of %s was changed\n", file);
190         hprint(HO, "on the dates shown.  <BR>Click on the date link\n");
191         hprint(HO, "to retrieve the corresponding version.</I>\n");
192         if(diffb){
193                 hprint(HO, "<BR><I>Lines beginning with &lt; are for the\n");
194                 hprint(HO, "newer of the two versions.</I>\n");
195         }
196
197         if(chdir("/usr/web/historic") < 0)
198                 hprint(HO, "chdir failed: %r\n");
199         netlibhistory(file);
200
201         hprint(HO, "<BR><A HREF=\"http://cm.bell-labs.com/who/ehg\">Eric Grosse</A>\n");
202         hprint(HO, "</BODY></HTML>\n");
203         hflush(HO);
204         writelog(c, "Reply: 200 netlib_history %ld %ld\n", HO->seek, HO->seek);
205         return 1;
206 }
207
208 void
209 main(int argc, char **argv)
210 {
211         HConnect *c;
212
213         c = init(argc, argv);
214         HO = &c->hout;
215         if(hparseheaders(c, HSTIMEOUT) >= 0)
216                 send(c);
217         exits(nil);
218 }