X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=slip.c;h=a23675253c603fb580c81ae0954b8e7943d1128f;hp=1a60f40f64490f89f3b6533a55116b3d93d50b7e;hb=423936d35d7671fd017d2d611d418d1b8eeb6195;hpb=ee697dd98d0f9aca6b9df7ffb32d3a15b4e33d6d diff --git a/slip.c b/slip.c index 1a60f40..a236752 100644 --- a/slip.c +++ b/slip.c @@ -31,6 +31,27 @@ struct slip { /* Generic SLIP mangling code */ +static void slip_write(int fd, const uint8_t *p, size_t l) +{ + while (l) { + ssize_t written=write(fd,p,l); + if (written<0) { + if (errno==EINTR) { + continue; + } else if (iswouldblock(errno)) { + lg_perror(0,"slip",0,M_ERR,errno,"write() (packet(s) lost)"); + return; + } else { + fatal_perror("slip_stuff: write()"); + } + } + assert(written>0); + assert((size_t)written<=l); + p+=written; + l-=written; + } +} + static void slip_stuff(struct slip *st, struct buffer_if *buf, int fd) { uint8_t txbuf[DEFAULT_BUFSIZE]; @@ -56,16 +77,12 @@ static void slip_stuff(struct slip *st, struct buffer_if *buf, int fd) break; } if ((j+2)>DEFAULT_BUFSIZE) { - if (write(fd,txbuf,j)<0) { - fatal_perror("slip_stuff: write()"); - } + slip_write(fd,txbuf,j); j=0; } } txbuf[j++]=SLIP_END; - if (write(fd,txbuf,j)<0) { - fatal_perror("slip_stuff: write()"); - } + slip_write(fd,txbuf,j); BUF_FREE(buf); } @@ -195,7 +212,7 @@ static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds) if (fds[1].revents&POLLIN) { l=read(st->rxfd,rxbuf,DEFAULT_BUFSIZE); if (l<0) { - if (errno!=EINTR) + if (errno!=EINTR && !iswouldblock(errno)) fatal_perror("%s: userv_afterpoll: read(rxfd)", st->slip.nl.name); } else if (l==0) { @@ -230,20 +247,13 @@ static void userv_userv_callback(void *sst, pid_t pid, int status) "(expected %d)\n",pid,st->pid); return; } - if (!st->expecting_userv_exit) { - if (WIFEXITED(status)) { - fatal("%s: userv exited unexpectedly with status %d", - st->slip.nl.name,WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - fatal("%s: userv exited unexpectedly: uncaught signal %d", - st->slip.nl.name,WTERMSIG(status)); - } else { - fatal("%s: userv stopped unexpectedly", - st->slip.nl.name); - } + if (!(st->expecting_userv_exit && + (!status || + (WIFSIGNALED(status) && WTERMSIG(status)==SIGTERM)))) { + lg_exitstatus(0,st->slip.nl.name,0, + st->expecting_userv_exit ? M_WARNING : M_FATAL, + status,"userv"); } - Message(M_WARNING,"%s: userv subprocess died with status %d\n", - st->slip.nl.name,WEXITSTATUS(status)); st->pid=0; } @@ -263,8 +273,6 @@ static void userv_entry(void *sst) dup2(st->out,1); setsid(); - /* XXX We really should strdup() all of argv[] but because we'll just - exit anyway if execvp() fails it doesn't seem worth bothering. */ execvp(st->path,(char *const*)st->argv); perror("userv-entry: execvp()"); exit(1); @@ -373,6 +381,11 @@ static void userv_invoke_userv(struct userv *st) st->slip.nl.name,confirm); } } + setnonblock(st->txfd); + setnonblock(st->rxfd); + + add_hook(PHASE_CHILDPERSIST,childpersist_closefd_hook,&st->txfd); + add_hook(PHASE_CHILDPERSIST,childpersist_closefd_hook,&st->rxfd); } static void userv_kill_userv(struct userv *st) @@ -391,7 +404,7 @@ static void userv_phase_hook(void *sst, uint32_t newphase) if (newphase==PHASE_RUN) { userv_invoke_userv(st); /* Register for poll() */ - register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, + register_for_poll(st, userv_beforepoll, userv_afterpoll, st->slip.nl.name); } if (newphase==PHASE_SHUTDOWN) { @@ -406,7 +419,7 @@ static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context, item_t *item; dict_t *dict; - st=safe_malloc(sizeof(*st),"userv_apply"); + NEW(st); /* First parameter must be a dict */ item=list_elem(args,0);