Standardize License information
[openafs.git] / src / procmgmt / procmgmt_nt.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <stddef.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <windows.h>
19 #include <pthread.h>
20 #include <afs/errmap_nt.h>
21 #include <afs/secutil_nt.h>
22
23 #include "procmgmt.h"
24 #include "pmgtprivate.h"
25
26
27
28 /* Signal disposition table and associated definitions and locks */
29
30 typedef struct {
31     struct sigaction action;  /* signal action information */
32 } sigtable_entry_t;
33
34 static sigtable_entry_t signalTable[NSIG];  /* signal table; slot 0 unused */
35 static pthread_mutex_t  signalTableLock;    /* lock protects signalTable */
36
37 /* Global signal block lock; all signal handlers are serialized for now */
38 static pthread_mutex_t signalBlockLock;
39
40 /* Named pipe prefix for sending signals */
41 #define PMGT_SIGNAL_PIPE_PREFIX  "\\\\.\\pipe\\TransarcAfsSignalPipe"
42
43 /* Macro to test process exit status for an uncaught exception */
44 #define PMGT_IS_EXPSTATUS(status)   (((status) & 0xF0000000) == 0xC0000000)
45
46
47
48 /* Child process table and associated definitions and locks */
49
50 typedef struct {
51     HANDLE p_handle;      /* process handle (NULL if table entry not valid) */
52     BOOL   p_reserved;    /* table entry is reserved for spawn */
53     DWORD  p_id;          /* process id */
54     BOOL   p_terminated;  /* process terminated; status available/valid */
55     DWORD  p_status;      /* status of terminated process */
56 } proctable_entry_t;
57
58 /* Max number of active child processes supported */
59 #define PMGT_CHILD_MAX  100
60
61 static proctable_entry_t procTable[PMGT_CHILD_MAX];  /* child process table */
62 static int procEntryCount;   /* count of valid entries in procTable */
63 static int procTermCount;    /* count of terminated entries in procTable */
64
65 /* lock protects procTable, procEntryCount, and procTermCount */
66 static pthread_mutex_t procTableLock;
67
68 /* Named shared memory prefix for passing a data buffer to a child process */
69 #define PMGT_DATA_MEM_PREFIX  "TransarcAfsSpawnDataMemory"
70
71 /* Named event prefix for indicating that a data buffer has been read */
72 #define PMGT_DATA_EVENT_PREFIX  "TransarcAfsSpawnDataEvent"
73
74 /* event signals termination of a child process */
75 static pthread_cond_t childTermEvent;
76
77
78 /* Exported data values */
79
80 void *pmgt_spawnData = NULL;
81 size_t pmgt_spawnDataLen = 0;
82
83
84 /* General definitions */
85
86 #define DWORD_OF_ONES   ((DWORD)0xFFFFFFFF)  /* a common Win32 failure code */
87
88
89
90
91
92
93 /* -----------------  Signals  ---------------- */
94
95
96 /*
97  * SignalIsDefined() -- Determine if an integer value corresponds to a
98  *     signal value defined for this platform.
99  */
100 static int
101 SignalIsDefined(int signo)
102 {
103     int isDefined = 0;
104
105     if (signo >= 1 && signo <= (NSIG - 1)) {
106         /* value is in valid range; check specifics */
107         switch (signo) {
108           case SIGHUP:
109           case SIGINT:
110           case SIGQUIT:
111           case SIGILL:
112           case SIGABRT:
113           case SIGFPE:
114           case SIGKILL:
115           case SIGSEGV:
116           case SIGTERM:
117           case SIGUSR1:
118           case SIGUSR2:
119           case SIGCHLD:
120           case SIGTSTP:
121             isDefined = 1;
122             break;
123         }
124     }
125     return isDefined;
126 }
127
128
129 /*
130  * DefaultActionHandler() -- Execute the default action for the given signal.
131  */
132 static void __cdecl
133 DefaultActionHandler(int signo)
134 {
135     switch (signo) {
136       case SIGHUP:
137       case SIGINT:
138       case SIGKILL:
139       case SIGTERM:
140       case SIGUSR1:
141       case SIGUSR2:
142         /* default action is "exit" */
143         ExitProcess(PMGT_SIGSTATUS_ENCODE(signo));
144         break;
145       case SIGQUIT:
146       case SIGILL:
147       case SIGABRT:
148       case SIGFPE:
149       case SIGSEGV:
150         /* default action is "core" */
151         /* Best we can do is to raise an exception that can be caught by
152          * Dr. Watson, which can in turn generate a crash dump file.
153          * The default exception handler will call ExitProcess() with
154          * our application-specific exception code.
155          */
156         RaiseException((DWORD)PMGT_SIGSTATUS_ENCODE(signo),
157                        EXCEPTION_NONCONTINUABLE, 0, NULL);
158         break;
159       case SIGCHLD:
160         /* default action is "ignore" */
161         break;
162       case SIGTSTP:
163         /* default action is "stop" */
164         /* No good way to implement this from inside a process so ignore */
165         break;
166       default:
167         /* no default action for specified signal value; just ignore */
168         break;
169     }
170 }
171
172
173 /*
174  * ProcessSignal() -- Execute the specified or default handler for the given
175  *     signal; reset the signal's disposition to SIG_DFL if necessary.
176  *     If the signal's disposition is SIG_IGN then no processing takes place.
177  *
178  * ASSUMPTIONS: signo is valid (i.e., SignalIsDefined(signo) is TRUE).
179  */
180 static void
181 ProcessSignal(int signo)
182 {
183     struct sigaction sigEntry;
184
185     if (signo != SIGKILL) {
186         /* serialize signals, but never block processing of SIGKILL */
187         (void) pthread_mutex_lock(&signalBlockLock);
188     }
189
190     /* fetch disposition of signo, updating it if necessary */
191
192     (void) pthread_mutex_lock(&signalTableLock);
193     sigEntry = signalTable[signo].action;
194
195     if ((sigEntry.sa_handler != SIG_IGN) &&
196         (sigEntry.sa_flags & SA_RESETHAND) &&
197         (signo != SIGILL)) {
198         signalTable[signo].action.sa_handler = SIG_DFL;
199     }
200     (void) pthread_mutex_unlock(&signalTableLock);
201
202     /* execute handler */
203
204     if (sigEntry.sa_handler != SIG_IGN) {
205         if (sigEntry.sa_handler == SIG_DFL) {
206             sigEntry.sa_handler = DefaultActionHandler;
207         }
208         (*sigEntry.sa_handler)(signo);
209     }
210
211     if (signo != SIGKILL) {
212         (void) pthread_mutex_unlock(&signalBlockLock);
213     }
214 }
215
216
217 /*
218  * RemoteSignalThread() -- Thread spawned to process remote signal.
219  *
220  *     Param must be the signal number.
221  */
222 static DWORD WINAPI
223 RemoteSignalThread(LPVOID param)
224 {
225     int signo = (int)param;
226     DWORD rc = 0;
227
228     if (SignalIsDefined(signo)) {
229         /* process signal */
230         ProcessSignal(signo);
231     } else if (signo != 0) {
232         /* invalid signal value */
233         rc = -1;
234     }
235     return rc;
236 }
237
238
239 /*
240  * RemoteSignalListenerThread() -- Thread spawned to receive and process
241  *     remotely generated signals; never returns.
242  *
243  *     Param must be a handle for a duplex server message pipe in blocking
244  *     mode.
245  */
246 static DWORD WINAPI
247 RemoteSignalListenerThread(LPVOID param)
248 {
249     HANDLE sigPipeHandle = (HANDLE)param;
250
251     while (1) {
252         /* wait for pipe client to connect */
253
254         if ((ConnectNamedPipe(sigPipeHandle, NULL)) ||
255             (GetLastError() == ERROR_PIPE_CONNECTED)) {
256             /* client connected; read signal value */
257             int signo;
258             DWORD bytesXfered;
259
260             if ((ReadFile(sigPipeHandle,
261                           &signo, sizeof(signo), &bytesXfered, NULL)) &&
262                 (bytesXfered == sizeof(signo))) {
263                 HANDLE sigThreadHandle;
264                 DWORD sigThreadId;
265
266                 /* ACK signal to release sender */
267                 (void) WriteFile(sigPipeHandle,
268                                  &signo, sizeof(signo), &bytesXfered, NULL);
269
270                 /* spawn thread to process signal; we do this so that
271                  * we can always process a SIGKILL even if a signal handler
272                  * invoked earlier fails to return (blocked/spinning).
273                  */
274                 sigThreadHandle =
275                     CreateThread(NULL,           /* default security attr. */
276                                  0,              /* default stack size */
277                                  RemoteSignalThread,
278                                  (LPVOID)signo,  /* thread argument */
279                                  0,              /* creation flags */
280                                  &sigThreadId);  /* thread id */
281
282                 if (sigThreadHandle != NULL) {
283                     (void) CloseHandle(sigThreadHandle);
284                 }
285             }
286             /* nothing to do if ReadFile, WriteFile or CreateThread fails. */
287
288         } else {
289             /* connect failed; this should never happen */
290             Sleep(2000); /* sleep 2 seconds to avoid tight loop */
291         }
292
293         (void)DisconnectNamedPipe(sigPipeHandle);
294     }
295
296     /* never reached */
297     return (0);
298 }
299
300
301
302
303
304 /*
305  * pmgt_SigactionSet() -- Examine and/or specify the action for a given
306  *     signal (Unix sigaction() semantics).
307  */
308 int
309 pmgt_SigactionSet(int signo,
310                   const struct sigaction *actionP,
311                   struct sigaction *old_actionP)
312 {
313     /* validate arguments */
314
315     if (!SignalIsDefined(signo) || signo == SIGKILL) {
316         /* invalid signal value or signal can't be caught/ignored */
317         errno = EINVAL;
318         return -1;
319     }
320
321     if (actionP && actionP->sa_handler == SIG_ERR) {
322         /* invalid signal disposition */
323         errno = EINVAL;
324         return -1;
325     }
326
327     /* fetch and/or set disposition of signo */
328
329     (void) pthread_mutex_lock(&signalTableLock);
330
331     if (old_actionP) {
332         *old_actionP = signalTable[signo].action;
333     }
334
335     if (actionP) {
336         signalTable[signo].action = *actionP;
337     }
338
339     (void) pthread_mutex_unlock(&signalTableLock);
340
341     return 0;
342 }
343
344
345 /*
346  * pmgt_SignalSet() -- Specify the disposition for a given signal
347  *     value (Unix signal() semantics).
348  */
349 void (__cdecl *pmgt_SignalSet(int signo,
350                               void (__cdecl *dispP)(int)))(int)
351 {
352     struct sigaction newAction, oldAction;
353
354     /* construct action to request Unix signal() semantics */
355
356     newAction.sa_handler = dispP;
357     sigemptyset(&newAction.sa_mask);
358     newAction.sa_flags = SA_RESETHAND;
359
360     if (!pmgt_SigactionSet(signo, &newAction, &oldAction)) {
361         /* successfully set new signal action */
362         return oldAction.sa_handler;
363     } else {
364         /* failed to set signal action; errno will have been set */
365         return SIG_ERR;
366     }
367 }
368
369
370 /*
371  * pmgt_SignalRaiseLocal() -- Raise a signal in this process (C raise()
372  *     semantics).
373  */
374 int
375 pmgt_SignalRaiseLocal(int signo)
376 {
377     int rc = 0;
378
379     /* Process signal directly in the context of the calling thread.
380      * This is the same as if the signal had been raised in this process
381      * and this thread chosen to execute the handler.
382      */
383
384     if (SignalIsDefined(signo)) {
385         /* process signal */
386         ProcessSignal(signo);
387     } else if (signo != 0) {
388         /* invalid signal value */
389         errno = EINVAL;
390         rc = -1;
391     }
392     return rc;
393 }
394
395
396 /*
397  * pmgt_SignalRaiseLocalByName() -- Raise a signal in this process where
398  *     the signal is specified by name (C raise() semantics).
399  *
400  *     Upon successful completion, *libSigno is set to the process management
401  *     library's constant value for signame.
402  *
403  *     Note: exists to implement the native-signal redirector (redirect_nt.c),
404  *           which can't include procmgmt.h and hence can't get the SIG* decls.
405  */
406 int
407 pmgt_SignalRaiseLocalByName(const char *signame, int *libSigno)
408 {
409     int rc = 0;
410     int signo;
411
412     if (!strcmp(signame, "SIGHUP")) {
413         signo = SIGHUP;
414     } else if (!strcmp(signame, "SIGINT")) {
415         signo = SIGINT;
416     } else if (!strcmp(signame, "SIGQUIT")) {
417         signo = SIGQUIT;
418     } else if (!strcmp(signame, "SIGILL")) {
419         signo = SIGILL;
420     } else if (!strcmp(signame, "SIGABRT")) {
421         signo = SIGABRT;
422     } else if (!strcmp(signame, "SIGFPE")) {
423         signo = SIGFPE;
424     } else if (!strcmp(signame, "SIGKILL")) {
425         signo = SIGKILL;
426     } else if (!strcmp(signame, "SIGSEGV")) {
427         signo = SIGSEGV;
428     } else if (!strcmp(signame, "SIGTERM")) {
429         signo = SIGTERM;
430     } else if (!strcmp(signame, "SIGUSR1")) {
431         signo = SIGUSR1;
432     } else if (!strcmp(signame, "SIGUSR2")) {
433         signo = SIGUSR2;
434     } else if (!strcmp(signame, "SIGCLD")) {
435         signo = SIGCLD;
436     } else if (!strcmp(signame, "SIGCHLD")) {
437         signo = SIGCHLD;
438     } else if (!strcmp(signame, "SIGTSTP")) {
439         signo = SIGTSTP;
440     } else {
441         /* unknown signal name */
442         errno = EINVAL;
443         rc = -1;
444     }
445
446     if (rc == 0) {
447         *libSigno = signo;
448         rc = pmgt_SignalRaiseLocal(signo);
449     }
450     return rc;
451 }
452
453
454 /*
455  * pmgt_SignalRaiseRemote() -- Raise a signal in the specified process (Unix
456  *     kill() semantics).
457  *
458  *     Note: only supports sending signal to a specific (single) process.
459  */
460 int
461 pmgt_SignalRaiseRemote(pid_t pid,
462                        int signo)
463 {
464     BOOL fsuccess;
465     char sigPipeName[sizeof(PMGT_SIGNAL_PIPE_PREFIX) + 20];
466     DWORD ackBytesRead;
467     int signoACK;
468     int status = 0;
469
470     /* validate arguments */
471
472     if ((pid <= (pid_t)0) ||
473         (!SignalIsDefined(signo) && signo != 0)) {
474         /* invalid pid or signo */
475         errno = EINVAL;
476         return -1;
477     }
478
479     /* optimize for the "this process" case */
480
481     if (pid == (pid_t)GetCurrentProcessId()) {
482         return pmgt_SignalRaiseLocal(signo);
483     }
484
485     /* send signal to process via named pipe */
486
487     sprintf(sigPipeName, "%s%d", PMGT_SIGNAL_PIPE_PREFIX, (int)pid);
488
489     fsuccess =
490         CallNamedPipe(sigPipeName,         /* process pid's signal pipe */
491                       &signo,              /* data written to pipe */
492                       sizeof(signo),       /* size of data to write */
493                       &signoACK,           /* data read from pipe */
494                       sizeof(signoACK),    /* size of data read buffer */
495                       &ackBytesRead,       /* number of bytes actually read */
496                       5 * 1000);           /* 5 second timeout */
497
498     if (!fsuccess) {
499         /* failed to send signal via named pipe */
500         status = -1;
501
502         if (signo == SIGKILL) {
503             /* could be a non-AFS process, which might still be kill-able */
504             HANDLE procHandle;
505
506             if (procHandle = OpenProcess(PROCESS_TERMINATE,
507                                          FALSE, (DWORD)pid)) {
508                 if (TerminateProcess(procHandle,
509                                      PMGT_SIGSTATUS_ENCODE(SIGKILL))) {
510                     /* successfully killed process */
511                     status = 0;
512                 } else {
513                     errno = nterr_nt2unix(GetLastError(), EPERM);
514                 }
515                 (void) CloseHandle(procHandle);
516             } else {
517                 if (GetLastError() == ERROR_INVALID_PARAMETER) {
518                     errno = ESRCH;
519                 } else if (GetLastError() == ERROR_ACCESS_DENIED) {
520                     errno = EPERM;
521                 } else {
522                     errno = nterr_nt2unix(GetLastError(), EPERM);
523                 }
524             }
525         } else {
526             /* couldn't open pipe so can't send (non-SIGKILL) signal */
527             errno = nterr_nt2unix(GetLastError(), EPERM);
528         }
529     }
530
531     return status;
532 }
533
534
535
536
537 /* -----------------  Processes  ---------------- */
538
539
540 /*
541  * StringArrayToString() -- convert a null-terminated array of strings,
542  *     such as argv, into a single string of space-separated elements
543  *     with each element quoted (in case it contains space characters
544  *     or is of zero length).
545  */
546 static char *
547 StringArrayToString(char *strArray[])
548 {
549     int strCount = 0;
550     int byteCount = 0;
551     char *buffer = NULL;
552
553     for (strCount = 0; strArray[strCount] != NULL; strCount++) {
554         /* sum all string lengths */
555         byteCount += strlen(strArray[strCount]);
556     }
557
558     /* put all strings into buffer; guarantee buffer is at least one char */
559     buffer = (char *)malloc(byteCount + (strCount * 3) /* quotes+space */ + 1);
560     if (buffer != NULL) {
561         int i;
562
563         buffer[0] = '\0';
564
565         for (i = 0; i < strCount; i++) {
566             char *bufp = buffer + strlen(buffer);
567
568             if (i == strCount - 1) {
569                 /* last string; no trailing space */
570                 sprintf(bufp, "\"%s\"", strArray[i]);
571             } else {
572                 sprintf(bufp, "\"%s\" ", strArray[i]);
573             }
574         }
575     }
576
577     return (buffer);
578 }
579
580
581 /*
582  * StringArrayToMultiString() -- convert a null-terminated array of strings,
583  *     such as envp, into a multistring.
584  */
585 static char *
586 StringArrayToMultiString(char *strArray[])
587 {
588     int strCount = 0;
589     int byteCount = 0;
590     char *buffer = NULL;
591
592     for (strCount = 0; strArray[strCount] != NULL; strCount++) {
593         /* sum all string lengths */
594         byteCount += strlen(strArray[strCount]);
595     }
596
597     /* put all strings into buffer; guarantee buffer is at least two chars */
598     buffer = (char *)malloc(byteCount + strCount + 2);
599     if (buffer != NULL) {
600         if (byteCount == 0) {
601             buffer[0] = '\0';
602             buffer[1] = '\0';
603         } else {
604             int i;
605             char *bufp = buffer;
606
607             for (i = 0; i < strCount; i++) {
608                 int strLen = strlen(strArray[i]);
609
610                 if (strLen > 0) {
611                     /* can not embed zero length string in a multistring */
612                     strcpy(bufp, strArray[i]);
613                     bufp += strLen + 1;
614                 }
615             }
616             bufp = '\0';  /* terminate multistring */
617         }
618     }
619
620     return (buffer);
621 }
622
623
624
625 /*
626  * ComputeWaitStatus() -- Compute an appropriate wait status value from
627  *     a given process termination (exit) code.
628  */
629 static int
630 ComputeWaitStatus(DWORD exitStatus)
631 {
632     int waitStatus;
633
634     if (PMGT_IS_SIGSTATUS(exitStatus)) {
635         /* child terminated due to an unhandled signal */
636         int signo = PMGT_SIGSTATUS_DECODE(exitStatus);
637         waitStatus = WSIGNALED_ENCODE(signo);
638     } else if (PMGT_IS_EXPSTATUS(exitStatus)) {
639         /* child terminated due to an uncaught exception */
640         int signo;
641
642         switch (exitStatus) {
643           case EXCEPTION_FLT_DENORMAL_OPERAND:
644           case EXCEPTION_FLT_DIVIDE_BY_ZERO:
645           case EXCEPTION_FLT_INEXACT_RESULT:
646           case EXCEPTION_FLT_INVALID_OPERATION:
647           case EXCEPTION_FLT_OVERFLOW:
648           case EXCEPTION_FLT_STACK_CHECK:
649           case EXCEPTION_FLT_UNDERFLOW:
650           case EXCEPTION_INT_DIVIDE_BY_ZERO:
651           case EXCEPTION_INT_OVERFLOW:
652             signo = SIGFPE;
653             break;
654           case EXCEPTION_PRIV_INSTRUCTION:
655           case EXCEPTION_ILLEGAL_INSTRUCTION:
656             signo = SIGILL;
657             break;
658           case CONTROL_C_EXIT:
659             signo = SIGINT;
660             break;
661           default:
662             signo = SIGSEGV;
663             break;
664         }
665         waitStatus = WSIGNALED_ENCODE(signo);
666     } else {
667         /* child terminated normally */
668         waitStatus = WEXITED_ENCODE(exitStatus);
669     }
670
671     return waitStatus;
672 }
673
674
675
676 /*
677  * CreateChildDataBuffer() -- Create and fill a named data buffer to pass to
678  *     a child process, along with a corresponding buffer read event.
679  *
680  * ASSUMPTIONS: child process is linked with this process management library;
681  *     otherwise no data transfer will take place.
682  */
683 static BOOL
684 CreateChildDataBuffer(DWORD pid,                /* child pid */
685                       void *datap,              /* data to place in buffer */
686                       size_t dataLen,           /* size of data in bytes */
687                       HANDLE *bufMemHandlep,    /* buffer memory handle */
688                       HANDLE *bufEventHandlep)  /* buffer read event handle */
689 {
690     BOOL fsuccess = FALSE;
691     DWORD bufMemSize = dataLen + sizeof(size_t);
692     char bufMemName[sizeof(PMGT_DATA_MEM_PREFIX) + 20];
693     char bufEventName[sizeof(PMGT_DATA_EVENT_PREFIX) + 20];
694
695     sprintf(bufMemName, "%s%d", PMGT_DATA_MEM_PREFIX, (int)pid);
696     sprintf(bufEventName, "%s%d", PMGT_DATA_EVENT_PREFIX, (int)pid);
697
698     /* Create and initialize named shared memory and named event */
699
700     *bufMemHandlep =
701         CreateFileMapping((HANDLE)0xFFFFFFFF, /* page-file backed */
702                           NULL,
703                           PAGE_READWRITE,
704                           0,
705                           bufMemSize,
706                           bufMemName);
707
708     if (*bufMemHandlep != NULL) {
709         void *bufMemp;
710
711         bufMemp = MapViewOfFile(*bufMemHandlep,
712                                 FILE_MAP_WRITE, 0, 0, bufMemSize);
713
714         if (bufMemp != NULL) {
715             /* copy data into shared memory, prefixed with data size */
716             size_t *memp = (size_t *)bufMemp;
717
718             *memp++ = dataLen;
719             memcpy((void *)memp, datap, dataLen);
720
721             if (UnmapViewOfFile(bufMemp)) {
722                 /* create buffer read event */
723                 *bufEventHandlep = CreateEvent(NULL,
724                                                FALSE /* manual reset */,
725                                                FALSE /* initial state */,
726                                                bufEventName);
727                 if (*bufEventHandlep != NULL) {
728                     fsuccess = TRUE;
729                 }
730             }
731         }
732
733         if (!fsuccess) {
734             (void) CloseHandle(*bufMemHandlep);
735         }
736     }
737
738     if (!fsuccess) {
739         *bufMemHandlep = *bufEventHandlep = NULL;
740     }
741     return fsuccess;
742 }
743
744
745
746 /*
747  * ReadChildDataBuffer() -- Read data buffer passed to child from parent,
748  *     if any, and place in allocated storage.
749  */
750 static BOOL
751 ReadChildDataBuffer(void **datap,      /* allocated data buffer */
752                     size_t *dataLen)   /* size of data buffer returned */
753 {
754     BOOL fsuccess = FALSE;
755     char bufMemName[sizeof(PMGT_DATA_MEM_PREFIX) + 20];
756     char bufEventName[sizeof(PMGT_DATA_EVENT_PREFIX) + 20];
757     HANDLE bufMemHandle, bufEventHandle;
758
759     sprintf(bufMemName, "%s%d",
760             PMGT_DATA_MEM_PREFIX, (int)GetCurrentProcessId());
761     sprintf(bufEventName, "%s%d",
762             PMGT_DATA_EVENT_PREFIX, (int)GetCurrentProcessId());
763
764     /* Attempt to open named event and named shared memory */
765
766     bufEventHandle = OpenEvent(EVENT_MODIFY_STATE, FALSE, bufEventName);
767
768     if (bufEventHandle != NULL) {
769         bufMemHandle = OpenFileMapping(FILE_MAP_READ, FALSE, bufMemName);
770
771         if (bufMemHandle != NULL) {
772             void *bufMemp;
773
774             bufMemp = MapViewOfFile(bufMemHandle, FILE_MAP_READ, 0, 0, 0);
775
776             if (bufMemp != NULL) {
777                 /* read data size and data from shared memory */
778                 size_t *memp = (size_t *)bufMemp;
779
780                 *dataLen = *memp++;
781                 *datap = (void *)malloc(*dataLen);
782
783                 if (*datap != NULL) {
784                     memcpy(*datap, (void *)memp, *dataLen);
785                     fsuccess = TRUE;
786                 }
787                 (void) UnmapViewOfFile(bufMemp);
788             }
789
790             (void) CloseHandle(bufMemHandle);
791         }
792
793         (void) SetEvent(bufEventHandle);
794         (void) CloseHandle(bufEventHandle);
795     }
796
797     if (!fsuccess) {
798         *datap = NULL;
799         *dataLen = 0;
800     }
801     return fsuccess;
802 }
803
804
805
806 /*
807  * ChildMonitorThread() -- Thread spawned to monitor status of child process.
808  *
809  *     Param must be index into child process table.
810  */
811 static DWORD WINAPI
812 ChildMonitorThread(LPVOID param)
813 {
814     int tidx = (int)param;
815     HANDLE childProcHandle;
816     BOOL fsuccess;
817     DWORD rc = -1;
818
819     /* retrieve handle for child process from process table and duplicate */
820
821     (void) pthread_mutex_lock(&procTableLock);
822
823     fsuccess =
824         DuplicateHandle(GetCurrentProcess(),      /* source process handle */
825                         procTable[tidx].p_handle, /* source handle to dup */
826                         GetCurrentProcess(),      /* target process handle */
827                         &childProcHandle,   /* target handle (duplicate) */
828                         0,                  /* access (ignored here) */
829                         FALSE,              /* not inheritable */
830                         DUPLICATE_SAME_ACCESS);
831
832     (void) pthread_mutex_unlock(&procTableLock);
833
834     if (fsuccess) {
835         /* wait for child process to terminate */
836
837         if (WaitForSingleObject(childProcHandle, INFINITE) == WAIT_OBJECT_0) {
838             /* child process terminated; mark in table and signal event */
839             (void) pthread_mutex_lock(&procTableLock);
840
841             procTable[tidx].p_terminated = TRUE;
842             (void) GetExitCodeProcess(childProcHandle,
843                                       &procTable[tidx].p_status);
844             procTermCount++;
845
846             (void) pthread_mutex_unlock(&procTableLock);
847
848             (void) pthread_cond_broadcast(&childTermEvent);
849
850             /* process/raise SIGCHLD; do last in case handler never returns */
851             ProcessSignal(SIGCHLD);
852             rc = 0;
853         }
854
855         (void) CloseHandle(childProcHandle);
856     }
857
858     /* note: nothing can be done if DuplicateHandle() or WaitForSingleObject()
859      *       fail; however, this should never happen.
860      */
861     return rc;
862 }
863
864
865
866 /*
867  * pmgt_ProcessSpawnVEB() -- Spawn a process (Unix fork()/execve() semantics)
868  *
869  *     Returns pid of the child process ((pid_t)-1 on failure with errno set).
870  *
871  *     Notes: A senvp value of NULL results in Unix fork()/execv() semantics.
872  *            Open files are not inherited; child's stdin, stdout, and stderr
873  *                are set to parent's console.
874  *            If spath does not specify a filename extension ".exe" is used.
875  *            If sdatap is not NULL, and sdatalen > 0, data is passed to child.
876  *            The spath and sargv[] strings must not contain quote chars (").
877  *
878  * ASSUMPTIONS: sargv[0] is the same as spath (or its last component).
879  */
880 pid_t
881 pmgt_ProcessSpawnVEB(const char *spath,
882                      char *sargv[],
883                      char *senvp[],
884                      void *sdatap,
885                      size_t sdatalen)
886 {
887     int tidx;
888     char *pathbuf, *argbuf, *envbuf;
889     char pathext[_MAX_EXT];
890     STARTUPINFO startInfo;
891     PROCESS_INFORMATION procInfo;
892     HANDLE monitorHandle = NULL;
893     HANDLE bufMemHandle, bufEventHandle;
894     DWORD monitorId, createFlags;
895     BOOL passingBuffer = (sdatap != NULL && sdatalen > 0);
896     BOOL fsuccess;
897
898     /* verify arguments */
899     if (!spath || !sargv) {
900         errno = EFAULT;
901         return (pid_t)-1;
902     } else if (*spath == '\0') {
903         errno = ENOENT;
904         return (pid_t)-1;
905     }
906
907     /* create path with .exe extension if no filename extension supplied */
908     if (!(pathbuf = (char *)malloc(strlen(spath) + 5 /* .exe */))) {
909         errno = ENOMEM;
910         return ((pid_t)-1);
911     }
912     strcpy(pathbuf, spath);
913
914     _splitpath(pathbuf, NULL, NULL, NULL, pathext);
915     if (*pathext == '\0') {
916         /* no filename extension supplied for spath; .exe is assumed */
917         strcat(pathbuf, ".exe");
918     }
919
920     /* create command line argument string */
921     argbuf = StringArrayToString(sargv);
922
923     if (!argbuf) {
924         free(pathbuf);
925         errno = ENOMEM;
926         return ((pid_t)-1);
927     }
928
929     /* create environment variable block (multistring) */
930     if (senvp) {
931         /* use environment variables provided */
932         envbuf = StringArrayToMultiString(senvp);
933
934         if (!envbuf) {
935             free(pathbuf);
936             free(argbuf);
937             errno = ENOMEM;
938             return ((pid_t)-1);
939         }
940     } else {
941         /* use default environment variables */
942         envbuf = NULL;
943     }
944
945     /* set process creation flags */
946     createFlags = CREATE_SUSPENDED | NORMAL_PRIORITY_CLASS;
947
948     if (getenv(PMGT_SPAWN_DETACHED_ENV_NAME) != NULL) {
949         createFlags |= DETACHED_PROCESS;
950     }
951
952     /* clear start-up info; use defaults */
953     memset((void *)&startInfo, 0, sizeof(startInfo));
954     startInfo.cb = sizeof(startInfo);
955
956     /* perform the following as a logically atomic unit:
957      *     1) allocate a process table entry
958      *     2) spawn child process (suspended)
959      *     3) create data buffer to pass (optional)
960      *     4) initialize process table entry
961      *     5) start child watcher thread
962      *     6) resume spawned child process
963      */
964
965     (void) pthread_mutex_lock(&procTableLock);
966
967     for (tidx = 0; tidx < PMGT_CHILD_MAX; tidx++) {
968         if (procTable[tidx].p_handle == NULL && 
969             procTable[tidx].p_reserved == FALSE) {
970             procTable[tidx].p_reserved = TRUE;
971             break;
972         }
973     }
974     (void) pthread_mutex_unlock(&procTableLock);
975
976     if (tidx >= PMGT_CHILD_MAX) {
977         /* no space left in process table */
978         free(pathbuf);
979         free(argbuf);
980         free(envbuf);
981
982         errno = EAGAIN;
983         return (pid_t)-1;
984     }
985
986     fsuccess =
987         CreateProcess(pathbuf,     /* executable path */
988                       argbuf,      /* command line argument string */
989                       NULL,        /* default process security attr */
990                       NULL,        /* default thread security attr */
991                       FALSE,       /* do NOT inherit handles */
992                       createFlags, /* creation control flags */
993                       envbuf,      /* environment variable block */
994                       NULL,        /* current directory is that of parent */
995                       &startInfo,  /* startup info block */
996                       &procInfo);
997
998     free(pathbuf);
999     free(argbuf);
1000     free(envbuf);
1001
1002     if (!fsuccess) {
1003         /* failed to spawn process */
1004         errno = nterr_nt2unix(GetLastError(), ENOENT);
1005
1006         (void) pthread_mutex_lock(&procTableLock);
1007         procTable[tidx].p_reserved = FALSE;   /* mark entry as not reserved */
1008         (void) pthread_mutex_unlock(&procTableLock);
1009
1010         return (pid_t)-1;
1011     }
1012
1013     if (passingBuffer) {
1014         /* create named data buffer and read event for child */
1015         fsuccess = CreateChildDataBuffer(procInfo.dwProcessId,
1016                                          sdatap,
1017                                          sdatalen,
1018                                          &bufMemHandle,
1019                                          &bufEventHandle);
1020         if (!fsuccess) {
1021             (void) pthread_mutex_lock(&procTableLock);
1022             procTable[tidx].p_reserved = FALSE;  /* mark entry not reserved */
1023             (void) pthread_mutex_unlock(&procTableLock);
1024
1025             (void) TerminateProcess(procInfo.hProcess,
1026                                     PMGT_SIGSTATUS_ENCODE(SIGKILL));
1027             (void) CloseHandle(procInfo.hThread);
1028             (void) CloseHandle(procInfo.hProcess);
1029
1030             errno = EAGAIN;
1031             return (pid_t)-1;
1032         }
1033     }
1034
1035     (void) pthread_mutex_lock(&procTableLock);
1036
1037     procTable[tidx].p_handle     = procInfo.hProcess;
1038     procTable[tidx].p_id         = procInfo.dwProcessId;
1039     procTable[tidx].p_terminated = FALSE;
1040
1041     procEntryCount++;
1042
1043     /* Note: must hold procTableLock during monitor thread creation so
1044      * that if creation fails we can clean up process table before another
1045      * thread has a chance to see this procTable entry.  Continue to hold
1046      * procTableLock while resuming child process, since the procTable
1047      * entry contains a copy of the child process handle which we might use.
1048      */
1049     monitorHandle =
1050         CreateThread(NULL,                  /* default security attr. */
1051                      0,                     /* default stack size */
1052                      ChildMonitorThread,
1053                      (LPVOID)tidx,          /* thread argument */
1054                      0,                     /* creation flags */
1055                      &monitorId);           /* thread id */
1056
1057     if (monitorHandle == NULL) {
1058         /* failed to start child monitor thread */
1059         procTable[tidx].p_handle   = NULL;   /* invalidate table entry */
1060         procTable[tidx].p_reserved = FALSE;  /* mark entry as not reserved */
1061         procEntryCount--;
1062
1063         (void) pthread_mutex_unlock(&procTableLock);
1064
1065         (void) TerminateProcess(procInfo.hProcess,
1066                                 PMGT_SIGSTATUS_ENCODE(SIGKILL));
1067         (void) CloseHandle(procInfo.hThread);
1068         (void) CloseHandle(procInfo.hProcess);
1069
1070         if (passingBuffer) {
1071             (void) CloseHandle(bufMemHandle);
1072             (void) CloseHandle(bufEventHandle);
1073         }
1074
1075         errno = EAGAIN;
1076         return (pid_t)-1;
1077     }
1078
1079     /* Resume child process, which was created suspended to implement spawn
1080      * atomically.  If resumption fails, which it never should, terminate
1081      * the child process with a status of SIGKILL.  Spawn still succeeds and
1082      * the net result is the same as if the child process received a spurious
1083      * SIGKILL signal; the child monitor thread will then handle this.
1084      */
1085     if (ResumeThread(procInfo.hThread) == DWORD_OF_ONES) {
1086         (void) TerminateProcess(procInfo.hProcess,
1087                                 PMGT_SIGSTATUS_ENCODE(SIGKILL));
1088
1089         if (passingBuffer) {
1090             /* child will never read data buffer */
1091             (void) SetEvent(bufEventHandle);
1092         }
1093     }
1094
1095     (void) pthread_mutex_unlock(&procTableLock);
1096
1097     (void) CloseHandle(procInfo.hThread);
1098     (void) CloseHandle(monitorHandle);
1099
1100     /* After spawn returns, signals can not be sent to the new child process
1101      * until that child initializes its signal-receiving mechanism (assuming
1102      * the child is linked with this library).  Shorten (but sadly don't
1103      * eliminate) this window of opportunity for failure by yielding this
1104      * thread's time slice.
1105      */
1106     (void) SwitchToThread();
1107
1108     /* If passing a data buffer to child, wait until child reads buffer
1109      * before closing handles and thus freeing resources; if don't wait
1110      * then parent can not safely exit immediately after returning from
1111      * this call (hence why wait is not done in a background thread).
1112      */
1113     if (passingBuffer) {
1114         WaitForSingleObject(bufEventHandle, 10000);
1115         /* note: if wait times out, child may not get to read buffer */
1116         (void) CloseHandle(bufMemHandle);
1117         (void) CloseHandle(bufEventHandle);
1118     }
1119
1120     return (pid_t)procInfo.dwProcessId;
1121 }
1122
1123
1124
1125 /*
1126  * pmgt_ProcessWaitPid() -- Wait for child process status; i.e., wait
1127  *     for child to terminate (Unix waitpid() semantics).
1128  *
1129  *     Note: does not support waiting for process in group (i.e., pid
1130  *           equals (pid_t)0 or pid is less than (pid_t)-1.
1131  */
1132 pid_t
1133 pmgt_ProcessWaitPid(pid_t pid,
1134                     int *statusP,
1135                     int options)
1136 {
1137     pid_t rc;
1138     int tidx;
1139     BOOL statusFound = FALSE;
1140     DWORD waitTime;
1141
1142     /* validate arguments */
1143     if (pid < (pid_t)-1 || pid == (pid_t)0) {
1144         errno = EINVAL;
1145         return (pid_t)-1;
1146     }
1147
1148     /* determine how long caller is willing to wait for child */
1149
1150     waitTime = (options & WNOHANG) ? 0 : INFINITE;
1151
1152     /* get child status */
1153
1154     (void) pthread_mutex_lock(&procTableLock);
1155
1156     while (1) {
1157         BOOL waitForChild = FALSE;
1158
1159         if (procEntryCount == 0) {
1160             /* no child processes */
1161             errno = ECHILD;
1162             rc = (pid_t)-1;
1163         } else {
1164             /* determine if status is available for specified child id */
1165
1166             if (pid == (pid_t)-1) {
1167                 /* CASE 1: pid matches any child id */
1168
1169                 if (procTermCount == 0) {
1170                     /* status not available for any child ... */
1171                     if (waitTime == 0) {
1172                         /* ... and caller is not willing to wait */
1173                         rc = (pid_t)0;
1174                     } else {
1175                         /* ... but caller is willing to wait */
1176                         waitForChild = TRUE;
1177                     }
1178                 } else {
1179                     /* status available for some child; locate table entry */
1180                     for (tidx = 0; tidx < PMGT_CHILD_MAX; tidx++) {
1181                         if (procTable[tidx].p_handle != NULL &&
1182                             procTable[tidx].p_terminated == TRUE) {
1183                             statusFound = TRUE;
1184                             break;
1185                         }
1186                     }
1187
1188                     if (!statusFound) {
1189                         /* should never happen; indicates a bug */
1190                         errno = EINTR;  /* plausible lie for failure */
1191                         rc = (pid_t)-1;
1192                     }
1193                 }
1194
1195             } else {
1196                 /* CASE 2: pid must match a specific child id */
1197
1198                 /* locate table entry */
1199                 for (tidx = 0; tidx < PMGT_CHILD_MAX; tidx++) {
1200                     if (procTable[tidx].p_handle != NULL &&
1201                         procTable[tidx].p_id == (DWORD)pid) {
1202                         break;
1203                     }
1204                 }
1205
1206                 if (tidx >= PMGT_CHILD_MAX) {
1207                     /* pid does not match any child id */
1208                     errno = ECHILD;
1209                     rc = (pid_t)-1;
1210                 } else if (procTable[tidx].p_terminated == FALSE) {
1211                     /* status not available for specified child ... */
1212                     if (waitTime == 0) {
1213                         /* ... and caller is not willing to wait */
1214                         rc = (pid_t)0;
1215                     } else {
1216                         /* ... but caller is willing to wait */
1217                         waitForChild = TRUE;
1218                     }
1219                 } else {
1220                     /* status is available for specified child */
1221                     statusFound = TRUE;
1222                 }
1223             }
1224         }
1225
1226         if (waitForChild) {
1227             (void) pthread_cond_wait(&childTermEvent, &procTableLock);
1228         } else {
1229             break;
1230         }
1231     } /* while() */
1232
1233     if (statusFound) {
1234         /* child status available */
1235         if (statusP) {
1236             *statusP = ComputeWaitStatus(procTable[tidx].p_status);
1237         }
1238         rc = (pid_t)procTable[tidx].p_id;
1239
1240         /* clean up process table */
1241         (void) CloseHandle(procTable[tidx].p_handle);
1242         procTable[tidx].p_handle   = NULL;
1243         procTable[tidx].p_reserved = FALSE;
1244
1245         procEntryCount--;
1246         procTermCount--;
1247     }
1248
1249     (void) pthread_mutex_unlock(&procTableLock);
1250     return rc;
1251 }
1252
1253
1254
1255
1256
1257
1258 /* -----------------  General  ---------------- */
1259
1260
1261
1262 /*
1263  * PmgtLibraryInitialize() -- Initialize process management library.
1264  */
1265 static int
1266 PmgtLibraryInitialize(void)
1267 {
1268     int rc, i;
1269     HANDLE sigPipeHandle;
1270     char sigPipeName[sizeof(PMGT_SIGNAL_PIPE_PREFIX) + 20];
1271     HANDLE sigListenerHandle;
1272     DWORD sigListenerId;
1273
1274     /* initialize mutex locks and condition variables */
1275
1276     if ((rc = pthread_mutex_init(&signalTableLock, NULL)) ||
1277         (rc = pthread_mutex_init(&signalBlockLock, NULL)) ||
1278         (rc = pthread_mutex_init(&procTableLock, NULL)) ||
1279         (rc = pthread_cond_init(&childTermEvent, NULL))) {
1280         errno = rc;
1281         return -1;
1282     }
1283
1284     /* initialize signal disposition table */
1285
1286     for (i = 0; i < NSIG; i++) {
1287         if (SignalIsDefined(i)) {
1288             /* initialize to default action for defined signals */
1289             signalTable[i].action.sa_handler = SIG_DFL;
1290             sigemptyset(&signalTable[i].action.sa_mask);
1291             signalTable[i].action.sa_flags = 0;
1292         } else {
1293             /* initialize to ignore for undefined signals */
1294             signalTable[i].action.sa_handler = SIG_IGN;
1295         }
1296     }
1297
1298     /* initialize child process table */
1299
1300     for (i = 0; i < PMGT_CHILD_MAX; i++) {
1301         procTable[i].p_handle = NULL;
1302         procTable[i].p_reserved = FALSE;
1303     }
1304     procEntryCount = 0;
1305     procTermCount = 0;
1306
1307     /* retrieve data buffer passed from parent in spawn, if any */
1308
1309     if (!ReadChildDataBuffer(&pmgt_spawnData, &pmgt_spawnDataLen)) {
1310         pmgt_spawnData = NULL;
1311         pmgt_spawnDataLen = 0;
1312     }
1313
1314     /* create named pipe for delivering signals to this process */
1315
1316     sprintf(sigPipeName, "%s%d",
1317             PMGT_SIGNAL_PIPE_PREFIX, (int)GetCurrentProcessId());
1318
1319     sigPipeHandle =
1320         CreateNamedPipe(sigPipeName,             /* pipe for this process */
1321                         PIPE_ACCESS_DUPLEX |     /* full duplex pipe */
1322                         WRITE_DAC,               /* DACL write access */
1323                         PIPE_TYPE_MESSAGE |      /* message type pipe */
1324                         PIPE_READMODE_MESSAGE |  /* message read-mode */
1325                         PIPE_WAIT,               /* blocking mode */
1326                         1,                       /* max of 1 pipe instance */
1327                         64,                 /* output buffer size (advisory) */
1328                         64,                 /* input buffer size (advisory) */
1329                         1000,               /* 1 sec default client timeout */
1330                         NULL);              /* default security attr. */
1331
1332     if (sigPipeHandle == INVALID_HANDLE_VALUE) {
1333         /* failed to create signal pipe */
1334         errno = nterr_nt2unix(GetLastError(), EIO);
1335         return -1;
1336     }
1337
1338     /* add entry to signal pipe ACL granting local Administrators R/W access */
1339
1340     (void) ObjectDaclEntryAdd(sigPipeHandle,
1341                               SE_KERNEL_OBJECT,
1342                               LocalAdministratorsGroup,
1343                               GENERIC_READ | GENERIC_WRITE,
1344                               GRANT_ACCESS,
1345                               NO_INHERITANCE);
1346
1347     /* start signal pipe listener thread */
1348
1349     sigListenerHandle =
1350         CreateThread(NULL,                    /* default security attr. */
1351                      0,                       /* default stack size */
1352                      RemoteSignalListenerThread,
1353                      (LPVOID)sigPipeHandle,   /* thread argument */
1354                      0,                       /* creation flags */
1355                      &sigListenerId);         /* thread id */
1356
1357     if (sigListenerHandle != NULL) {
1358         /* listener thread started; bump priority */
1359         (void) SetThreadPriority(sigListenerHandle, THREAD_PRIORITY_HIGHEST);
1360         (void) CloseHandle(sigListenerHandle);
1361     } else {
1362         /* failed to start listener thread */
1363         errno = EAGAIN;
1364         (void) CloseHandle(sigPipeHandle);
1365         return -1;
1366     }
1367
1368     /* redirect native NT signals into this process management library */
1369
1370     if (pmgt_RedirectNativeSignals()) {
1371         /* errno set by called function */
1372         return -1;
1373     }
1374
1375     return 0;
1376 }
1377
1378
1379 /*
1380  * DllMain() -- Entry-point function called by the DllMainCRTStartup()
1381  *     function in the MSVC runtime DLL (msvcrt.dll).
1382  *
1383  *     Note: the system serializes calls to this function.
1384  */
1385 BOOL WINAPI
1386 DllMain(HINSTANCE dllInstHandle,  /* instance handle for this DLL module */
1387         DWORD reason,             /* reason function is being called */
1388         LPVOID reserved)          /* reserved for future use */
1389 {
1390     if (reason == DLL_PROCESS_ATTACH) {
1391         /* library is being attached to a process */
1392         if (PmgtLibraryInitialize()) {
1393             /* failed to initialize library */
1394             return FALSE;
1395         }
1396
1397         /* disable thread attach/detach notifications */
1398         (void) DisableThreadLibraryCalls(dllInstHandle);
1399     }
1400
1401     return TRUE;
1402 }