2 00f0146a 2010-11-09 rsc * mirror manager.
3 00f0146a 2010-11-09 rsc * a work in progress.
4 00f0146a 2010-11-09 rsc * use at your own risk.
7 00f0146a 2010-11-09 rsc #include "stdinc.h"
8 00f0146a 2010-11-09 rsc #include <regexp.h>
9 00f0146a 2010-11-09 rsc #include <bio.h>
10 00f0146a 2010-11-09 rsc #include "dat.h"
11 00f0146a 2010-11-09 rsc #include "fns.h"
13 bd51695c 2011-11-21 rsc #ifdef PLAN9PORT
14 bd51695c 2011-11-21 rsc #define sp s.sp
15 bd51695c 2011-11-21 rsc #define ep e.ep
18 00f0146a 2010-11-09 rsc void sendmail(char *content, char *subject, char *msg);
19 00f0146a 2010-11-09 rsc #define TIME "[0-9]+/[0-9]+ [0-9]+:[0-9]+:[0-9]+"
21 00f0146a 2010-11-09 rsc char *mirrorregexp =
22 00f0146a 2010-11-09 rsc "^" TIME " ("
23 00f0146a 2010-11-09 rsc "([^ ]+ \\([0-9,]+-[0-9,]+\\))"
24 00f0146a 2010-11-09 rsc "|( copy [0-9,]+-[0-9,]+ (data|hole|directory|tail))"
25 00f0146a 2010-11-09 rsc "|( sha1 [0-9,]+-[0-9,]+)"
26 bd51695c 2011-11-21 rsc "|([^ ]+: [0-9,]+ used mirrored)"
27 00f0146a 2010-11-09 rsc "|([^ \\-]+-[^ \\-]+( mirrored| sealed| empty)+)"
29 00f0146a 2010-11-09 rsc Reprog *mirrorprog;
31 bd51695c 2011-11-21 rsc char *verifyregexp =
32 bd51695c 2011-11-21 rsc "^" TIME " ("
33 bd51695c 2011-11-21 rsc "([^ ]+: unsealed [0-9,]+ bytes)"
35 bd51695c 2011-11-21 rsc Reprog *verifyprog;
40 00f0146a 2010-11-09 rsc LogSize = 4*1024*1024 // TODO: make smaller
43 00f0146a 2010-11-09 rsc VtLog *errlog;
45 00f0146a 2010-11-09 rsc typedef struct Mirror Mirror;
46 00f0146a 2010-11-09 rsc struct Mirror
52 00f0146a 2010-11-09 rsc typedef struct Conf Conf;
55 00f0146a 2010-11-09 rsc Mirror *mirror;
57 00f0146a 2010-11-09 rsc char **verify;
59 00f0146a 2010-11-09 rsc char *httpaddr;
60 00f0146a 2010-11-09 rsc char *webroot;
62 00f0146a 2010-11-09 rsc char *mailfrom;
63 00f0146a 2010-11-09 rsc char *mailto;
64 00f0146a 2010-11-09 rsc int mirrorfreq;
65 00f0146a 2010-11-09 rsc int verifyfreq;
68 00f0146a 2010-11-09 rsc typedef struct Job Job;
73 00f0146a 2010-11-09 rsc char *argv[10];
76 00f0146a 2010-11-09 rsc VtLog *oldlog;
77 00f0146a 2010-11-09 rsc VtLog *newlog;
82 00f0146a 2010-11-09 rsc vlong runstart;
83 00f0146a 2010-11-09 rsc vlong runend;
84 00f0146a 2010-11-09 rsc double offset;
85 00f0146a 2010-11-09 rsc int (*ok)(char*);
98 00f0146a 2010-11-09 rsc fprint(2, "usage: mgr [-s] [-b bin/venti/] venti.conf\n");
99 00f0146a 2010-11-09 rsc threadexitsall(0);
103 00f0146a 2010-11-09 rsc rdconf(char *file, Conf *conf)
105 00f0146a 2010-11-09 rsc char *s, *line, *flds[10];
109 00f0146a 2010-11-09 rsc if(readifile(&f, file) < 0)
111 00f0146a 2010-11-09 rsc memset(conf, 0, sizeof *conf);
115 00f0146a 2010-11-09 rsc s = ifileline(&f);
116 00f0146a 2010-11-09 rsc if(s == nil){
120 00f0146a 2010-11-09 rsc line = estrdup(s);
121 00f0146a 2010-11-09 rsc i = getfields(s, flds, nelem(flds), 1, " \t\r");
122 00f0146a 2010-11-09 rsc if(i <= 0 || strcmp(flds[0], "mgr") != 0) {
123 00f0146a 2010-11-09 rsc /* do nothing */
124 00f0146a 2010-11-09 rsc }else if(i == 4 && strcmp(flds[1], "mirror") == 0) {
125 00f0146a 2010-11-09 rsc if(conf->nmirror%64 == 0)
126 00f0146a 2010-11-09 rsc conf->mirror = vtrealloc(conf->mirror, (conf->nmirror+64)*sizeof(conf->mirror[0]));
127 00f0146a 2010-11-09 rsc conf->mirror[conf->nmirror].src = vtstrdup(flds[2]);
128 00f0146a 2010-11-09 rsc conf->mirror[conf->nmirror].dst = vtstrdup(flds[3]);
129 00f0146a 2010-11-09 rsc conf->nmirror++;
130 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "mirrorfreq") == 0) {
131 00f0146a 2010-11-09 rsc conf->mirrorfreq = atoi(flds[2]);
132 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "verify") == 0) {
133 00f0146a 2010-11-09 rsc if(conf->nverify%64 == 0)
134 00f0146a 2010-11-09 rsc conf->verify = vtrealloc(conf->verify, (conf->nverify+64)*sizeof(conf->verify[0]));
135 fa325e9b 2020-01-10 cross conf->verify[conf->nverify++] = vtstrdup(flds[2]);
136 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "verifyfreq") == 0) {
137 00f0146a 2010-11-09 rsc conf->verifyfreq = atoi(flds[2]);
138 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "httpaddr") == 0){
139 00f0146a 2010-11-09 rsc if(conf->httpaddr){
140 00f0146a 2010-11-09 rsc seterr(EAdmin, "duplicate httpaddr lines in configuration file %s", file);
143 00f0146a 2010-11-09 rsc conf->httpaddr = estrdup(flds[2]);
144 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "webroot") == 0){
145 00f0146a 2010-11-09 rsc if(conf->webroot){
146 00f0146a 2010-11-09 rsc seterr(EAdmin, "duplicate webroot lines in configuration file %s", file);
149 00f0146a 2010-11-09 rsc conf->webroot = estrdup(flds[2]);
150 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "smtp") == 0) {
151 00f0146a 2010-11-09 rsc if(conf->smtp){
152 00f0146a 2010-11-09 rsc seterr(EAdmin, "duplicate smtp lines in configuration file %s", file);
155 00f0146a 2010-11-09 rsc conf->smtp = estrdup(flds[2]);
156 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "mailfrom") == 0) {
157 00f0146a 2010-11-09 rsc if(conf->mailfrom){
158 00f0146a 2010-11-09 rsc seterr(EAdmin, "duplicate mailfrom lines in configuration file %s", file);
161 00f0146a 2010-11-09 rsc conf->mailfrom = estrdup(flds[2]);
162 00f0146a 2010-11-09 rsc }else if(i == 3 && strcmp(flds[1], "mailto") == 0) {
163 00f0146a 2010-11-09 rsc if(conf->mailto){
164 00f0146a 2010-11-09 rsc seterr(EAdmin, "duplicate mailto lines in configuration file %s", file);
167 00f0146a 2010-11-09 rsc conf->mailto = estrdup(flds[2]);
169 00f0146a 2010-11-09 rsc seterr(EAdmin, "illegal line '%s' in configuration file %s", line, file);
176 00f0146a 2010-11-09 rsc freeifile(&f);
180 00f0146a 2010-11-09 rsc static QLock loglk;
181 00f0146a 2010-11-09 rsc static char *logbuf;
184 00f0146a 2010-11-09 rsc logtext(VtLog *l)
188 00f0146a 2010-11-09 rsc VtLogChunk *c;
192 00f0146a 2010-11-09 rsc for(i=0; i<l->nchunk; i++) {
193 00f0146a 2010-11-09 rsc if(++c == l->chunk+l->nchunk)
194 00f0146a 2010-11-09 rsc c = l->chunk;
195 00f0146a 2010-11-09 rsc memmove(p, c->p, c->wp - c->p);
196 00f0146a 2010-11-09 rsc p += c->wp - c->p;
199 00f0146a 2010-11-09 rsc return logbuf;
203 00f0146a 2010-11-09 rsc typedef struct HttpObj HttpObj;
205 00f0146a 2010-11-09 rsc static int fromwebdir(HConnect*);
209 00f0146a 2010-11-09 rsc ObjNameSize = 64,
210 00f0146a 2010-11-09 rsc MaxObjs = 64
213 00f0146a 2010-11-09 rsc struct HttpObj
215 00f0146a 2010-11-09 rsc char name[ObjNameSize];
216 00f0146a 2010-11-09 rsc int (*f)(HConnect*);
219 00f0146a 2010-11-09 rsc static HttpObj objs[MaxObjs];
220 00f0146a 2010-11-09 rsc static void httpproc(void*);
222 00f0146a 2010-11-09 rsc static HConnect*
223 00f0146a 2010-11-09 rsc mkconnect(void)
225 00f0146a 2010-11-09 rsc HConnect *c;
227 00f0146a 2010-11-09 rsc c = mallocz(sizeof(HConnect), 1);
228 00f0146a 2010-11-09 rsc if(c == nil)
229 00f0146a 2010-11-09 rsc sysfatal("out of memory");
230 00f0146a 2010-11-09 rsc c->replog = nil;
231 00f0146a 2010-11-09 rsc c->hpos = c->header;
232 00f0146a 2010-11-09 rsc c->hstop = c->header;
237 00f0146a 2010-11-09 rsc preq(HConnect *c)
239 00f0146a 2010-11-09 rsc if(hparseheaders(c, 0) < 0)
241 00f0146a 2010-11-09 rsc if(strcmp(c->req.meth, "GET") != 0
242 00f0146a 2010-11-09 rsc && strcmp(c->req.meth, "HEAD") != 0)
243 00f0146a 2010-11-09 rsc return hunallowed(c, "GET, HEAD");
244 00f0146a 2010-11-09 rsc if(c->head.expectother || c->head.expectcont)
245 00f0146a 2010-11-09 rsc return hfail(c, HExpectFail, nil);
250 00f0146a 2010-11-09 rsc hsettype(HConnect *c, char *type)
255 00f0146a 2010-11-09 rsc r = preq(c);
259 00f0146a 2010-11-09 rsc hout = &c->hout;
260 00f0146a 2010-11-09 rsc if(c->req.vermaj){
261 00f0146a 2010-11-09 rsc hokheaders(c);
262 00f0146a 2010-11-09 rsc hprint(hout, "Content-type: %s\r\n", type);
263 00f0146a 2010-11-09 rsc if(http11(c))
264 00f0146a 2010-11-09 rsc hprint(hout, "Transfer-Encoding: chunked\r\n");
265 00f0146a 2010-11-09 rsc hprint(hout, "\r\n");
268 00f0146a 2010-11-09 rsc if(http11(c))
269 00f0146a 2010-11-09 rsc hxferenc(hout, 1);
271 00f0146a 2010-11-09 rsc c->head.closeit = 1;
276 00f0146a 2010-11-09 rsc hsethtml(HConnect *c)
278 00f0146a 2010-11-09 rsc return hsettype(c, "text/html; charset=utf-8");
282 00f0146a 2010-11-09 rsc hsettext(HConnect *c)
284 00f0146a 2010-11-09 rsc return hsettype(c, "text/plain; charset=utf-8");
288 00f0146a 2010-11-09 rsc hnotfound(HConnect *c)
292 00f0146a 2010-11-09 rsc r = preq(c);
295 00f0146a 2010-11-09 rsc return hfail(c, HNotFound, c->req.uri);
299 00f0146a 2010-11-09 rsc xloglist(HConnect *c)
301 00f0146a 2010-11-09 rsc if(hsettype(c, "text/html") < 0)
303 00f0146a 2010-11-09 rsc vtloghlist(&c->hout);
304 00f0146a 2010-11-09 rsc hflush(&c->hout);
309 00f0146a 2010-11-09 rsc strpcmp(const void *va, const void *vb)
311 00f0146a 2010-11-09 rsc return strcmp(*(char**)va, *(char**)vb);
315 00f0146a 2010-11-09 rsc vtloghlist(Hio *h)
320 00f0146a 2010-11-09 rsc hprint(h, "<html><head>\n");
321 00f0146a 2010-11-09 rsc hprint(h, "<title>Venti Server Logs</title>\n");
322 00f0146a 2010-11-09 rsc hprint(h, "</head><body>\n");
323 00f0146a 2010-11-09 rsc hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
325 00f0146a 2010-11-09 rsc p = vtlognames(&n);
326 00f0146a 2010-11-09 rsc qsort(p, n, sizeof(p[0]), strpcmp);
327 00f0146a 2010-11-09 rsc for(i=0; i<n; i++)
328 00f0146a 2010-11-09 rsc hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
330 00f0146a 2010-11-09 rsc hprint(h, "</body></html>\n");
334 00f0146a 2010-11-09 rsc vtloghdump(Hio *h, VtLog *l)
337 00f0146a 2010-11-09 rsc VtLogChunk *c;
340 00f0146a 2010-11-09 rsc name = l ? l->name : "<nil>";
342 00f0146a 2010-11-09 rsc hprint(h, "<html><head>\n");
343 00f0146a 2010-11-09 rsc hprint(h, "<title>Venti Server Log: %s</title>\n", name);
344 00f0146a 2010-11-09 rsc hprint(h, "</head><body>\n");
345 00f0146a 2010-11-09 rsc hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
349 00f0146a 2010-11-09 rsc for(i=0; i<l->nchunk; i++){
350 00f0146a 2010-11-09 rsc if(++c == l->chunk+l->nchunk)
351 00f0146a 2010-11-09 rsc c = l->chunk;
352 00f0146a 2010-11-09 rsc hwrite(h, c->p, c->wp-c->p);
355 00f0146a 2010-11-09 rsc hprint(h, "</body></html>\n");
360 00f0146a 2010-11-09 rsc hargstr(HConnect *c, char *name, char *def)
364 00f0146a 2010-11-09 rsc for(p=c->req.searchpairs; p; p=p->next)
365 00f0146a 2010-11-09 rsc if(strcmp(p->s, name) == 0)
366 00f0146a 2010-11-09 rsc return p->t;
371 00f0146a 2010-11-09 rsc xlog(HConnect *c)
376 00f0146a 2010-11-09 rsc name = hargstr(c, "log", "");
377 00f0146a 2010-11-09 rsc if(!name[0])
378 00f0146a 2010-11-09 rsc return xloglist(c);
379 00f0146a 2010-11-09 rsc l = vtlogopen(name, 0);
380 00f0146a 2010-11-09 rsc if(l == nil)
381 00f0146a 2010-11-09 rsc return hnotfound(c);
382 00f0146a 2010-11-09 rsc if(hsettype(c, "text/html") < 0){
383 00f0146a 2010-11-09 rsc vtlogclose(l);
386 00f0146a 2010-11-09 rsc vtloghdump(&c->hout, l);
387 00f0146a 2010-11-09 rsc vtlogclose(l);
388 00f0146a 2010-11-09 rsc hflush(&c->hout);
393 00f0146a 2010-11-09 rsc httpdproc(void *vaddress)
395 00f0146a 2010-11-09 rsc HConnect *c;
396 00f0146a 2010-11-09 rsc char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
397 00f0146a 2010-11-09 rsc int ctl, nctl, data;
399 00f0146a 2010-11-09 rsc address = vaddress;
400 00f0146a 2010-11-09 rsc ctl = announce(address, dir);
401 00f0146a 2010-11-09 rsc if(ctl < 0){
402 00f0146a 2010-11-09 rsc sysfatal("announce %s: %r", address);
406 00f0146a 2010-11-09 rsc if(0) print("announce ctl %d dir %s\n", ctl, dir);
409 00f0146a 2010-11-09 rsc * wait for a call (or an error)
411 00f0146a 2010-11-09 rsc nctl = listen(dir, ndir);
412 00f0146a 2010-11-09 rsc if(0) print("httpd listen %d %s...\n", nctl, ndir);
413 00f0146a 2010-11-09 rsc if(nctl < 0){
414 00f0146a 2010-11-09 rsc fprint(2, "mgr: httpd can't listen on %s: %r\n", address);
418 00f0146a 2010-11-09 rsc data = accept(ctl, ndir);
419 00f0146a 2010-11-09 rsc if(0) print("httpd accept %d...\n", data);
420 00f0146a 2010-11-09 rsc if(data < 0){
421 00f0146a 2010-11-09 rsc fprint(2, "mgr: httpd accept: %r\n");
422 00f0146a 2010-11-09 rsc close(nctl);
425 00f0146a 2010-11-09 rsc if(0) print("httpd close nctl %d\n", nctl);
426 00f0146a 2010-11-09 rsc close(nctl);
427 00f0146a 2010-11-09 rsc c = mkconnect();
428 00f0146a 2010-11-09 rsc hinit(&c->hin, data, Hread);
429 00f0146a 2010-11-09 rsc hinit(&c->hout, data, Hwrite);
430 00f0146a 2010-11-09 rsc vtproc(httpproc, c);
435 00f0146a 2010-11-09 rsc httpproc(void *v)
437 00f0146a 2010-11-09 rsc HConnect *c;
438 00f0146a 2010-11-09 rsc int ok, i, n;
444 00f0146a 2010-11-09 rsc * No timeout because the signal appears to hit every
445 00f0146a 2010-11-09 rsc * proc, not just us.
447 00f0146a 2010-11-09 rsc if(hparsereq(c, 0) < 0)
450 00f0146a 2010-11-09 rsc for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
451 00f0146a 2010-11-09 rsc n = strlen(objs[i].name);
452 00f0146a 2010-11-09 rsc if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
453 00f0146a 2010-11-09 rsc || (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
454 00f0146a 2010-11-09 rsc ok = (*objs[i].f)(c);
458 00f0146a 2010-11-09 rsc ok = fromwebdir(c);
460 00f0146a 2010-11-09 rsc hflush(&c->hout);
461 00f0146a 2010-11-09 rsc if(c->head.closeit)
463 00f0146a 2010-11-09 rsc hreqcleanup(c);
468 00f0146a 2010-11-09 rsc hreqcleanup(c);
469 00f0146a 2010-11-09 rsc close(c->hin.fd);
474 00f0146a 2010-11-09 rsc httpdobj(char *name, int (*f)(HConnect*))
478 00f0146a 2010-11-09 rsc if(name == nil || strlen(name) >= ObjNameSize)
480 00f0146a 2010-11-09 rsc for(i = 0; i < MaxObjs; i++){
481 00f0146a 2010-11-09 rsc if(objs[i].name[0] == '\0'){
482 00f0146a 2010-11-09 rsc strcpy(objs[i].name, name);
483 00f0146a 2010-11-09 rsc objs[i].f = f;
486 00f0146a 2010-11-09 rsc if(strcmp(objs[i].name, name) == 0)
496 00f0146a 2010-11-09 rsc } exttab[] = {
497 00f0146a 2010-11-09 rsc ".html", "text/html",
498 00f0146a 2010-11-09 rsc ".txt", "text/plain",
499 00f0146a 2010-11-09 rsc ".xml", "text/xml",
500 00f0146a 2010-11-09 rsc ".png", "image/png",
501 00f0146a 2010-11-09 rsc ".gif", "image/gif",
506 00f0146a 2010-11-09 rsc fromwebdir(HConnect *c)
508 00f0146a 2010-11-09 rsc char buf[4096], *p, *ext, *type;
509 00f0146a 2010-11-09 rsc int i, fd, n, defaulted;
512 00f0146a 2010-11-09 rsc if(conf.webroot == nil || strstr(c->req.uri, ".."))
513 00f0146a 2010-11-09 rsc return hnotfound(c);
514 00f0146a 2010-11-09 rsc snprint(buf, sizeof buf-20, "%s/%s", conf.webroot, c->req.uri+1);
515 00f0146a 2010-11-09 rsc defaulted = 0;
517 00f0146a 2010-11-09 rsc if((fd = open(buf, OREAD)) < 0)
518 00f0146a 2010-11-09 rsc return hnotfound(c);
519 00f0146a 2010-11-09 rsc d = dirfstat(fd);
520 00f0146a 2010-11-09 rsc if(d == nil){
522 00f0146a 2010-11-09 rsc return hnotfound(c);
524 00f0146a 2010-11-09 rsc if(d->mode&DMDIR){
525 00f0146a 2010-11-09 rsc if(!defaulted){
526 00f0146a 2010-11-09 rsc defaulted = 1;
527 00f0146a 2010-11-09 rsc strcat(buf, "/index.html");
530 00f0146a 2010-11-09 rsc goto reopen;
533 00f0146a 2010-11-09 rsc return hnotfound(c);
536 00f0146a 2010-11-09 rsc p = buf+strlen(buf);
537 00f0146a 2010-11-09 rsc type = "application/octet-stream";
538 00f0146a 2010-11-09 rsc for(i=0; exttab[i].ext; i++){
539 00f0146a 2010-11-09 rsc ext = exttab[i].ext;
540 00f0146a 2010-11-09 rsc if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
541 00f0146a 2010-11-09 rsc type = exttab[i].type;
545 00f0146a 2010-11-09 rsc if(hsettype(c, type) < 0){
549 00f0146a 2010-11-09 rsc while((n = read(fd, buf, sizeof buf)) > 0)
550 00f0146a 2010-11-09 rsc if(hwrite(&c->hout, buf, n) < 0)
553 00f0146a 2010-11-09 rsc hflush(&c->hout);
558 00f0146a 2010-11-09 rsc hmanager(HConnect *c)
565 00f0146a 2010-11-09 rsc VtLogChunk *ch;
567 00f0146a 2010-11-09 rsc r = hsethtml(c);
571 00f0146a 2010-11-09 rsc hout = &c->hout;
572 00f0146a 2010-11-09 rsc hprint(hout, "<html><head><title>venti mgr status</title></head>\n");
573 00f0146a 2010-11-09 rsc hprint(hout, "<body><h2>venti mgr status</h2>\n");
575 00f0146a 2010-11-09 rsc for(i=0; i<njob; i++) {
576 00f0146a 2010-11-09 rsc j = &job[i];
577 00f0146a 2010-11-09 rsc hprint(hout, "<b>");
578 00f0146a 2010-11-09 rsc if(j->nrun == 0)
579 00f0146a 2010-11-09 rsc hprint(hout, "----/--/-- --:--:--");
581 00f0146a 2010-11-09 rsc hprint(hout, "%+T", (long)(j->runstart + time0));
582 00f0146a 2010-11-09 rsc hprint(hout, " %s", j->name);
583 00f0146a 2010-11-09 rsc if(j->nrun > 0) {
584 00f0146a 2010-11-09 rsc if(j->newok == -1) {
585 00f0146a 2010-11-09 rsc hprint(hout, " (running)");
586 00f0146a 2010-11-09 rsc } else if(!j->newok) {
587 00f0146a 2010-11-09 rsc hprint(hout, " <font color=\"#cc0000\">(FAILED)</font>");
590 00f0146a 2010-11-09 rsc hprint(hout, "</b>\n");
591 00f0146a 2010-11-09 rsc hprint(hout, "<font size=-1><pre>\n");
592 00f0146a 2010-11-09 rsc l = j->newlog;
594 00f0146a 2010-11-09 rsc for(k=0; k<l->nchunk; k++){
595 00f0146a 2010-11-09 rsc if(++ch == l->chunk+l->nchunk)
596 00f0146a 2010-11-09 rsc ch = l->chunk;
597 00f0146a 2010-11-09 rsc hwrite(hout, ch->p, ch->wp-ch->p);
599 00f0146a 2010-11-09 rsc hprint(hout, "</pre></font>\n");
600 00f0146a 2010-11-09 rsc hprint(hout, "\n");
602 00f0146a 2010-11-09 rsc hprint(hout, "</body></html>\n");
603 00f0146a 2010-11-09 rsc hflush(hout);
608 00f0146a 2010-11-09 rsc piper(void *v)
611 00f0146a 2010-11-09 rsc char buf[512];
619 00f0146a 2010-11-09 rsc fd = j->pipe;
620 00f0146a 2010-11-09 rsc l = j->newlog;
621 00f0146a 2010-11-09 rsc while((n = read(fd, buf, 512-1)) > 0) {
623 00f0146a 2010-11-09 rsc if(l != nil)
624 00f0146a 2010-11-09 rsc vtlogprint(l, "%s", buf);
626 00f0146a 2010-11-09 rsc qlock(&loglk);
627 00f0146a 2010-11-09 rsc p = logtext(l);
628 fa325e9b 2020-01-10 cross ok = j->ok(p);
629 00f0146a 2010-11-09 rsc qunlock(&loglk);
630 00f0146a 2010-11-09 rsc j->newok = ok;
635 00f0146a 2010-11-09 rsc kickjob(Job *j)
642 00f0146a 2010-11-09 rsc if((fd[0] = open("/dev/null", ORDWR)) < 0) {
643 00f0146a 2010-11-09 rsc vtlogprint(errlog, "%T open /dev/null: %r\n");
646 00f0146a 2010-11-09 rsc if(pipe(p) < 0) {
647 00f0146a 2010-11-09 rsc vtlogprint(errlog, "%T pipe: %r\n");
648 00f0146a 2010-11-09 rsc close(fd[0]);
651 00f0146a 2010-11-09 rsc qlock(&j->lk);
652 00f0146a 2010-11-09 rsc l = j->oldlog;
653 00f0146a 2010-11-09 rsc j->oldlog = j->newlog;
654 00f0146a 2010-11-09 rsc j->newlog = l;
655 00f0146a 2010-11-09 rsc qlock(&l->lk);
656 00f0146a 2010-11-09 rsc for(i=0; i<l->nchunk; i++)
657 00f0146a 2010-11-09 rsc l->chunk[i].wp = l->chunk[i].p;
658 00f0146a 2010-11-09 rsc qunlock(&l->lk);
659 00f0146a 2010-11-09 rsc j->oldok = j->newok;
660 00f0146a 2010-11-09 rsc j->newok = -1;
661 00f0146a 2010-11-09 rsc qunlock(&j->lk);
663 00f0146a 2010-11-09 rsc fd[1] = p[1];
664 00f0146a 2010-11-09 rsc fd[2] = p[1];
665 00f0146a 2010-11-09 rsc j->pid = threadspawn(fd, j->argv[0], j->argv);
666 00f0146a 2010-11-09 rsc if(j->pid < 0) {
667 00f0146a 2010-11-09 rsc vtlogprint(errlog, "%T exec %s: %r\n", j->argv[0]);
668 00f0146a 2010-11-09 rsc close(fd[0]);
669 00f0146a 2010-11-09 rsc close(fd[1]);
670 00f0146a 2010-11-09 rsc close(p[0]);
672 00f0146a 2010-11-09 rsc // fd[0], fd[1], fd[2] are closed now
673 00f0146a 2010-11-09 rsc j->pipe = p[0];
675 00f0146a 2010-11-09 rsc vtproc(piper, j);
679 00f0146a 2010-11-09 rsc getline(Resub *text, Resub *line)
683 bd51695c 2011-11-21 rsc if(text->sp >= text->ep)
685 bd51695c 2011-11-21 rsc line->sp = text->sp;
686 bd51695c 2011-11-21 rsc p = memchr(text->sp, '\n', text->ep - text->sp);
687 00f0146a 2010-11-09 rsc if(p == nil) {
688 bd51695c 2011-11-21 rsc line->ep = text->ep;
689 bd51695c 2011-11-21 rsc text->sp = text->ep;
691 bd51695c 2011-11-21 rsc line->ep = p;
692 bd51695c 2011-11-21 rsc text->sp = p+1;
698 bd51695c 2011-11-21 rsc verifyok(char *output)
700 00f0146a 2010-11-09 rsc Resub text, line, m;
702 bd51695c 2011-11-21 rsc text.sp = output;
703 bd51695c 2011-11-21 rsc text.ep = output+strlen(output);
704 00f0146a 2010-11-09 rsc while(getline(&text, &line) >= 0) {
705 bd51695c 2011-11-21 rsc *line.ep = 0;
706 00f0146a 2010-11-09 rsc memset(&m, 0, sizeof m);
707 bd51695c 2011-11-21 rsc if(!regexec(verifyprog, line.sp, nil, 0))
709 bd51695c 2011-11-21 rsc *line.ep = '\n';
715 bd51695c 2011-11-21 rsc mirrorok(char *output)
717 bd51695c 2011-11-21 rsc Resub text, line, m;
719 bd51695c 2011-11-21 rsc text.sp = output;
720 bd51695c 2011-11-21 rsc text.ep = output+strlen(output);
721 bd51695c 2011-11-21 rsc while(getline(&text, &line) >= 0) {
722 bd51695c 2011-11-21 rsc *line.ep = 0;
723 bd51695c 2011-11-21 rsc memset(&m, 0, sizeof m);
724 bd51695c 2011-11-21 rsc if(!regexec(mirrorprog, line.sp, nil, 0))
726 bd51695c 2011-11-21 rsc *line.ep = '\n';
732 00f0146a 2010-11-09 rsc mkjob(Job *j, ...)
736 00f0146a 2010-11-09 rsc va_list arg;
738 00f0146a 2010-11-09 rsc memset(j, 0, sizeof *j);
740 00f0146a 2010-11-09 rsc va_start(arg, j);
741 00f0146a 2010-11-09 rsc while((p = va_arg(arg, char*)) != nil) {
742 00f0146a 2010-11-09 rsc j->argv[i++] = p;
743 00f0146a 2010-11-09 rsc if(i >= nelem(j->argv))
744 00f0146a 2010-11-09 rsc sysfatal("job argv size too small");
746 00f0146a 2010-11-09 rsc j->argv[i] = nil;
747 bd51695c 2011-11-21 rsc j->oldlog = vtlogopen(smprint("log%ld.0", j-job), LogSize);
748 bd51695c 2011-11-21 rsc j->newlog = vtlogopen(smprint("log%ld.1", j-job), LogSize);
749 00f0146a 2010-11-09 rsc va_end(arg);
753 00f0146a 2010-11-09 rsc manager(void *v)
760 00f0146a 2010-11-09 rsc for(;; sleep(1000)) {
761 00f0146a 2010-11-09 rsc for(i=0; i<njob; i++) {
762 00f0146a 2010-11-09 rsc now = time(0) - time0;
763 00f0146a 2010-11-09 rsc j = &job[i];
764 00f0146a 2010-11-09 rsc if(j->pid > 0 || j->newok == -1) {
765 00f0146a 2010-11-09 rsc // still running
766 00f0146a 2010-11-09 rsc if(now - j->runstart > 2*j->freq) {
767 00f0146a 2010-11-09 rsc //TODO: log slow running j
771 00f0146a 2010-11-09 rsc if((j->nrun > 0 && now - j->runend > j->freq)
772 00f0146a 2010-11-09 rsc || (j->nrun == 0 && now > (vlong)(j->offset*j->freq))) {
773 00f0146a 2010-11-09 rsc j->runstart = now;
774 00f0146a 2010-11-09 rsc j->runend = 0;
782 00f0146a 2010-11-09 rsc waitproc(void *v)
791 00f0146a 2010-11-09 rsc w = recvp(c);
792 00f0146a 2010-11-09 rsc for(i=0; i<njob; i++) {
793 00f0146a 2010-11-09 rsc j = &job[i];
794 00f0146a 2010-11-09 rsc if(j->pid == w->pid) {
796 00f0146a 2010-11-09 rsc j->runend = time(0) - time0;
805 00f0146a 2010-11-09 rsc threadmain(int argc, char **argv)
812 00f0146a 2010-11-09 rsc ventilogging = 1;
813 00f0146a 2010-11-09 rsc ventifmtinstall();
814 bd51695c 2011-11-21 rsc #ifdef PLAN9PORT
815 00f0146a 2010-11-09 rsc bin = unsharp("#9/bin/venti");
817 bd51695c 2011-11-21 rsc bin = "/bin/venti";
822 00f0146a 2010-11-09 rsc bin = EARGF(usage());
831 00f0146a 2010-11-09 rsc if(argc != 1)
833 00f0146a 2010-11-09 rsc if(rdconf(argv[0], &conf) < 0)
834 00f0146a 2010-11-09 rsc sysfatal("reading config: %r");
835 00f0146a 2010-11-09 rsc if(conf.httpaddr == nil)
836 00f0146a 2010-11-09 rsc sysfatal("config has no httpaddr");
837 00f0146a 2010-11-09 rsc if(conf.smtp != nil && conf.mailfrom == nil)
838 00f0146a 2010-11-09 rsc sysfatal("config has smtp but no mailfrom");
839 00f0146a 2010-11-09 rsc if(conf.smtp != nil && conf.mailto == nil)
840 00f0146a 2010-11-09 rsc sysfatal("config has smtp but no mailto");
841 00f0146a 2010-11-09 rsc if((mirrorprog = regcomp(mirrorregexp)) == nil)
842 bd51695c 2011-11-21 rsc sysfatal("mirrorregexp did not complete");
843 bd51695c 2011-11-21 rsc if((verifyprog = regcomp(verifyregexp)) == nil)
844 bd51695c 2011-11-21 rsc sysfatal("verifyregexp did not complete");
845 00f0146a 2010-11-09 rsc if(conf.nverify > 0 && conf.verifyfreq == 0)
846 00f0146a 2010-11-09 rsc sysfatal("config has no verifyfreq");
847 00f0146a 2010-11-09 rsc if(conf.nmirror > 0 && conf.mirrorfreq == 0)
848 00f0146a 2010-11-09 rsc sysfatal("config has no mirrorfreq");
850 00f0146a 2010-11-09 rsc time0 = time(0);
851 00f0146a 2010-11-09 rsc // sendmail("startup", "mgr is starting\n");
853 00f0146a 2010-11-09 rsc logbuf = vtmalloc(LogSize+1); // +1 for NUL
855 00f0146a 2010-11-09 rsc errlog = vtlogopen("errors", LogSize);
856 00f0146a 2010-11-09 rsc job = vtmalloc((conf.nmirror+conf.nverify)*sizeof job[0]);
857 00f0146a 2010-11-09 rsc prog = smprint("%s/mirrorarenas", bin);
858 00f0146a 2010-11-09 rsc for(i=0; i<conf.nmirror; i++) {
859 00f0146a 2010-11-09 rsc // job: /bin/venti/mirrorarenas -v src dst
860 00f0146a 2010-11-09 rsc // filter output
861 00f0146a 2010-11-09 rsc j = &job[njob++];
862 bd51695c 2011-11-21 rsc mkjob(j, prog, "-v", conf.mirror[i].src, conf.mirror[i].dst, nil);
863 00f0146a 2010-11-09 rsc j->name = smprint("mirror %s %s", conf.mirror[i].src, conf.mirror[i].dst);
864 00f0146a 2010-11-09 rsc j->ok = mirrorok;
865 00f0146a 2010-11-09 rsc j->freq = conf.mirrorfreq; // 4 hours // TODO: put in config
866 00f0146a 2010-11-09 rsc j->offset = (double)i/conf.nmirror;
869 00f0146a 2010-11-09 rsc prog = smprint("%s/verifyarena", bin);
870 00f0146a 2010-11-09 rsc for(i=0; i<conf.nverify; i++) {
871 00f0146a 2010-11-09 rsc // job: /bin/venti/verifyarena -b 64M -s 1000 -v arena
872 00f0146a 2010-11-09 rsc // filter output
873 00f0146a 2010-11-09 rsc j = &job[njob++];
874 bd51695c 2011-11-21 rsc mkjob(j, prog, "-b64M", "-s1000", conf.verify[i], nil);
875 00f0146a 2010-11-09 rsc j->name = smprint("verify %s", conf.verify[i]);
876 00f0146a 2010-11-09 rsc j->ok = verifyok;
877 00f0146a 2010-11-09 rsc j->freq = conf.verifyfreq;
878 00f0146a 2010-11-09 rsc j->offset = (double)i/conf.nverify;
881 00f0146a 2010-11-09 rsc httpdobj("/mgr", hmanager);
882 00f0146a 2010-11-09 rsc httpdobj("/log", xlog);
883 00f0146a 2010-11-09 rsc vtproc(httpdproc, conf.httpaddr);
884 00f0146a 2010-11-09 rsc vtproc(waitproc, threadwaitchan());
886 00f0146a 2010-11-09 rsc manager(nil);
888 00f0146a 2010-11-09 rsc vtproc(manager, nil);
893 00f0146a 2010-11-09 rsc qp(Biobuf *b, char *p)
895 00f0146a 2010-11-09 rsc int n, nspace;
897 fa325e9b 2020-01-10 cross nspace = 0;
899 00f0146a 2010-11-09 rsc for(; *p; p++) {
900 00f0146a 2010-11-09 rsc if(*p == '\n') {
901 00f0146a 2010-11-09 rsc if(nspace > 0) {
903 00f0146a 2010-11-09 rsc Bprint(b, "=\n");
905 00f0146a 2010-11-09 rsc Bputc(b, '\n');
909 00f0146a 2010-11-09 rsc if(n > 70) {
910 00f0146a 2010-11-09 rsc Bprint(b, "=\n");
914 00f0146a 2010-11-09 rsc if(33 <= *p && *p <= 126 && *p != '=') {
915 00f0146a 2010-11-09 rsc Bputc(b, *p);
920 00f0146a 2010-11-09 rsc if(*p == ' ' || *p == '\t') {
921 00f0146a 2010-11-09 rsc Bputc(b, *p);
926 00f0146a 2010-11-09 rsc Bprint(b, "=%02X", (uchar)*p);
933 00f0146a 2010-11-09 rsc smtpread(Biobuf *b, int code)
935 00f0146a 2010-11-09 rsc char *p, *q;
938 00f0146a 2010-11-09 rsc while((p = Brdstr(b, '\n', 1)) != nil) {
939 00f0146a 2010-11-09 rsc n = strtol(p, &q, 10);
940 00f0146a 2010-11-09 rsc if(n == 0 || q != p+3) {
942 00f0146a 2010-11-09 rsc vtlogprint(errlog, "sending mail: %s\n", p);
946 00f0146a 2010-11-09 rsc if(*q == ' ') {
947 00f0146a 2010-11-09 rsc if(n == code) {
953 00f0146a 2010-11-09 rsc if(*q != '-') {
962 00f0146a 2010-11-09 rsc sendmail(char *content, char *subject, char *msg)
965 00f0146a 2010-11-09 rsc Biobuf *bin, *bout;
967 00f0146a 2010-11-09 rsc if((fd = dial(conf.smtp, 0, 0, 0)) < 0) {
968 00f0146a 2010-11-09 rsc vtlogprint(errlog, "dial %s: %r\n", conf.smtp);
971 00f0146a 2010-11-09 rsc bin = vtmalloc(sizeof *bin);
972 00f0146a 2010-11-09 rsc bout = vtmalloc(sizeof *bout);
973 00f0146a 2010-11-09 rsc Binit(bin, fd, OREAD);
974 00f0146a 2010-11-09 rsc Binit(bout, fd, OWRITE);
975 00f0146a 2010-11-09 rsc if(smtpread(bin, 220) < 0){
979 00f0146a 2010-11-09 rsc Bterm(bout);
983 00f0146a 2010-11-09 rsc Bprint(bout, "HELO venti-mgr\n");
984 00f0146a 2010-11-09 rsc Bflush(bout);
985 00f0146a 2010-11-09 rsc if(smtpread(bin, 250) < 0)
988 00f0146a 2010-11-09 rsc Bprint(bout, "MAIL FROM:<%s>\n", conf.mailfrom);
989 00f0146a 2010-11-09 rsc Bflush(bout);
990 00f0146a 2010-11-09 rsc if(smtpread(bin, 250) < 0)
993 00f0146a 2010-11-09 rsc Bprint(bout, "RCPT TO:<%s>\n", conf.mailfrom);
994 00f0146a 2010-11-09 rsc Bflush(bout);
995 00f0146a 2010-11-09 rsc if(smtpread(bin, 250) < 0)
998 00f0146a 2010-11-09 rsc Bprint(bout, "DATA\n");
999 00f0146a 2010-11-09 rsc Bflush(bout);
1000 00f0146a 2010-11-09 rsc if(smtpread(bin, 354) < 0)
1001 00f0146a 2010-11-09 rsc goto error;
1003 00f0146a 2010-11-09 rsc Bprint(bout, "From: \"venti mgr\" <%s>\n", conf.mailfrom);
1004 00f0146a 2010-11-09 rsc Bprint(bout, "To: <%s>\n", conf.mailto);
1005 00f0146a 2010-11-09 rsc Bprint(bout, "Subject: %s\n", subject);
1006 00f0146a 2010-11-09 rsc Bprint(bout, "MIME-Version: 1.0\n");
1007 00f0146a 2010-11-09 rsc Bprint(bout, "Content-Type: %s; charset=\"UTF-8\"\n", content);
1008 00f0146a 2010-11-09 rsc Bprint(bout, "Content-Transfer-Encoding: quoted-printable\n");
1009 bd51695c 2011-11-21 rsc Bprint(bout, "Message-ID: %08lux%08lux@venti.swtch.com\n", fastrand(), fastrand());
1010 00f0146a 2010-11-09 rsc Bprint(bout, "\n");
1011 00f0146a 2010-11-09 rsc qp(bout, msg);
1012 00f0146a 2010-11-09 rsc Bprint(bout, ".\n");
1013 00f0146a 2010-11-09 rsc Bflush(bout);
1014 00f0146a 2010-11-09 rsc if(smtpread(bin, 250) < 0)
1015 00f0146a 2010-11-09 rsc goto error;
1017 00f0146a 2010-11-09 rsc Bprint(bout, "QUIT\n");
1018 00f0146a 2010-11-09 rsc Bflush(bout);
1019 00f0146a 2010-11-09 rsc Bterm(bin);
1020 00f0146a 2010-11-09 rsc Bterm(bout);