X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=lib%2Fcf.c;h=41352090e96c42e9f1faf11c5f30f9595bab3071;hb=7a092cefb32b7dceae2a5140bf9d83f00a991572;hp=f5defd7e37b10a02e1daea4aec0256befadcec81;hpb=f9a65eb249034b28f604dce099deb1a622d373cf;p=ashd.git diff --git a/lib/cf.c b/lib/cf.c index f5defd7..4135209 100644 --- a/lib/cf.c +++ b/lib/cf.c @@ -41,7 +41,9 @@ struct stdchild { int type; char **argv; + char **envp; int fd; + int agains; }; static int parsefile(struct cfstate *s, FILE *in); @@ -308,33 +310,116 @@ static struct chandler stdhandler = { .destroy = stddestroy, }; -static int stdhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata) +static char **expandargs(struct stdchild *sd) { - struct stdchild *i = ch->pdata; + int i; + char **ret, *p, *p2, *p3, *np, *env; + struct charbuf exp; + + ret = szmalloc(sizeof(*ret) * (calen(sd->argv) + 1)); + bufinit(exp); + for(i = 0; sd->argv[i] != NULL; i++) { + if((p = strchr(sd->argv[i], '$')) == NULL) { + ret[i] = sstrdup(sd->argv[i]); + } else { + exp.d = 0; + for(p2 = sd->argv[i]; p != NULL; p2 = np, p = strchr(np, '$')) { + bufcat(exp, p2, p - p2); + if(p[1] == '{') { + if((p3 = strchr((p += 2), '}')) == NULL) + break; + np = p3 + 1; + } else { + for(p3 = ++p; *p3; p3++) { + if(!(((*p3 >= 'a') && (*p3 <= 'z')) || + ((*p3 >= 'A') && (*p3 <= 'Z')) || + ((*p3 >= '0') && (*p3 <= '9')) || + (*p3 == '_'))) { + break; + } + } + np = p3; + } + char temp[(p3 - p) + 1]; + memcpy(temp, p, p3 - p); + temp[p3 - p] = 0; + if((env = getenv(temp)) != NULL) + bufcatstr(exp, env); + } + bufcatstr2(exp, np); + ret[i] = sstrdup(exp.b); + } + } + ret[i] = NULL; + buffree(exp); + return(ret); +} + +struct sidata { + struct stdchild *sd; + void (*sinit)(void *); + void *sdata; +}; + +static void stdinit(void *data) +{ + struct sidata *d = data; + int i; + + for(i = 0; d->sd->envp[i]; i += 2) + putenv(sprintf2("%s=%s", d->sd->envp[i], d->sd->envp[i + 1])); + if(d->sinit != NULL) + d->sinit(d->sdata); +} + +static int stdhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *sdata) +{ + struct stdchild *sd = ch->pdata; int serr; + char **args; + struct sidata idat; - if(i->type == CH_SOCKET) { - if(i->fd < 0) - i->fd = stdmkchild(i->argv, chinit, idata); - if(sendreq2(i->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)) { + if(sd->type == CH_SOCKET) { + idat = (struct sidata) {.sd = sd, .sinit = chinit, .sdata = sdata}; + if(sd->fd < 0) { + args = expandargs(sd); + sd->fd = stdmkchild(args, stdinit, &idat); + freeca(args); + } + if(sendreq2(sd->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)) { serr = errno; if((serr == EPIPE) || (serr == ECONNRESET)) { /* Assume that the child has crashed and restart it. */ - close(i->fd); - i->fd = stdmkchild(i->argv, chinit, idata); - if(!sendreq2(i->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)) - return(0); + close(sd->fd); + args = expandargs(sd); + sd->fd = stdmkchild(args, stdinit, &idat); + freeca(args); + if(!sendreq2(sd->fd, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)) + goto ok; + serr = errno; } - flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(serr)); - if(serr != EAGAIN) { - close(i->fd); - i->fd = -1; + if(serr == EAGAIN) { + if(sd->agains++ == 0) + flog(LOG_WARNING, "request to child %s denied due to buffer overload", ch->name); + } else { + flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(serr)); + close(sd->fd); + sd->fd = -1; } return(-1); } - } else if(i->type == CH_FORK) { - if(stdforkserve(i->argv, req, fd, chinit, idata) < 0) + ok: + if(sd->agains > 0) { + flog(LOG_WARNING, "%i requests to child %s were denied due to buffer overload", sd->agains, ch->name); + sd->agains = 0; + } + } else if(sd->type == CH_FORK) { + args = expandargs(sd); + if(stdforkserve(args, req, fd, chinit, sdata) < 0) { + freeca(args); return(-1); + } + freeca(args); } return(0); } @@ -359,6 +444,8 @@ static void stddestroy(struct child *ch) close(d->fd); if(d->argv) freeca(d->argv); + if(d->envp) + freeca(d->envp); free(d); } @@ -366,6 +453,7 @@ struct child *parsechild(struct cfstate *s) { struct child *ch; struct stdchild *d; + struct charvbuf envbuf; int i; int sl; @@ -393,6 +481,7 @@ struct child *parsechild(struct cfstate *s) } d->fd = -1; + bufinit(envbuf); while(1) { getcfline(s); if(!strcmp(s->argv[0], "exec")) { @@ -403,12 +492,21 @@ struct child *parsechild(struct cfstate *s) d->argv = szmalloc(sizeof(*d->argv) * s->argc); for(i = 0; i < s->argc - 1; i++) d->argv[i] = sstrdup(s->argv[i + 1]); + } else if(!strcmp(s->argv[0], "env")) { + if(s->argc < 3) { + flog(LOG_WARNING, "%s:%i: too few parameters to `env'", s->file, s->lno); + continue; + } + bufadd(envbuf, sstrdup(s->argv[1])); + bufadd(envbuf, sstrdup(s->argv[2])); } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { break; } else { flog(LOG_WARNING, "%s:%i: unknown directive `%s' in child declaration", s->file, s->lno, s->argv[0]); } } + bufadd(envbuf, NULL); + d->envp = envbuf.b; if(d->argv == NULL) { flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", s->file, sl, ch->name); freechild(ch);