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