ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_process.c
Revision: 3.3
Committed: Mon Jul 14 20:02:29 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 3.2: +3 -2 lines
Log Message:
Moved some more platform dependencies to common header files.
Included a few necessary system headers.

File Contents

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