--- /dev/null
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/* --------------------------------------------------------------------
+ *
+ * wintty : a Apache/WinNT support utility for monitoring and
+ * reflecting user feedback from the Apache process via
+ * stdin/stdout, even as running within the service context.
+ *
+ * Originally contributed by William Rowe <wrowe@covalent.net>
+ *
+ * Note: this implementation is _very_ experimental, and error handling
+ * is far from complete. Using it as a cgi or pipe process allows the
+ * programmer to discover if facilities such as reliable piped logs
+ * are working as expected, or answer operator prompts that would
+ * otherwise be discarded by the service process.
+ *
+ * Also note the isservice detection semantics, which far exceed any
+ * mechanism we have discovered thus far.
+ *
+ * --------------------------------------------------------------------
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+const char *options =
+"Syntax: wintty [opts] [-?]\n\n"
+" opts: -c{haracter} or -l{ine} input\n"
+"\t-q{uiet} or -e{cho} input\n"
+"\topts: -u{nprocessed} or -p{rocessed} input\n"
+"\topts: -n{owrap} or -w{rap} output lines\n"
+"\topts: -f{ormatted} or -r{aw} output lines\n"
+"\topts: -v{erbose} error checking\n"
+"\topts: -? for this message\n\n";
+
+HANDLE herrout;
+BOOL verbose = FALSE;
+
+void printerr(char *fmt, ...)
+{
+ char str[1024];
+ va_list args;
+ DWORD len;
+ if (!verbose)
+ return;
+ va_start(args, fmt);
+ wvsprintf(str, fmt, args);
+ WriteFile(herrout, str, len = strlen(str), &len, NULL);
+}
+
+DWORD WINAPI feedback(LPVOID pipeout);
+
+int main(int argc, char** argv)
+{
+ char str[1024], *contitle;
+ HANDLE hproc, thread;
+ HANDLE hwinsta, hsavewinsta;
+ HANDLE hdesk, hsavedesk;
+ HANDLE conin, conout;
+ HANDLE pipein, pipeout;
+ HANDLE hstdin, hstdout, hstderr;
+ DWORD conmode;
+ DWORD newinmode = 0, notinmode = 0;
+ DWORD newoutmode = 0, notoutmode = 0;
+ DWORD tid;
+ DWORD len;
+ BOOL isservice = FALSE;
+
+ while (--argc) {
+ ++argv;
+ if (**argv == '/' || **argv == '-') {
+ switch (tolower((*argv)[1])) {
+ case 'c':
+ notinmode |= ENABLE_LINE_INPUT; break;
+ case 'l':
+ newinmode |= ENABLE_LINE_INPUT; break;
+ case 'q':
+ notinmode |= ENABLE_ECHO_INPUT; break;
+ case 'e':
+ newinmode |= ENABLE_ECHO_INPUT; break;
+ case 'u':
+ notinmode |= ENABLE_PROCESSED_INPUT; break;
+ case 'p':
+ newinmode |= ENABLE_PROCESSED_INPUT; break;
+ case 'n':
+ notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
+ case 'w':
+ newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
+ case 'r':
+ notoutmode |= ENABLE_PROCESSED_OUTPUT; break;
+ case 'f':
+ newoutmode |= ENABLE_PROCESSED_OUTPUT; break;
+ case 'v':
+ verbose = TRUE;
+ break;
+ case 't':
+ contitle = *(++argv);
+ --argc;
+ break;
+ case '?':
+ printf(options);
+ exit(1);
+ default:
+ printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
+ exit(1);
+ }
+ }
+ else {
+ printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
+ exit(1);
+ }
+ }
+
+ hproc = GetCurrentProcess();
+ herrout = hstderr = GetStdHandle(STD_ERROR_HANDLE);
+ if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!DuplicateHandle(hproc, hstderr,
+ hproc, &herrout, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ printerr("DupHandle(stderr) failed (%d)\n", GetLastError());
+ }
+
+ hstdin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!DuplicateHandle(hproc, hstdin,
+ hproc, &pipein, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ printerr("DupHandle(stdin) failed (%d)\n", GetLastError());
+ }
+
+ hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!DuplicateHandle(hproc, hstdout,
+ hproc, &pipeout, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ printerr("DupHandle(stdout) failed (%d)\n", GetLastError());
+ }
+
+ hsavewinsta = GetProcessWindowStation();
+ if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
+ printerr("GetProcWinSta() failed (%d)\n", GetLastError());
+ }
+ else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
+ printerr("GetUserObjectInfo(GetProcWinSta) failed (%d)\n", GetLastError());
+ CloseHandle(hsavewinsta);
+ }
+ else if (strnicmp(str, "Service-", 8) == 0) {
+ isservice = TRUE;
+ }
+ else
+ CloseHandle(hsavewinsta);
+ SetLastError(0);
+
+ if (!FreeConsole())
+ printerr("DupHandle(stdout) failed (%d)\n", GetLastError());
+
+ if (isservice) {
+ hwinsta = OpenWindowStation("WinSta0", TRUE,
+ WINSTA_ACCESSCLIPBOARD
+ | WINSTA_ACCESSGLOBALATOMS
+ | WINSTA_ENUMDESKTOPS
+ | WINSTA_ENUMERATE
+ | WINSTA_READATTRIBUTES
+ | WINSTA_READSCREEN
+ | WINSTA_WRITEATTRIBUTES);
+ if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
+ printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
+ }
+ else if (!SetProcessWindowStation(hwinsta)) {
+ printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
+ }
+ hsavedesk = GetThreadDesktop(GetCurrentThreadId());
+ hdesk = OpenDesktop("Default", 0, TRUE,
+ DESKTOP_READOBJECTS
+ | DESKTOP_CREATEWINDOW
+ | DESKTOP_CREATEMENU
+ | DESKTOP_HOOKCONTROL
+ | DESKTOP_JOURNALRECORD
+ | DESKTOP_JOURNALPLAYBACK
+ | DESKTOP_ENUMERATE
+ | DESKTOP_WRITEOBJECTS);
+ if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
+ printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
+ }
+ else if (!SetThreadDesktop(hdesk)) {
+ printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
+ }
+ }
+
+ if (!AllocConsole()) {
+ printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
+ }
+
+ if (contitle && !SetConsoleTitle(contitle)) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+
+ conout = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!conout || conout == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!GetConsoleMode(conout, &conmode)) {
+ printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
+ }
+ else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode) & ~notoutmode))) {
+ printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n", conmode, GetLastError());
+ }
+
+ conin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!conin || conin == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n", GetLastError());
+ }
+ else if (!GetConsoleMode(conin, &conmode)) {
+ printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
+ }
+ else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode) & ~notinmode))) {
+ printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n", conmode, GetLastError());
+ }
+
+ thread = CreateThread(NULL, 0, feedback, (LPVOID)pipeout, 0, &tid);
+
+ while (ReadFile(pipein, str, sizeof(str), &len, NULL))
+ if (!len || !WriteFile(conout, str, len, &len, NULL))
+ break;
+
+ printerr("[EOF] from stdin (%d)\n", GetLastError());
+
+ CloseHandle(pipeout);
+ if (!GetConsoleTitle(str, sizeof(str))) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+ else {
+ strcat(str, " - [Finished]");
+ if (!SetConsoleTitle(str)) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+ }
+
+ WaitForSingleObject(thread, INFINITE);
+ FreeConsole();
+ CloseHandle(herrout);
+ if (isservice) {
+ if (!SetProcessWindowStation(hsavewinsta)) {
+ len = GetLastError();
+ }
+ if (!SetThreadDesktop(hsavedesk)) {
+ len = GetLastError();
+ }
+ CloseDesktop(hdesk);
+ CloseWindowStation(hwinsta);
+ }
+ return 0;
+}
+
+
+DWORD WINAPI feedback(LPVOID arg)
+{
+ HANDLE conin;
+ HANDLE pipeout = (HANDLE)arg;
+ char *str[1024];
+ DWORD len;
+
+ conin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!conin) {
+ len = GetLastError();
+ }
+
+ while (ReadFile(conin, str, sizeof(str), &len, NULL))
+ if (!len || !WriteFile(pipeout, str, len, &len, NULL))
+ break;
+
+ printerr("[EOF] from Console (%d)\n", GetLastError());
+
+ return 0;
+}
--- /dev/null
+# Microsoft Developer Studio Project File - Name="wintty" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=wintty - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak" CFG="wintty - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "wintty - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "wintty - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/wintty" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /machine:I386
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /machine:I386
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/wintty" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /incremental:no /map /debug /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "wintty - Win32 Release"
+# Name "wintty - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\wintty.c
+# End Source File
+# End Target
+# End Project