diff -Naur inetutils-1.9.2-orig/src/inetd.c inetutils-1.9.2/src/inetd.c --- inetutils-1.9.2-orig/src/inetd.c 2013-12-23 14:57:54.000000000 +0300 +++ inetutils-1.9.2/src/inetd.c 2014-12-12 11:55:11.402400000 +0300 @@ -138,6 +138,13 @@ #include "version-etc.h" #include "unused-parameter.h" +#ifdef __CYGWIN__ +#include +#include +#include +#endif /* __CYGWIN__ */ + + #ifndef EAI_ADDRFAMILY # define EAI_ADDRFAMILY 1 #endif @@ -151,7 +158,14 @@ #endif #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) +enum { + NO_DAEMON = 0, + UNIX_DAEMON +}; + bool debug = false; +static int daemonize = UNIX_DAEMON; + int nsock, maxsock; fd_set allsock; int options; @@ -196,6 +210,13 @@ {"resolve", OPT_RESOLVE, NULL, 0, "resolve IP addresses when setting environment variables " "(see --environment)", GRP+1}, +#ifdef __CYGWIN__ + {0,0,0,0,"Cygwin-specific options:",GRP+2}, + {"no-daemonize", 'D', NULL, 0, + "Do not run as a daemon", GRP+2}, + {"traditional-daemon", 'T', NULL, 0, + "This option is present for backwards compatibility.", GRP+2}, +#endif /* __CYGWIN__ */ #undef GRP {NULL, 0, NULL, 0, NULL, 0} }; @@ -237,6 +258,16 @@ resolve_option = true; break; +#ifdef __CYGWIN__ + case 'D': /* don't become a daemon */ + daemonize = NO_DAEMON; + break; + + case 'T': /* act like a normal unix daemon */ + daemonize = UNIX_DAEMON; + break; +#endif /* __CYGWIN__ */ + default: return ARGP_ERR_UNKNOWN; } @@ -412,6 +443,44 @@ #endif } +#ifdef __CYGWIN__ +void +hide_console () +{ + HMODULE lib; + HWND WINAPI (*GetConsoleWindow) (void) = NULL; + HWND console = NULL; + + AllocConsole (); + if (lib = LoadLibrary ("kernel32.dll")) + GetConsoleWindow = (HWND WINAPI (*) (void)) + GetProcAddress (lib, "GetConsoleWindow"); + + if (GetConsoleWindow) + /* If GetConsoleWindow exists (W2K and newer), use it. */ + console = GetConsoleWindow (); + if (!console) + { + /* Get console window handle as described in KB article Q124103 */ + char title[32]; + snprintf (title, 32, "inetd.%d", getpid ()); + SetConsoleTitle (title); + Sleep (40); + console = FindWindow (NULL, title); + if (console) + { + char ctitle[256]; + if (!GetWindowText (console, ctitle, 256) || strcmp (title, ctitle)) + console = NULL; + } + } + if (console) + ShowWindow (console, SW_HIDE); +} +#endif /* __CYGWIN__ */ + + + void run_service (int ctrl, struct servtab *sep) { @@ -431,6 +500,10 @@ close (ctrl); dup2 (0, 1); dup2 (0, 2); +#ifdef __CYGWIN__ + if (strcmp (sep->se_user, "root")) + { +#endif pwd = getpwnam (sep->se_user); if (pwd == NULL) { @@ -452,14 +525,21 @@ _exit (EXIT_FAILURE); } } +#ifdef __CYGWIN__ + } + else + { + pwd = getpwuid (getuid ()); + } +#endif if (pwd->pw_uid) { if (grp && grp->gr_gid) { if (setgid (grp->gr_gid) < 0) { - syslog (LOG_ERR, "%s: can't set gid %d: %m", - sep->se_service, grp->gr_gid); + syslog (LOG_ERR, "%s: can't set gid %d uid(%d): %m", + sep->se_service, pwd->pw_gid, pwd->pw_uid); _exit (EXIT_FAILURE); } } @@ -1278,6 +1358,10 @@ } while ((sep = getconfigent (fconfig, file, &line))) { +#ifdef __CYGWIN__ + if (strcmp (sep->se_user, "root")) + { +#endif pwd = getpwnam (sep->se_user); if (pwd == NULL) { @@ -1285,6 +1369,9 @@ sep->se_service, sep->se_proto, sep->se_user); continue; } +#ifdef __CYGWIN__ + } +#endif if (sep->se_group && *sep->se_group) { grp = getgrnam (sep->se_group); @@ -1497,10 +1584,48 @@ } else snprintf (buf, sizeof buf, "-%s", a); - strncpy (cp, buf, LastArg - cp); - cp += strlen (cp); - while (cp < LastArg) - *cp++ = ' '; + + /* the non-portable code in the #else block relies on + the system allocating all of the strings in argv[] + contiguously. On cygwin this is not necessarily so, + and to assume otherwise will lead to segfaults. + The downside here is we get supposed ps entries for + internal services like: + '-echo' instead of '-echo [remoteIP]' (okay?) + '-char' instead of '-chargen [remoteIP]' (awful) + '-disc' instead of '-discard [remoteIP]' (awful) + because the original argv[0] might be 'inetd' unless + it was specifically invoked with a full path. However, + this is mostly moot: + (1) cygwin's ps uses its own internal version of the + exe name (or GetModuleName) and then calls + cygwin_conv_xxx() for display. + (2) procps DOES use the modified argv[0] value + */ + { +#ifdef __CYGWIN__ + char* LastNullChar = cp + strlen(cp); + char** scan; +#else + char* LastNullChar = LastArg; +#endif + + strncpy (cp, buf, LastNullChar - cp); + cp += strlen (cp); + while (cp < LastNullChar) + *cp++ = ' '; + +#ifdef __CYGWIN__ + /* individually blank out the rest of the args */ + for (scan = Argv + 1; *scan != NULL; scan++) + { + char* nullChar = *scan + strlen(*scan); + cp = *scan; + while (cp < nullChar) + *cp++ = ' '; + } +#endif + } } /* @@ -1939,6 +2064,16 @@ envp++; LastArg = envp[-1] + strlen (envp[-1]); +#ifdef __CYGWIN__ + /* on cygwin, open the log early -- because even + help and cmdline processing messages go directly + to syslog. This is because inetd is often run + under the SYSTEM account (which is not quite like + the *nix 'root') + */ + openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); +#endif + /* Parse command line */ iu_argp_init ("inetd", program_authors); argp_parse (&argp, argc, argv, 0, &index, NULL); @@ -1962,7 +2097,7 @@ config_files[1] = newstr (PATH_INETDDIR); } - if (!debug) + if ((debug == 0) && daemonize) { if (daemon (0, 0) < 0) { @@ -1971,6 +2106,12 @@ exit (EXIT_FAILURE); }; } +#ifndef __CYGWIN__ + exception_list except_list; + cygwin_internal (CW_INIT_EXCEPTIONS, &except_list); + hide_console (); +#endif /* __CYGWIN__ */ + openlog ("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); @@ -1995,6 +2136,7 @@ signal_set_handler (SIGCHLD, reapchild); signal_set_handler (SIGPIPE, SIG_IGN); +#ifndef __CYGWIN__ { /* space for daemons to overwrite environment for ps */ #define DUMMYSIZE 100 @@ -2004,6 +2146,7 @@ dummy[DUMMYSIZE - 1] = '\0'; setenv ("inetd_dummy", dummy, 1); } +#endif /* __CYGWIN__ */ for (;;) {