ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_process.c
Revision: 3.5
Committed: Sat Oct 23 18:55:52 2004 UTC (19 years, 5 months ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad3R6P1
Changes since 3.4: +28 -19 lines
Log Message:
Compatibility fixes as suggested by Siegbert Debatin.

File Contents

# Content
1 #ifndef lint
2 static char RCSid[]="$Id: win_process.c,v 3.4 2003/10/21 19:19:28 schorsch Exp $";
3 #endif
4 /*
5 * Routines to communicate with separate process via dual pipes.
6 * Windows version.
7 *
8 * External symbols declared in standard.h
9 */
10
11 #include "copyright.h"
12
13 #include <stdio.h>
14 #define STRICT
15 #include <windows.h> /* typedefs */
16 #include <io.h> /* _open_osfhandle */
17 #include <fcntl.h> /* _O_XXX */
18
19 #include "rterror.h"
20 #include "rtio.h"
21 #include "rtprocess.h"
22
23
24 int
25 win_nice(int inc) /* simple nice(2) replacement for Windows */
26 {
27 /* We don't have much granularity available: IDLE_PRIORITY_CLASS
28 will run whenever no other higher priority process is running */
29 if (inc > 0) {
30 return (int)!SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
31 }
32 return 0;
33 }
34
35
36 /*
37 Safely terminate a process by creating a remote thread
38 in the process that calls ExitProcess.
39 As presented by Andrew Tucker in Windows Developer Magazine.
40 */
41 #ifndef OBSOLETE_WINDOWS /* won't work on Win 9X/ME/CE. */
42 BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
43 {
44 DWORD dwTID, dwCode, dwErr = 0;
45 HANDLE hProcessDup = INVALID_HANDLE_VALUE;
46 HANDLE hRT = NULL;
47 HINSTANCE hKernel = GetModuleHandle("Kernel32");
48 BOOL bSuccess = FALSE;
49
50 BOOL bDup = DuplicateHandle(GetCurrentProcess(),
51 hProcess,
52 GetCurrentProcess(),
53 &hProcessDup,
54 PROCESS_ALL_ACCESS,
55 FALSE,
56 0);
57 /* Detect the special case where the process is already dead... */
58 if ( GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
59 (dwCode == STILL_ACTIVE) ) {
60 FARPROC pfnExitProc;
61 pfnExitProc = GetProcAddress(hKernel, "ExitProcess");
62 hRT = CreateRemoteThread((bDup) ? hProcessDup : hProcess,
63 NULL,
64 0,
65 (LPTHREAD_START_ROUTINE)pfnExitProc,
66 (PVOID)uExitCode, 0, &dwTID);
67 if ( hRT == NULL ) dwErr = GetLastError();
68 } else {
69 dwErr = ERROR_PROCESS_ABORTED;
70 }
71 if ( hRT ) {
72 /* Must wait process to terminate to guarantee that it has exited... */
73 WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
74 CloseHandle(hRT);
75 bSuccess = TRUE;
76 }
77 if ( bDup ) CloseHandle(hProcessDup);
78 if ( !bSuccess ) SetLastError(dwErr);
79 return bSuccess;
80 }
81 #endif
82
83
84 static int
85 start_process(SUBPROC *proc, char *cmdstr)
86 {
87 BOOL res;
88 int Pflags = 0;
89 SECURITY_ATTRIBUTES SAttrs;
90 STARTUPINFO SInfo;
91 PROCESS_INFORMATION PInfo;
92 /* welcome to the world of resource handles */
93 HANDLE hToChildRead = NULL;
94 HANDLE hToChildWrite = NULL;
95 HANDLE hFromChildRead = NULL;
96 HANDLE hFromChildWrite = NULL;
97 HANDLE hRead = NULL, hWrite = NULL;
98 HANDLE hStdIn, hStdOut, hStdErr;
99 HANDLE hCurProc;
100
101 /* get process and standard stream handles */
102 hCurProc = GetCurrentProcess();
103 hStdIn = GetStdHandle(STD_INPUT_HANDLE);
104 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
105 hStdErr = GetStdHandle(STD_ERROR_HANDLE);
106
107 /* the remote pipe handles must be inheritable */
108 SAttrs.bInheritHandle = 1;
109 SAttrs.lpSecurityDescriptor = NULL;
110 SAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
111
112 /* make pipe, assign to stdout */
113 /* we'll check for errors after CreateProcess()...*/
114 res = CreatePipe(&hFromChildRead, &hFromChildWrite, &SAttrs, 0);
115 res = SetStdHandle(STD_OUTPUT_HANDLE, hFromChildWrite);
116 /* create non-inheritable dup of local end */
117 res = DuplicateHandle(hCurProc, hFromChildRead, hCurProc, &hRead,
118 0, FALSE, DUPLICATE_SAME_ACCESS);
119 CloseHandle(hFromChildRead); hFromChildRead = NULL;
120
121 res = CreatePipe(&hToChildRead, &hToChildWrite, &SAttrs, 0);
122 res = SetStdHandle(STD_INPUT_HANDLE, hToChildRead);
123 res = DuplicateHandle(hCurProc, hToChildWrite, hCurProc, &hWrite,
124 0, FALSE, DUPLICATE_SAME_ACCESS);
125 CloseHandle(hToChildWrite); hToChildWrite = NULL;
126
127 CloseHandle(hCurProc); hCurProc = NULL;
128
129 /* do some bookkeeping for Windows... */
130 SInfo.cb = sizeof(STARTUPINFO);
131 SInfo.lpReserved = NULL;
132 SInfo.lpDesktop = NULL;
133 SInfo.lpTitle = NULL;
134 SInfo.cbReserved2 = 0;
135 SInfo.lpReserved2 = NULL;
136 /* don't open a console automatically, pass handles */
137 SInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
138 SInfo.wShowWindow = SW_HIDE;
139 SInfo.hStdInput = hToChildRead;
140 SInfo.hStdOutput = hFromChildWrite;
141 SInfo.hStdError = hStdErr; /* reuse original stderr */
142
143 res = CreateProcess(NULL, /* command name */
144 cmdstr, /* full command line */
145 NULL, /* default process attributes */
146 NULL, /* default security attributes */
147 1, /* inherit handles (pass doesn't work reliably) */
148 Pflags, /* process flags */
149 NULL, /* no new environment */
150 NULL, /* stay in current directory */
151 &SInfo,
152 &PInfo
153 );
154 /* reset stdin/stdout in any case */
155 SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
156 SetStdHandle(STD_INPUT_HANDLE, hStdIn);
157 /* Oops... */
158 if(res == 0) {
159 char es[128];
160 _snprintf(es, sizeof(es),
161 "Error creating process (%d)\n", GetLastError());
162 eputs(es);
163 goto error;
164 }
165 /* close stuff we don't need */
166 CloseHandle(PInfo.hThread);
167 CloseHandle(hFromChildWrite); hFromChildWrite = NULL;
168 CloseHandle(hToChildRead); hToChildRead = NULL;
169 /* get the file descriptors */
170 proc->r = _open_osfhandle((long)hRead, _O_RDONLY);
171 proc->w = _open_osfhandle((long)hWrite, _O_APPEND);
172 proc->pid = PInfo.dwProcessId;
173 proc->running = 1;
174 CloseHandle(hCurProc);
175 /* Windows doesn't tell us the actual buffer size */
176 return PIPE_BUF;
177
178 error: /* cleanup */
179 if(PInfo.hThread) CloseHandle(PInfo.hThread);
180 if(hToChildRead) CloseHandle(hToChildRead);
181 if(hToChildWrite) CloseHandle(hToChildWrite);
182 if(hFromChildRead) CloseHandle(hFromChildRead);
183 if(hFromChildWrite) CloseHandle(hFromChildWrite);
184 if(hRead) CloseHandle(hRead);
185 if(hWrite) CloseHandle(hWrite);
186 if(hCurProc) CloseHandle(hCurProc);
187 proc->running = 0;
188 return 0;
189 /* There... Are we happy now? */
190 }
191
192
193 static int /* copied size or -1 on error */
194 wordncopy( /* copy (quoted) src to dest. */
195
196 char * dest,
197 char * src,
198 int dlen,
199 int insert_space, /* prepend a space */
200 int force_dq /* turn 'src' into "dest" (for Win command line) */
201 )
202 {
203 int slen;
204 int pos = 0;
205
206 slen = strlen(src);
207 if (insert_space) {
208 if (1 >= dlen) return -1;
209 dest[pos++] = ' ';
210 }
211 if (strpbrk(src, " \f\n\r\t\v")) {
212 if (force_dq && src[0] == '\'' && src[slen-1] == '\'') {
213 if (slen + pos + 1 > dlen) return -1;
214 dest[pos++] = '"';
215 strncpy(dest + pos, src + 1, slen -2);
216 pos += slen - 2;
217 dest[pos++] = '"';
218 } else if (src[0] == '"' && src[slen-1] == '"') {
219 if (slen + pos + 1 > dlen) return -1;
220 strncpy(dest + pos, src, slen);
221 pos += slen;
222 } else {
223 if (slen + pos + 3 > dlen) return -1;
224 dest[pos++] = '"';
225 strncpy(dest + pos, src, slen);
226 pos += slen;
227 dest[pos++] = '"';
228 }
229 } else {
230 if (slen + pos + 1 > dlen) return -1;
231 strncpy(dest + pos, src, slen);
232 pos += slen;
233 }
234 dest[pos] = '\0';
235 return pos;
236 }
237
238
239
240 static char *
241 quoted_cmdline( /* compose command line for StartProcess() as static string */
242
243 char *cmdpath, /* full path to executable */
244 char *sl[] /* list of arguments */
245 )
246 {
247 static char *cmdstr;
248 static int clen;
249 char *newcs;
250 int newlen, pos, res, i;
251
252 newlen = strlen(cmdpath) + 3; /* allow two quotes plus the final \0 */
253 for (i = 0; sl[i] != NULL; i++) {
254 newlen += strlen(sl[i]) + 3; /* allow two quotes and a space */
255 }
256 if (cmdstr == NULL) {
257 cmdstr = (char *) malloc(newlen);
258 if (cmdstr == NULL) return NULL;
259 } else if (newlen > clen) {
260 newcs = (char *) realloc(cmdstr, newlen);
261 if (newcs == NULL) return NULL;
262 cmdstr = newcs;
263 }
264 clen = newlen;
265 pos = wordncopy(cmdstr, cmdpath, clen, 0, 1);
266 if (pos < 0) return NULL;
267 for (i = 0; sl[i] != NULL; i++) {
268 res = wordncopy(cmdstr + pos, sl[i], clen - pos, 1, 1);
269 if (res < 0) return NULL;
270 pos += res;
271 }
272 return cmdstr;
273 }
274
275
276 int
277 open_process(SUBPROC *proc, char *av[])
278 {
279 char *cmdpath;
280 char *cmdstr;
281
282 proc->running = 0;
283 cmdpath = getpath(av[0], getenv("PATH"), X_OK);
284 cmdstr = quoted_cmdline(cmdpath, av);
285 if (cmdstr == NULL) { return 0; }
286 return start_process(proc, cmdstr);
287 }
288
289
290 int win_kill(RT_PID pid, int sig) /* we ignore sig... */
291 {
292 HANDLE hProc;
293
294 hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pid);
295 /* it looks like we want to ignore errors here */
296 if(hProc != NULL) {
297 #ifdef OBSOLETE_WINDOWS
298 #define KILL_TIMEOUT 10 * 1000 /* milliseconds */
299 /* it might have some windows open... */
300 EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM)pid);
301 if(WaitForSingleObject(hProc, KILL_TIMEOUT)!=WAIT_OBJECT_0) {
302 /* No way to avoid dangling DLLs here. */
303 TerminateProcess(hProc, 0);
304 }
305 #else
306 SafeTerminateProcess(hProc, 0);
307 #endif
308 /* WaitForSingleObject(hProc, 0); */
309 /* not much use to wait on Windows */
310 CloseHandle(hProc);
311 }
312 return 0; /* XXX we need to figure out more here... */
313 }
314
315
316 int
317 close_process(SUBPROC *proc) {
318 int icres, ocres;
319 DWORD pid;
320
321 ocres = close(proc->w);
322 icres = close(proc->r);
323 pid = proc->pid;
324 if(ocres != 0 || icres != 0) {
325 /* something went wrong: enforce infanticide */
326 /* other than that, it looks like we want to ignore errors here */
327 if (proc->running) {
328 int win_kill(pid, 0);
329 }
330 }
331 proc->running = 0;
332 return 0; /* XXX we need to figure out more here... */
333 }
334
335
336 #ifdef TEST_MODULE
337 int
338 main( int argc, char **argv )
339 {
340 SUBPROC proc;
341 FILE *inf, *outf;
342 int res;
343 char ret[1024];
344 char *command[]= {"word", "gappy word", "\"quoted words\"", "'squoted words'", NULL};
345
346 res = open_process(&proc, command)
347 if (res == 0) {
348 printf("open_process() failed with return value 0\n");
349 return -1;
350 }
351 printf("process opened with return value: %d, pid: %d, r: %d, w: %d\n",
352 res, proc.pid, proc.r, proc.w);
353 inf = fdopen(proc.r, "rb");
354 outf = fdopen(proc.w, "wb");
355 fprintf(outf,"0 0 0 0 1 0\n");
356 fflush(outf);
357 fgets(ret, sizeof(ret), inf);
358 printf("%s\n",ret);
359 close_process(&proc);
360 }
361 #endif
362