From 5c5b5e8a0b4c219932436f3cb110c08af6ef5b07 Mon Sep 17 00:00:00 2001 From: hpa Date: Thu, 29 Nov 2001 20:53:59 +0000 Subject: [PATCH] More Cygwin compatibility work -- now actually WORKS! Always leave fds 0-2 defined; point them to /dev/null rather than just closing them... --- configure.in | 1 + tftpd/tftpd.c | 76 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/configure.in b/configure.in index fefa2bc..d55daed 100644 --- a/configure.in +++ b/configure.in @@ -93,6 +93,7 @@ AC_SEARCH_LIBS(gethostbyname, [nsl resolv], , [AC_MSG_ERROR(gethostbyname not fo AC_SEARCH_LIBS(inet_aton, [nsl resolv], , [AC_MSG_ERROR(inet_aton not found)]) AC_SEARCH_LIBS(herror, [nsl resolv], , [AC_MSG_ERROR(herror not found)]) +AC_CHECK_FUNCS(dup2) AC_CHECK_FUNCS(fcntl) AC_CHECK_FUNCS(setsid) AC_CHECK_FUNCS(recvmsg) diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c index 16ce456..9d1f30f 100644 --- a/tftpd/tftpd.c +++ b/tftpd/tftpd.c @@ -170,6 +170,25 @@ read_remap_rules(const char *file) } #endif +static inline void +set_socket_nonblock(int fd, int flag) +{ + int err; + int flags; +#if defined(HAVE_FCNTL) && defined(O_NONBLOCK) + /* Posixly correct */ + err = ((flags = fcntl(fd, F_GETFL, 0)) < 0) || + (fcntl(fd, F_SETFL, flag ? flags|O_NONBLOCK : flags&~O_NONBLOCK) < 0); +#else + flags = flag ? 1 : 0; + err = (ioctl(fd, FIONBIO, &flags) < 0); +#endif + if ( err ) { + syslog(LOG_ERR, "Cannot set nonblock flag on socket: %m"); + exit(EX_OSERR); + } +} + int main(int argc, char **argv) { @@ -296,25 +315,10 @@ main(int argc, char **argv) if ( spec_umask || !unixperms ) umask(my_umask); -#if defined(HAVE_FCNTL) && defined(O_NONBLOCK) - /* Posixly correct */ - { - int flags; - if ( (flags = fcntl(fd, F_GETFL, 0) < 0) || - (fcntl(fd, F_SETFL, flags|O_NONBLOCK)) ) { - syslog(LOG_ERR, "Cannot set nonblocking socket: %m"); - exit(EX_OSERR); - } - } -#else - /* Old BSD version */ - { - int on = 1; - if ( ioctl(fd, FIONBIO, &on) < 0 ) { - syslog(LOG_ERR, "Cannot set nonblocking socket: %m"); - exit(EX_OSERR); - } - } + /* Note: on Cygwin, select() on a nonblocking socket becomes + a nonblocking select. */ +#ifndef __CYGWIN__ + set_socket_nonblock(fd, 1); #endif #ifdef WITH_REGEX @@ -376,15 +380,32 @@ main(int argc, char **argv) /* Daemonize this process */ { pid_t f = fork(); + int nfd; if ( f > 0 ) exit(0); if ( f < 0 ) { syslog(LOG_ERR, "cannot fork: %m"); exit(EX_OSERR); } - close(0); close(1); close(2); + nfd = open("/dev/null", O_RDWR); + if ( nfd >= 0 ) { +#ifdef HAVE_DUP2 + dup2(nfd, 0); + dup2(nfd, 1); + dup2(nfd, 2); +#else + close(0); dup(nfd); + close(1); dup(nfd); + close(2); dup(nfd); +#endif + close(nfd); + } else { + close(0); close(1); close(2); + } #ifdef HAVE_SETSID +#ifndef __CYGWIN__ /* Kills the process on Cygwin? */ setsid(); +#endif #endif } } else { @@ -429,6 +450,12 @@ main(int argc, char **argv) tv_waittime.tv_sec = waittime; tv_waittime.tv_usec = 0; +#ifdef __CYGWIN__ + /* On Cygwin, select() on a nonblocking socket returns immediately, + with a rv of 0! */ + set_socket_nonblock(fd, 0); +#endif + /* Never time out if we're in standalone mode */ rv = select(fd+1, &readset, NULL, NULL, standalone ? NULL : &tv_waittime); if ( rv == -1 && errno == EINTR ) @@ -439,6 +466,10 @@ main(int argc, char **argv) } else if ( rv == 0 ) { exit(0); /* Timeout, return to inetd */ } + +#ifdef __CYGWIN__ + set_socket_nonblock(fd, 1); +#endif fromlen = sizeof (from); n = myrecvfrom(fd, buf, sizeof (buf), 0, @@ -454,7 +485,6 @@ main(int argc, char **argv) } } - if ( standalone && myaddr.sin_addr.s_addr == INADDR_ANY ) { /* myrecvfrom() didn't capture the source address; but we might have bound to a specific address, if so we should use it */ @@ -534,6 +564,10 @@ main(int argc, char **argv) exit(EX_OSERR); } +#ifdef __CYGWIN__ + chdir("/"); /* Cygwin chroot() bug workaround */ +#endif + #ifdef HAVE_SETREGID setrv = setregid(pw->pw_gid, pw->pw_gid); #else