wintty.c revision ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dc
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd/* Copyright 2001-2004 Apache Software Foundation
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Licensed under the Apache License, Version 2.0 (the "License");
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * you may not use this file except in compliance with the License.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe/* --------------------------------------------------------------------
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * wintty : a Apache/WinNT support utility for monitoring and
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * reflecting user feedback from the Apache process via
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * stdin/stdout, even as running within the service context.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Originally contributed by William Rowe <wrowe covalent.net>
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * Note: this implementation is _very_ experimental, and error handling
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * is far from complete. Using it as a cgi or pipe process allows the
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * programmer to discover if facilities such as reliable piped logs
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * are working as expected, or answer operator prompts that would
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * otherwise be discarded by the service process.
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * Also note the isservice detection semantics, which far exceed any
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * mechanism we have discovered thus far.
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe * --------------------------------------------------------------------
d15674e194392bfaedba1fe2fccc9297e4e20da6wroweconst char *options =
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\nwintty: a utility for echoing the stdin stream to a new console window,\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\teven when invoked from within a service (such as the Apache server.)\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\tAlso reflects the console input back to the stdout stream, allowing\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\tthe operator to respond to prompts from the context of a service.\n\n"
d7e95cd18c2c0109efb3b6f0f90cb0b344e3903cwrowe"Syntax: %s [opts] [-t \"Window Title\"]\n\n"
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe" opts: -c{haracter} or -l{ine} input\n"
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe"\t-q{uiet} or -e{cho} input\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\t-u{nprocessed} or -p{rocessed} input\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\t-n{owrap} or -w{rap} output lines\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\t-f{ormatted} or -r{aw} output lines\n"
89f6ddf394f0dad4c32fa6870cd9e8309c0ad8f1rbb"\t-O{output} [number of seconds]\n"
d7e95cd18c2c0109efb3b6f0f90cb0b344e3903cwrowe"\t-v{erbose} error reporting (for debugging)\n"
44f635c1fcd33ff43339e01dcac5812c6a635ecewrowe"\t-? for this message\n\n";
9bc83c8de0be46245af97e1196cf12b7e70761f3wrowetypedef struct feedback_args_t {
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe while (--argc) {
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("GetProcessWindowStation() failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("WindowStation Name %s is a service\n", str);
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n",
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0,
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n",
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0,
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n",
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0,
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe /* You can't close the console till all the handles above were
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe * rescued by DuplicateHandle()
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("FreeConsole() failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) {
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("GetThreadDesktop(GetTID()) failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe hwinsta = OpenWindowStation("WinSta0", TRUE, MAXIMUM_ALLOWED);
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe hdesk = OpenDesktop("Default", 0, TRUE, MAXIMUM_ALLOWED);
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe if (!GetModuleFileName(NULL, appbuff, sizeof(appbuff))) {
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe /* Instantly, upon creating the new process, we will close our
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe * copies of the handles so our parent isn't confused when the
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe * child closes their copy of the handle. Without this action,
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe * we would hold a copy of the handle, and the parent would not
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe * receive their EOF notification.
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
da8ed3ffd1b4b8fe981298ca0c58d6be952783c8wrowe conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("CreateFile(CONOUT$) failed (%d)\n", GetLastError());
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode)
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n",
da8ed3ffd1b4b8fe981298ca0c58d6be952783c8wrowe conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe printerr("CreateFile(CONIN$) failed (%d)\n", GetLastError());
da8ed3ffd1b4b8fe981298ca0c58d6be952783c8wrowe printerr("GetConsoleMode(CONIN) failed (%d)\n", GetLastError());
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode)
9bc83c8de0be46245af97e1196cf12b7e70761f3wrowe thread = CreateThread(NULL, 0, feedback, (LPVOID)&feed, 0, &tid);
42b4b9ed820867a98b709eb80791e3b4a2291960wrowe while (ReadFile(hstdin, str, sizeof(str), &len, NULL))
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
9bc83c8de0be46245af97e1196cf12b7e70761f3wrowe while (ReadFile(feed->in, str, sizeof(str), &len, NULL))
9bc83c8de0be46245af97e1196cf12b7e70761f3wrowe if (!len || !WriteFile(feed->out, str, len, &len, NULL))
d15674e194392bfaedba1fe2fccc9297e4e20da6wrowe printerr("[EOF] from Console (%d)\n", GetLastError());