bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / support / win32 / wintty.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* --------------------------------------------------------------------
18  *
19  * wintty : a Apache/WinNT support utility for monitoring and 
20  *          reflecting user feedback from the Apache process via
21  *          stdin/stdout, even as running within the service context.
22  *
23  * Originally contributed by William Rowe <wrowe covalent.net>
24  *
25  * Note: this implementation is _very_ experimental, and error handling
26  * is far from complete.  Using it as a cgi or pipe process allows the
27  * programmer to discover if facilities such as reliable piped logs
28  * are working as expected, or answer operator prompts that would
29  * otherwise be discarded by the service process.
30  *
31  * Also note the isservice detection semantics, which far exceed any
32  * mechanism we have discovered thus far.
33  * 
34  * --------------------------------------------------------------------
35  */
36
37 #define WIN32_LEAN_AND_MEAN
38
39 #if defined(_MSC_VER) && _MSC_VER >= 1400
40 #define _CRT_SECURE_NO_DEPRECATE
41 #pragma warning(disable: 4996)
42 #endif
43
44 #include <windows.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47
48 const char *options = 
49 "\nwintty: a utility for echoing the stdin stream to a new console window,\n"
50 "\teven when invoked from within a service (such as the Apache server.)\n"
51 "\tAlso reflects the console input back to the stdout stream, allowing\n"
52 "\tthe operator to respond to prompts from the context of a service.\n\n"
53 "Syntax: %s [opts] [-t \"Window Title\"]\n\n"
54 "  opts: -c{haracter}   or -l{ine} input\n"
55 "\t-q{uiet}       or -e{cho} input\n"
56 "\t-u{nprocessed} or -p{rocessed} input\n"
57 "\t-n{owrap}      or -w{rap} output lines\n"
58 "\t-f{ormatted}   or -r{aw} output lines\n"
59 "\t-O{output} [number of seconds]\n"
60 "\t-v{erbose} error reporting (for debugging)\n"
61 "\t-? for this message\n\n";
62
63 BOOL verbose = FALSE;
64
65 void printerr(char *fmt, ...) 
66 {
67     char str[1024];
68     va_list args;
69     if (!verbose)
70         return;
71     va_start(args, fmt);
72     wvsprintf(str, fmt, args);
73     OutputDebugString(str);
74 }
75
76 DWORD WINAPI feedback(LPVOID args);
77
78 typedef struct feedback_args_t {
79     HANDLE in;
80     HANDLE out;
81 } feedback_args_t;
82
83 int main(int argc, char** argv)
84 {
85     char str[1024], *contitle = NULL;
86     HANDLE hproc, thread;
87     HANDLE hwinsta = NULL, hsavewinsta;
88     HANDLE hdesk = NULL, hsavedesk = NULL;
89     HANDLE conin, conout;
90     HANDLE hstdin, hstdout, hstderr, hdup;
91     feedback_args_t feed;
92     DWORD conmode;
93     DWORD newinmode = 0, notinmode = 0;
94     DWORD newoutmode = 0, notoutmode = 0;
95     DWORD tid;
96     DWORD len;
97     DWORD timeout = INFINITE;
98     BOOL isservice = FALSE;
99     char *arg0 = argv[0];
100
101     while (--argc) {
102         ++argv;
103         if (**argv == '/' || **argv == '-') {
104             switch (tolower((*argv)[1])) {
105                 case 'c':
106                     notinmode |= ENABLE_LINE_INPUT;          break;
107                 case 'l':
108                     newinmode |= ENABLE_LINE_INPUT;          break;
109                 case 'q':
110                     notinmode |= ENABLE_ECHO_INPUT;          break;
111                 case 'e':
112                     newinmode |= ENABLE_ECHO_INPUT;          break;
113                 case 'u':
114                     notinmode |= ENABLE_PROCESSED_INPUT;     break;
115                 case 'p':
116                     newinmode |= ENABLE_PROCESSED_INPUT;     break;
117                 case 'n':
118                     notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
119                 case 'w':
120                     newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
121                 case 'r':
122                     notoutmode |= ENABLE_PROCESSED_OUTPUT;   break;
123                 case 'f':
124                     newoutmode |= ENABLE_PROCESSED_OUTPUT;   break;
125                 case 'o':
126                     if (*(argv + 1) && *(argv + 1)[0] != '-') {
127                         *(++argv);
128                         timeout = atoi(*argv) / 1000;
129                         --argc;
130                     }
131                     else {
132                         timeout = 0;
133                     }   
134                     break;
135                 case 'v':
136                     verbose = TRUE;
137                     break;
138                 case 't':
139                     contitle = *(++argv);
140                     --argc;
141                     break;
142                 case '?':
143                     printf(options, arg0);
144                     exit(1);
145                 default:
146                     printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
147                     exit(1);
148             }
149         }
150         else {
151             printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
152             exit(1);
153         }
154     }
155
156     hproc = GetCurrentProcess();
157     hsavewinsta = GetProcessWindowStation();
158     if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
159         printerr("GetProcessWindowStation() failed (%d)\n", GetLastError());
160     }
161     else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
162         printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n", GetLastError());
163     }
164     else if (strnicmp(str, "Service-", 8) == 0) {
165         printerr("WindowStation Name %s is a service\n", str);
166         isservice = TRUE;
167     }
168     SetLastError(0);
169
170     hstdin = GetStdHandle(STD_INPUT_HANDLE);
171     if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
172         printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n", 
173                  GetLastError());
174     }
175     else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0, 
176                              isservice, DUPLICATE_SAME_ACCESS)) {
177         CloseHandle(hstdin);
178         hstdin = hdup;
179     }
180     else {
181         printerr("DupHandle(stdin [%x]) failed (%d)\n", 
182                  hstdin, GetLastError());
183     }
184
185     hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
186     if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
187         printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n", 
188                  GetLastError());
189     }
190     else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0, 
191                              isservice, DUPLICATE_SAME_ACCESS)) {
192         CloseHandle(hstdout);
193         hstdout = hdup;
194     }
195     else {
196         printerr("DupHandle(stdout [%x]) failed (%d)\n", 
197                  hstdout, GetLastError());
198     }
199
200     hstderr = GetStdHandle(STD_ERROR_HANDLE);
201     if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
202         printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n", 
203                  GetLastError());
204     }
205     else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0, 
206                              isservice, DUPLICATE_SAME_ACCESS)) {
207         CloseHandle(hstderr);
208         hstderr = hdup;
209     }
210     else {
211         printerr("DupHandle(stderr [%x]) failed (%d)\n", 
212                  hstderr, GetLastError());
213     }
214
215     /* You can't close the console till all the handles above were
216      * rescued by DuplicateHandle()
217      */
218     if (!FreeConsole())
219         printerr("FreeConsole() failed (%d)\n", GetLastError());
220         
221     if (isservice) {
222 #ifdef WE_EVER_FIGURE_OUT_WHY_THIS_DOESNT_WORK
223         hsavedesk = GetThreadDesktop(GetCurrentThreadId());
224         if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) {
225             printerr("GetThreadDesktop(GetTID()) failed (%d)\n", GetLastError());
226         }
227         CloseWindowStation(hwinsta);
228         hwinsta = OpenWindowStation("WinSta0", TRUE, MAXIMUM_ALLOWED);
229         if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
230             printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
231         }
232         else if (!SetProcessWindowStation(hwinsta)) {
233             printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
234         }
235         hdesk = OpenDesktop("Default", 0, TRUE, MAXIMUM_ALLOWED);
236         if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
237             printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
238         } 
239         else if (!SetThreadDesktop(hdesk)) {
240             printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
241         }
242 #else
243         PROCESS_INFORMATION pi;
244         STARTUPINFO si;
245         DWORD exitcode = 1;
246         char appbuff[MAX_PATH];
247         char *appname = NULL;
248         char *cmdline = GetCommandLine();
249         
250         if (!GetModuleFileName(NULL, appbuff, sizeof(appbuff))) {
251             appname = appbuff;
252         }
253         
254         memset(&si, 0, sizeof(si));
255         si.cb = sizeof(si);
256         si.dwFlags     = STARTF_USESHOWWINDOW
257                        | STARTF_USESTDHANDLES;
258         si.lpDesktop   = "WinSta0\\Default";
259         si.wShowWindow = 1;  /* SW_SHOWNORMAL */
260         si.hStdInput   = hstdin;
261         si.hStdOutput  = hstdout;
262         si.hStdError   = hstderr;
263
264         /* Instantly, upon creating the new process, we will close our
265          * copies of the handles so our parent isn't confused when the
266          * child closes their copy of the handle.  Without this action,
267          * we would hold a copy of the handle, and the parent would not
268          * receive their EOF notification.
269          */
270         if (CreateProcess(appname, cmdline, NULL, NULL, TRUE,
271                           CREATE_SUSPENDED | CREATE_NEW_CONSOLE, 
272                           NULL, NULL, &si, &pi)) {
273             CloseHandle(si.hStdInput);
274             CloseHandle(si.hStdOutput);
275             CloseHandle(si.hStdError);
276             ResumeThread(pi.hThread);
277             CloseHandle(pi.hThread);
278             WaitForSingleObject(pi.hProcess, INFINITE);
279             GetExitCodeProcess(pi.hProcess, &exitcode);
280             CloseHandle(pi.hProcess);
281             return exitcode;
282         }
283         return 1;
284 #endif
285     }
286
287     if (!AllocConsole()) {
288         printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
289     }
290
291     if (contitle && !SetConsoleTitle(contitle)) {
292         printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
293     }
294
295     conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, 
296                         FILE_SHARE_READ | FILE_SHARE_WRITE, 
297                         FALSE, OPEN_EXISTING, 0, NULL);
298     if (!conout || conout == INVALID_HANDLE_VALUE) {
299         printerr("CreateFile(CONOUT$) failed (%d)\n", GetLastError());
300     }
301     else if (!GetConsoleMode(conout, &conmode)) {
302         printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
303     }
304     else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode)
305                                                          & ~notoutmode))) {
306         printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n", 
307                  conmode, GetLastError());
308     }
309
310     conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, 
311                        FILE_SHARE_READ | FILE_SHARE_WRITE, 
312                        FALSE, OPEN_EXISTING, 0, NULL);
313     if (!conin || conin == INVALID_HANDLE_VALUE) {
314         printerr("CreateFile(CONIN$) failed (%d)\n", GetLastError());
315     }
316     else if (!GetConsoleMode(conin, &conmode)) {
317         printerr("GetConsoleMode(CONIN) failed (%d)\n", GetLastError());
318     }
319     else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode) 
320                                                         & ~notinmode))) {
321         printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n", 
322                  conmode, GetLastError());
323     }
324
325     feed.in = conin;
326     feed.out = hstdout;
327     thread = CreateThread(NULL, 0, feedback, (LPVOID)&feed, 0, &tid);
328
329     while (ReadFile(hstdin, str, sizeof(str), &len, NULL))
330         if (!len || !WriteFile(conout, str, len, &len, NULL))
331            break;
332
333     printerr("[EOF] from stdin (%d)\n", GetLastError());
334
335     CloseHandle(stdout);
336     if (!GetConsoleTitle(str, sizeof(str))) {
337         printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
338     }
339     else {
340         strcat(str, " - [Finished]");
341         if (!SetConsoleTitle(str)) {
342             printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
343         }
344     }
345
346     WaitForSingleObject(thread, timeout);
347     FreeConsole();
348     if (isservice) {
349         if (!SetProcessWindowStation(hsavewinsta)) {
350             len = GetLastError();
351         }
352         if (!SetThreadDesktop(hsavedesk)) {
353             len = GetLastError();
354         }
355         CloseDesktop(hdesk);
356         CloseWindowStation(hwinsta);
357     }
358     return 0;
359 }
360
361
362 DWORD WINAPI feedback(LPVOID arg)
363 {
364     feedback_args_t *feed = (feedback_args_t*)arg;
365     char *str[1024];
366     DWORD len;
367
368     while (ReadFile(feed->in, str, sizeof(str), &len, NULL))
369         if (!len || !WriteFile(feed->out, str, len, &len, NULL))
370             break;
371
372     printerr("[EOF] from Console (%d)\n", GetLastError());
373
374     return 0;
375 }