ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_process.c
Revision: 3.14
Committed: Fri Feb 28 05:18:49 2020 UTC (4 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R3, HEAD
Changes since 3.13: +12 -8 lines
Log Message:
Added filtering capabilities to Unix version of open_process()

File Contents

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