1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
50 /* --------------------------------------------------------------------
52 * wintty : a Apache/WinNT support utility for monitoring and
53 * reflecting user feedback from the Apache process via
54 * stdin/stdout, even as running within the service context.
56 * Originally contributed by William Rowe <wrowe@covalent.net>
58 * Note: this implementation is _very_ experimental, and error handling
59 * is far from complete. Using it as a cgi or pipe process allows the
60 * programmer to discover if facilities such as reliable piped logs
61 * are working as expected, or answer operator prompts that would
62 * otherwise be discarded by the service process.
64 * Also note the isservice detection semantics, which far exceed any
65 * mechanism we have discovered thus far.
67 * --------------------------------------------------------------------
70 #define WIN32_LEAN_AND_MEAN
76 "\nwintty: a utility for echoing the stdin stream to a new console window,\n"
77 "\teven when invoked from within a service (such as the Apache server.)\n"
78 "\tAlso reflects the console input back to the stdout stream, allowing\n"
79 "\tthe operator to respond to prompts from the context of a service.\n\n"
80 "Syntax: %s [opts] [-t \"Window Title\"]\n\n"
81 " opts: -c{haracter} or -l{ine} input\n"
82 "\t-q{uiet} or -e{cho} input\n"
83 "\t-u{nprocessed} or -p{rocessed} input\n"
84 "\t-n{owrap} or -w{rap} output lines\n"
85 "\t-f{ormatted} or -r{aw} output lines\n"
86 "\t-v{erbose} error reporting (for debugging)\n"
87 "\t-? for this message\n\n";
91 void printerr(char *fmt, ...)
98 wvsprintf(str, fmt, args);
99 OutputDebugString(str);
102 DWORD WINAPI feedback(LPVOID args);
104 typedef struct feedback_args_t {
109 int main(int argc, char** argv)
111 char str[1024], *contitle;
112 HANDLE hproc, thread;
113 HANDLE hwinsta, hsavewinsta;
114 HANDLE hdesk, hsavedesk;
115 HANDLE conin, conout;
116 HANDLE hstdin, hstdout, hstderr, hdup;
117 feedback_args_t feed;
119 DWORD newinmode = 0, notinmode = 0;
120 DWORD newoutmode = 0, notoutmode = 0;
123 BOOL isservice = FALSE;
124 char *arg0 = argv[0];
128 if (**argv == '/' || **argv == '-') {
129 switch (tolower((*argv)[1])) {
131 notinmode |= ENABLE_LINE_INPUT; break;
133 newinmode |= ENABLE_LINE_INPUT; break;
135 notinmode |= ENABLE_ECHO_INPUT; break;
137 newinmode |= ENABLE_ECHO_INPUT; break;
139 notinmode |= ENABLE_PROCESSED_INPUT; break;
141 newinmode |= ENABLE_PROCESSED_INPUT; break;
143 notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
145 newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
147 notoutmode |= ENABLE_PROCESSED_OUTPUT; break;
149 newoutmode |= ENABLE_PROCESSED_OUTPUT; break;
154 contitle = *(++argv);
158 printf(options, arg0);
161 printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
166 printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
171 hproc = GetCurrentProcess();
172 hsavewinsta = GetProcessWindowStation();
173 if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
174 printerr("GetProcessWindowStation() failed (%d)\n", GetLastError());
176 else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
177 printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n", GetLastError());
179 else if (strnicmp(str, "Service-", 8) == 0) {
180 printerr("WindowStation Name %s is a service\n", str);
185 hstdin = GetStdHandle(STD_INPUT_HANDLE);
186 if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
187 printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n",
190 else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0,
191 isservice, DUPLICATE_SAME_ACCESS)) {
196 printerr("DupHandle(stdin [%x]) failed (%d)\n",
197 hstdin, GetLastError());
200 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
201 if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
202 printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n",
205 else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0,
206 isservice, DUPLICATE_SAME_ACCESS)) {
207 CloseHandle(hstdout);
211 printerr("DupHandle(stdout [%x]) failed (%d)\n",
212 hstdout, GetLastError());
215 hstderr = GetStdHandle(STD_ERROR_HANDLE);
216 if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
217 printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n",
220 else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0,
221 isservice, DUPLICATE_SAME_ACCESS)) {
222 CloseHandle(hstderr);
226 printerr("DupHandle(stderr [%x]) failed (%d)\n",
227 hstderr, GetLastError());
230 /* You can't close the console till all the handles above were
231 * rescued by DuplicateHandle()
234 printerr("FreeConsole() failed (%d)\n", GetLastError());
237 #ifdef WE_EVER_FIGURE_OUT_WHY_THIS_DOESNT_WORK
238 hsavedesk = GetThreadDesktop(GetCurrentThreadId());
239 if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) {
240 printerr("GetThreadDesktop(GetTID()) failed (%d)\n", GetLastError());
242 CloseWindowStation(hwinsta);
243 hwinsta = OpenWindowStation("WinSta0", TRUE, MAXIMUM_ALLOWED);
244 if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
245 printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
247 else if (!SetProcessWindowStation(hwinsta)) {
248 printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
250 hdesk = OpenDesktop("Default", 0, TRUE, MAXIMUM_ALLOWED);
251 if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
252 printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
254 else if (!SetThreadDesktop(hdesk)) {
255 printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
258 PROCESS_INFORMATION pi;
261 char appbuff[MAX_PATH];
262 char *appname = NULL;
263 char *cmdline = GetCommandLine();
265 if (!GetModuleFileName(NULL, appbuff, sizeof(appbuff))) {
269 memset(&si, 0, sizeof(si));
271 si.dwFlags = STARTF_USESHOWWINDOW
272 | STARTF_USESTDHANDLES;
273 si.lpDesktop = "WinSta0\\Default";
274 si.wShowWindow = 1; /* SW_SHOWNORMAL */
275 si.hStdInput = hstdin;
276 si.hStdOutput = hstdout;
277 si.hStdError = hstderr;
279 /* Instantly, upon creating the new process, we will close our
280 * copies of the handles so our parent isn't confused when the
281 * child closes their copy of the handle. Without this action,
282 * we would hold a copy of the handle, and the parent would not
283 * receive their EOF notification.
285 if (CreateProcess(appname, cmdline, NULL, NULL, TRUE,
286 CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
287 NULL, NULL, &si, &pi)) {
288 CloseHandle(si.hStdInput);
289 CloseHandle(si.hStdOutput);
290 CloseHandle(si.hStdError);
291 ResumeThread(pi.hThread);
292 CloseHandle(pi.hThread);
293 WaitForSingleObject(pi.hProcess, INFINITE);
294 GetExitCodeProcess(pi.hProcess, &exitcode);
295 CloseHandle(pi.hProcess);
302 if (!AllocConsole()) {
303 printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
306 if (contitle && !SetConsoleTitle(contitle)) {
307 printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
310 conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
311 FILE_SHARE_READ | FILE_SHARE_WRITE,
312 FALSE, OPEN_EXISTING, 0, NULL);
313 if (!conout || conout == INVALID_HANDLE_VALUE) {
314 printerr("CreateFile(CONOUT$) failed (%d)\n", GetLastError());
316 else if (!GetConsoleMode(conout, &conmode)) {
317 printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
319 else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode)
321 printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n",
322 conmode, GetLastError());
325 conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
326 FILE_SHARE_READ | FILE_SHARE_WRITE,
327 FALSE, OPEN_EXISTING, 0, NULL);
328 if (!conin || conin == INVALID_HANDLE_VALUE) {
329 printerr("CreateFile(CONIN$) failed (%d)\n", GetLastError());
331 else if (!GetConsoleMode(conin, &conmode)) {
332 printerr("GetConsoleMode(CONIN) failed (%d)\n", GetLastError());
334 else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode)
336 printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n",
337 conmode, GetLastError());
342 thread = CreateThread(NULL, 0, feedback, (LPVOID)&feed, 0, &tid);
344 while (ReadFile(hstdin, str, sizeof(str), &len, NULL))
345 if (!len || !WriteFile(conout, str, len, &len, NULL))
348 printerr("[EOF] from stdin (%d)\n", GetLastError());
351 if (!GetConsoleTitle(str, sizeof(str))) {
352 printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
355 strcat(str, " - [Finished]");
356 if (!SetConsoleTitle(str)) {
357 printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
361 WaitForSingleObject(thread, INFINITE);
364 if (!SetProcessWindowStation(hsavewinsta)) {
365 len = GetLastError();
367 if (!SetThreadDesktop(hsavedesk)) {
368 len = GetLastError();
371 CloseWindowStation(hwinsta);
377 DWORD WINAPI feedback(LPVOID arg)
379 feedback_args_t *feed = (feedback_args_t*)arg;
383 while (ReadFile(feed->in, str, sizeof(str), &len, NULL))
384 if (!len || !WriteFile(feed->out, str, len, &len, NULL))
387 printerr("[EOF] from Console (%d)\n", GetLastError());