~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to support/win32/wintty.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <windows.h>
 
39
#include <stdlib.h>
 
40
#include <stdio.h>
 
41
 
 
42
#if defined(_MSC_VER) && _MSC_VER >= 1400
 
43
#define _CRT_SECURE_NO_DEPRECATE
 
44
#pragma warning(disable: 4996)
 
45
#endif
 
46
 
 
47
const char *options =
 
48
"\nwintty: a utility for echoing the stdin stream to a new console window,\n"
 
49
"\teven when invoked from within a service (such as the Apache server.)\n"
 
50
"\tAlso reflects the console input back to the stdout stream, allowing\n"
 
51
"\tthe operator to respond to prompts from the context of a service.\n\n"
 
52
"Syntax: %s [opts] [-t \"Window Title\"]\n\n"
 
53
"  opts: -c{haracter}   or -l{ine} input\n"
 
54
"\t-q{uiet}       or -e{cho} input\n"
 
55
"\t-u{nprocessed} or -p{rocessed} input\n"
 
56
"\t-n{owrap}      or -w{rap} output lines\n"
 
57
"\t-f{ormatted}   or -r{aw} output lines\n"
 
58
"\t-O{output} [number of seconds]\n"
 
59
"\t-v{erbose} error reporting (for debugging)\n"
 
60
"\t-? for this message\n\n";
 
61
 
 
62
BOOL verbose = FALSE;
 
63
 
 
64
void printerr(char *fmt, ...)
 
65
{
 
66
    char str[1024];
 
67
    va_list args;
 
68
    if (!verbose)
 
69
        return;
 
70
    va_start(args, fmt);
 
71
    wvsprintf(str, fmt, args);
 
72
    OutputDebugString(str);
 
73
}
 
74
 
 
75
DWORD WINAPI feedback(LPVOID args);
 
76
 
 
77
typedef struct feedback_args_t {
 
78
    HANDLE in;
 
79
    HANDLE out;
 
80
} feedback_args_t;
 
81
 
 
82
int main(int argc, char** argv)
 
83
{
 
84
    char str[1024], *contitle = NULL;
 
85
    HANDLE hproc, thread;
 
86
    HANDLE hwinsta = NULL, hsavewinsta;
 
87
    HANDLE hdesk = NULL, hsavedesk = NULL;
 
88
    HANDLE conin, conout;
 
89
    HANDLE hstdin, hstdout, hstderr, hdup;
 
90
    feedback_args_t feed;
 
91
    DWORD conmode;
 
92
    DWORD newinmode = 0, notinmode = 0;
 
93
    DWORD newoutmode = 0, notoutmode = 0;
 
94
    DWORD tid;
 
95
    DWORD len;
 
96
    DWORD timeout = INFINITE;
 
97
    BOOL isservice = FALSE;
 
98
    char *arg0 = argv[0];
 
99
 
 
100
    while (--argc) {
 
101
        ++argv;
 
102
        if (**argv == '/' || **argv == '-') {
 
103
            switch (tolower((*argv)[1])) {
 
104
                case 'c':
 
105
                    notinmode |= ENABLE_LINE_INPUT;          break;
 
106
                case 'l':
 
107
                    newinmode |= ENABLE_LINE_INPUT;          break;
 
108
                case 'q':
 
109
                    notinmode |= ENABLE_ECHO_INPUT;          break;
 
110
                case 'e':
 
111
                    newinmode |= ENABLE_ECHO_INPUT;          break;
 
112
                case 'u':
 
113
                    notinmode |= ENABLE_PROCESSED_INPUT;     break;
 
114
                case 'p':
 
115
                    newinmode |= ENABLE_PROCESSED_INPUT;     break;
 
116
                case 'n':
 
117
                    notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
 
118
                case 'w':
 
119
                    newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
 
120
                case 'r':
 
121
                    notoutmode |= ENABLE_PROCESSED_OUTPUT;   break;
 
122
                case 'f':
 
123
                    newoutmode |= ENABLE_PROCESSED_OUTPUT;   break;
 
124
                case 'o':
 
125
                    if (*(argv + 1) && *(argv + 1)[0] != '-') {
 
126
                        *(++argv);
 
127
                        timeout = atoi(*argv) / 1000;
 
128
                        --argc;
 
129
                    }
 
130
                    else {
 
131
                        timeout = 0;
 
132
                    }
 
133
                    break;
 
134
                case 'v':
 
135
                    verbose = TRUE;
 
136
                    break;
 
137
                case 't':
 
138
                    contitle = *(++argv);
 
139
                    --argc;
 
140
                    break;
 
141
                case '?':
 
142
                    printf(options, arg0);
 
143
                    exit(1);
 
144
                default:
 
145
                    printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
 
146
                    exit(1);
 
147
            }
 
148
        }
 
149
        else {
 
150
            printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
 
151
            exit(1);
 
152
        }
 
153
    }
 
154
 
 
155
    hproc = GetCurrentProcess();
 
156
    hsavewinsta = GetProcessWindowStation();
 
157
    if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
 
158
        printerr("GetProcessWindowStation() failed (%d)\n", GetLastError());
 
159
    }
 
160
    else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
 
161
        printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n", GetLastError());
 
162
    }
 
163
    else if (strnicmp(str, "Service-", 8) == 0) {
 
164
        printerr("WindowStation Name %s is a service\n", str);
 
165
        isservice = TRUE;
 
166
    }
 
167
    SetLastError(0);
 
168
 
 
169
    hstdin = GetStdHandle(STD_INPUT_HANDLE);
 
170
    if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
 
171
        printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n",
 
172
                 GetLastError());
 
173
    }
 
174
    else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0,
 
175
                             isservice, DUPLICATE_SAME_ACCESS)) {
 
176
        CloseHandle(hstdin);
 
177
        hstdin = hdup;
 
178
    }
 
179
    else {
 
180
        printerr("DupHandle(stdin [%x]) failed (%d)\n",
 
181
                 hstdin, GetLastError());
 
182
    }
 
183
 
 
184
    hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
185
    if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
 
186
        printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n",
 
187
                 GetLastError());
 
188
    }
 
189
    else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0,
 
190
                             isservice, DUPLICATE_SAME_ACCESS)) {
 
191
        CloseHandle(hstdout);
 
192
        hstdout = hdup;
 
193
    }
 
194
    else {
 
195
        printerr("DupHandle(stdout [%x]) failed (%d)\n",
 
196
                 hstdout, GetLastError());
 
197
    }
 
198
 
 
199
    hstderr = GetStdHandle(STD_ERROR_HANDLE);
 
200
    if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
 
201
        printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n",
 
202
                 GetLastError());
 
203
    }
 
204
    else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0,
 
205
                             isservice, DUPLICATE_SAME_ACCESS)) {
 
206
        CloseHandle(hstderr);
 
207
        hstderr = hdup;
 
208
    }
 
209
    else {
 
210
        printerr("DupHandle(stderr [%x]) failed (%d)\n",
 
211
                 hstderr, GetLastError());
 
212
    }
 
213
 
 
214
    /* You can't close the console till all the handles above were
 
215
     * rescued by DuplicateHandle()
 
216
     */
 
217
    if (!FreeConsole())
 
218
        printerr("FreeConsole() failed (%d)\n", GetLastError());
 
219
 
 
220
    if (isservice) {
 
221
#ifdef WE_EVER_FIGURE_OUT_WHY_THIS_DOESNT_WORK
 
222
        hsavedesk = GetThreadDesktop(GetCurrentThreadId());
 
223
        if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) {
 
224
            printerr("GetThreadDesktop(GetTID()) failed (%d)\n", GetLastError());
 
225
        }
 
226
        CloseWindowStation(hwinsta);
 
227
        hwinsta = OpenWindowStation("WinSta0", TRUE, MAXIMUM_ALLOWED);
 
228
        if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
 
229
            printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
 
230
        }
 
231
        else if (!SetProcessWindowStation(hwinsta)) {
 
232
            printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
 
233
        }
 
234
        hdesk = OpenDesktop("Default", 0, TRUE, MAXIMUM_ALLOWED);
 
235
        if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
 
236
            printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
 
237
        }
 
238
        else if (!SetThreadDesktop(hdesk)) {
 
239
            printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
 
240
        }
 
241
#else
 
242
        PROCESS_INFORMATION pi;
 
243
        STARTUPINFO si;
 
244
        DWORD exitcode = 1;
 
245
        char appbuff[MAX_PATH];
 
246
        char *appname = NULL;
 
247
        char *cmdline = GetCommandLine();
 
248
 
 
249
        if (!GetModuleFileName(NULL, appbuff, sizeof(appbuff))) {
 
250
            appname = appbuff;
 
251
        }
 
252
 
 
253
        memset(&si, 0, sizeof(si));
 
254
        si.cb = sizeof(si);
 
255
        si.dwFlags     = STARTF_USESHOWWINDOW
 
256
                       | STARTF_USESTDHANDLES;
 
257
        si.lpDesktop   = "WinSta0\\Default";
 
258
        si.wShowWindow = 1;  /* SW_SHOWNORMAL */
 
259
        si.hStdInput   = hstdin;
 
260
        si.hStdOutput  = hstdout;
 
261
        si.hStdError   = hstderr;
 
262
 
 
263
        /* Instantly, upon creating the new process, we will close our
 
264
         * copies of the handles so our parent isn't confused when the
 
265
         * child closes their copy of the handle.  Without this action,
 
266
         * we would hold a copy of the handle, and the parent would not
 
267
         * receive their EOF notification.
 
268
         */
 
269
        if (CreateProcess(appname, cmdline, NULL, NULL, TRUE,
 
270
                          CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
 
271
                          NULL, NULL, &si, &pi)) {
 
272
            CloseHandle(si.hStdInput);
 
273
            CloseHandle(si.hStdOutput);
 
274
            CloseHandle(si.hStdError);
 
275
            ResumeThread(pi.hThread);
 
276
            CloseHandle(pi.hThread);
 
277
            WaitForSingleObject(pi.hProcess, INFINITE);
 
278
            GetExitCodeProcess(pi.hProcess, &exitcode);
 
279
            CloseHandle(pi.hProcess);
 
280
            return exitcode;
 
281
        }
 
282
        return 1;
 
283
#endif
 
284
    }
 
285
 
 
286
    if (!AllocConsole()) {
 
287
        printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
 
288
    }
 
289
 
 
290
    if (contitle && !SetConsoleTitle(contitle)) {
 
291
        printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
 
292
    }
 
293
 
 
294
    conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
 
295
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
 
296
                        FALSE, OPEN_EXISTING, 0, NULL);
 
297
    if (!conout || conout == INVALID_HANDLE_VALUE) {
 
298
        printerr("CreateFile(CONOUT$) failed (%d)\n", GetLastError());
 
299
    }
 
300
    else if (!GetConsoleMode(conout, &conmode)) {
 
301
        printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
 
302
    }
 
303
    else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode)
 
304
                                                         & ~notoutmode))) {
 
305
        printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n",
 
306
                 conmode, GetLastError());
 
307
    }
 
308
 
 
309
    conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
 
310
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
 
311
                       FALSE, OPEN_EXISTING, 0, NULL);
 
312
    if (!conin || conin == INVALID_HANDLE_VALUE) {
 
313
        printerr("CreateFile(CONIN$) failed (%d)\n", GetLastError());
 
314
    }
 
315
    else if (!GetConsoleMode(conin, &conmode)) {
 
316
        printerr("GetConsoleMode(CONIN) failed (%d)\n", GetLastError());
 
317
    }
 
318
    else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode)
 
319
                                                        & ~notinmode))) {
 
320
        printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n",
 
321
                 conmode, GetLastError());
 
322
    }
 
323
 
 
324
    feed.in = conin;
 
325
    feed.out = hstdout;
 
326
    thread = CreateThread(NULL, 0, feedback, (LPVOID)&feed, 0, &tid);
 
327
 
 
328
    while (ReadFile(hstdin, str, sizeof(str), &len, NULL))
 
329
        if (!len || !WriteFile(conout, str, len, &len, NULL))
 
330
           break;
 
331
 
 
332
    printerr("[EOF] from stdin (%d)\n", GetLastError());
 
333
 
 
334
    CloseHandle(stdout);
 
335
    if (!GetConsoleTitle(str, sizeof(str))) {
 
336
        printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
 
337
    }
 
338
    else {
 
339
        strcat(str, " - [Finished]");
 
340
        if (!SetConsoleTitle(str)) {
 
341
            printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
 
342
        }
 
343
    }
 
344
 
 
345
    WaitForSingleObject(thread, timeout);
 
346
    FreeConsole();
 
347
    if (isservice) {
 
348
        if (!SetProcessWindowStation(hsavewinsta)) {
 
349
            len = GetLastError();
 
350
        }
 
351
        if (!SetThreadDesktop(hsavedesk)) {
 
352
            len = GetLastError();
 
353
        }
 
354
        CloseDesktop(hdesk);
 
355
        CloseWindowStation(hwinsta);
 
356
    }
 
357
    return 0;
 
358
}
 
359
 
 
360
 
 
361
DWORD WINAPI feedback(LPVOID arg)
 
362
{
 
363
    feedback_args_t *feed = (feedback_args_t*)arg;
 
364
    char *str[1024];
 
365
    DWORD len;
 
366
 
 
367
    while (ReadFile(feed->in, str, sizeof(str), &len, NULL))
 
368
        if (!len || !WriteFile(feed->out, str, len, &len, NULL))
 
369
            break;
 
370
 
 
371
    printerr("[EOF] from Console (%d)\n", GetLastError());
 
372
 
 
373
    return 0;
 
374
}