X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=secnet.c;h=f9808b78b828baf036cd3359bb5246f84bbbe7b4;hp=a21e52b39753c68c3fa562203c429b218088ebc3;hb=076bb54e68477f883033bee696c9c5f801ece2f2;hpb=4f5e39ecfaa49376b0a5c3a4c384e91a828c1105 diff --git a/secnet.c b/secnet.c index a21e52b..f9808b7 100644 --- a/secnet.c +++ b/secnet.c @@ -1,7 +1,7 @@ -extern char version[]; - #include "secnet.h" #include +#include +#include #include #include #include @@ -14,39 +14,36 @@ extern char version[]; #include "conffile.h" #include "process.h" +#if __APPLE__ +/* apple's poll() does not work on char devs */ +# define USE_SELECT 1 +#endif + /* XXX should be from autoconf */ -static char *configfile="/etc/secnet/secnet.conf"; -static char *sites_key="sites"; +static const char *configfile="/etc/secnet/secnet.conf"; +static const char *sites_key="sites"; bool_t just_check_config=False; static char *userid=NULL; static uid_t uid=0; bool_t background=True; static char *pidfile=NULL; bool_t require_root_privileges=False; -string_t require_root_privileges_explanation=NULL; +cstring_t require_root_privileges_explanation=NULL; static pid_t secnet_pid; -/* from log.c */ -extern uint32_t message_level; -extern bool_t secnet_is_daemon; -extern struct log_if *system_log; - -/* from process.c */ -extern void start_signal_handling(void); - /* Structures dealing with poll() call */ struct poll_interest { beforepoll_fn *before; afterpoll_fn *after; void *state; - uint32_t max_nfds; - uint32_t nfds; - string_t desc; + int32_t max_nfds; + int32_t nfds; + cstring_t desc; struct poll_interest *next; }; static struct poll_interest *reg=NULL; -static uint32_t total_nfds=10; +static int32_t total_nfds=10; static bool_t finished=False; @@ -65,7 +62,7 @@ static void parse_options(int argc, char **argv) {"nodetach", 0, 0, 'n'}, {"silent", 0, 0, 'f'}, {"quiet", 0, 0, 'f'}, - {"debug", 1, 0, 'd'}, + {"debug", 0, 0, 'd'}, {"config", 1, 0, 'c'}, {"just-check-config", 0, 0, 'j'}, {"sites-key", 1, 0, 's'}, @@ -90,7 +87,7 @@ static void parse_options(int argc, char **argv) " -s, --sites-key=name configuration key that " "specifies active sites\n" " -n, --nodetach do not run in background\n" - " -d, --debug=item,... set debug options\n" + " -d, --debug output debug messages\n" " --help display this help and exit\n" " --version output version information " "and exit\n" @@ -144,6 +141,7 @@ static void parse_options(int argc, char **argv) break; case '?': + exit(1); break; default: @@ -229,7 +227,7 @@ static void setup(dict_t *config) } void register_for_poll(void *st, beforepoll_fn *before, - afterpoll_fn *after, uint32_t max_nfds, string_t desc) + afterpoll_fn *after, int32_t max_nfds, cstring_t desc) { struct poll_interest *i; @@ -240,6 +238,7 @@ void register_for_poll(void *st, beforepoll_fn *before, i->max_nfds=max_nfds; i->nfds=0; i->desc=desc; + assert(total_nfds < INT_MAX - max_nfds); total_nfds+=max_nfds; i->next=reg; reg=i; @@ -254,31 +253,70 @@ static void system_phase_hook(void *sst, uint32_t newphase) } } +#if USE_SELECT +static int fakepoll(struct pollfd *fds, int nfds, int timeout) { + fd_set infds[1], outfds[1]; + int maxfd = -1, i, rc; + struct timeval tvtimeout; + FD_ZERO(infds); + FD_ZERO(outfds); + for(i = 0; i < nfds; ++i) { + if(fds[i].events & POLLIN) + FD_SET(fds[i].fd, infds); + if(fds[i].events & POLLOUT) + FD_SET(fds[i].fd, outfds); + if(fds[i].fd > maxfd) + maxfd = fds[i].fd; + } + if(timeout != -1) { + tvtimeout.tv_sec = timeout / 1000; + tvtimeout.tv_usec = 1000 * (timeout % 1000); + } + rc = select(maxfd + 1, infds, outfds, NULL, + timeout == -1 ? NULL : &tvtimeout); + if(rc >= 0) { + for(i = 0; i < nfds; ++i) { + int revents = 0; + if(FD_ISSET(fds[i].fd, infds)) + revents |= POLLIN; + if(FD_ISSET(fds[i].fd, outfds)) + revents |= POLLOUT; + fds[i].revents = revents; + } + } + return rc; +} +#endif + +struct timeval tv_now_global; +uint64_t now_global; + static void run(void) { - struct timeval tv_now; - uint64_t now; struct poll_interest *i; int rv, nfds, remain, idx; int timeout; struct pollfd *fds; - fds=alloca(sizeof(*fds)*total_nfds); - if (!fds) { - fatal("run: couldn't alloca"); - } + fds=safe_malloc(sizeof(*fds)*total_nfds, "run"); Message(M_NOTICE,"%s [%d]: starting\n",version,secnet_pid); do { - if (gettimeofday(&tv_now, NULL)!=0) { + if (gettimeofday(&tv_now_global, NULL)!=0) { fatal_perror("main loop: gettimeofday"); } - now=((uint64_t)tv_now.tv_sec*(uint64_t)1000)+ - ((uint64_t)tv_now.tv_usec/(uint64_t)1000); + now_global=((uint64_t)tv_now_global.tv_sec*(uint64_t)1000)+ + ((uint64_t)tv_now_global.tv_usec/(uint64_t)1000); idx=0; for (i=reg; i; i=i->next) { - i->after(i->state, fds+idx, i->nfds, &tv_now, &now); + int check; + for (check=0; checknfds; check++) { + if(fds[idx+check].revents & POLLNVAL) { + fatal("run: poll (%s#%d) set POLLNVAL", i->desc, check); + } + } + i->after(i->state, fds+idx, i->nfds); idx+=i->nfds; } remain=total_nfds; @@ -286,7 +324,7 @@ static void run(void) timeout=-1; for (i=reg; i; i=i->next) { nfds=remain; - rv=i->before(i->state, fds+idx, &nfds, &timeout, &tv_now, &now); + rv=i->before(i->state, fds+idx, &nfds, &timeout); if (rv!=0) { /* XXX we need to handle this properly: increase the nfds available */ @@ -301,7 +339,11 @@ static void run(void) } do { if (finished) break; +#if USE_SELECT + rv=fakepoll(fds, idx, timeout); +#else rv=poll(fds, idx, timeout); +#endif if (rv<0) { if (errno!=EINTR) { fatal_perror("run: poll"); @@ -309,12 +351,14 @@ static void run(void) } } while (rv<0); } while (!finished); + free(fds); } static void droppriv(void) { FILE *pf=NULL; pid_t p; + int errfds[2]; add_hook(PHASE_SHUTDOWN,system_phase_hook,NULL); @@ -349,15 +393,20 @@ static void droppriv(void) } else if (p==0) { /* Child process - all done, just carry on */ if (pf) fclose(pf); - /* Close stdin, stdout and stderr; we don't need them any more */ - /* XXX we must leave stderr pointing to something useful - - a pipe to a log destination, for example, or just leave - it alone. */ + /* Close stdin and stdout; we don't need them any more. + stderr is redirected to the system/log facility */ + if (pipe(errfds)!=0) { + fatal_perror("can't create pipe for stderr"); + } close(0); close(1); - /* XXX close(2); */ + close(2); + dup2(errfds[1],0); + dup2(errfds[1],1); + dup2(errfds[1],2); secnet_is_daemon=True; setsid(); + log_from_fd(errfds[0],"stderr",system_log); } else { /* Error */ fatal_perror("cannot fork"); @@ -404,8 +453,9 @@ int main(int argc, char **argv) droppriv(); start_signal_handling(); - request_signal_notification(SIGTERM,finish,"SIGTERM"); - if (!background) request_signal_notification(SIGINT,finish,"SIGINT"); + request_signal_notification(SIGTERM,finish,safe_strdup("SIGTERM","run")); + if (!background) request_signal_notification(SIGINT,finish, + safe_strdup("SIGINT","run")); request_signal_notification(SIGHUP,ignore_hup,NULL); enter_phase(PHASE_RUN); run();