include-afsconfig-before-param-h-20010712
[openafs.git] / src / procmgmt / test / pmgttest.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 /* Test of the process management library */
11
12
13 #include <afsconfig.h>
14 #include <afs/param.h>
15
16 RCSID("$Header$");
17
18 #include <afs/stds.h>
19
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24
25 #ifdef AFS_NT40_ENV
26 #include <windows.h>
27 #include <crtdbg.h>
28 #else
29 #include <math.h>
30 #include <time.h>
31 #include <sys/time.h>
32 extern char **environ;
33 #endif
34
35 #include <afs/procmgmt.h>
36
37
38 /* define constants */
39
40 #define TEST_CHILD_MAX  20  /* max number of active child procs in test */
41
42 #if defined(AFS_NT40_ENV)
43 /* Test for reset of signal() handler (i.e., unreliable signal() behavior).
44  * Note: some Unix systems implement a reliable form of signal(), some
45  *       do not; NT does not.  Only test the NT behavior because we trust
46  *       the Unix implementation.
47  */
48 #define TEST_SIGNAL_RESET
49 #endif
50
51
52 /* define globals */
53
54 static volatile int lastSignalCaught;   /* last signo caught by sig handler */
55 static volatile int chldSignalCaught;   /* SIGCHLD caught by sig handler */
56
57 static pid_t childPid[TEST_CHILD_MAX];  /* pids of active child procs */
58
59 static char spawntestDataBuffer[] = "Four score and seven years ago...";
60
61
62 /* define arguments for child processes
63  *
64  * format:
65  *     argv[0] - exe name
66  *     argv[1] - CHILD_ARG1
67  *     argv[2] - test name
68  *     argv[3...n] - arguments for specified test (argv[2])
69  */
70 #define CHILD_ARG_BAD   255  /* child got bad args for test (exit status) */
71 #define CHILD_EXEC_FAILED   254  /* child failed exec() (Unix only) */
72
73 #define CHILD_ARG1  "cHiLd" /* indicates that proc is a child */
74
75 #define SPAWNTEST_ARG2  "spawntest"   /* spawn test child */
76 #define SPAWNTEST_ARG_MAX 4           /* must match SPAWNTEST_ARG[] count */
77 static char *SPAWNTEST_ARG[] = {"fred and wilma",
78                                     "barney and betty",
79                                     "",  /* test empty string arg */
80                                     "flintstone and rubble"};
81
82 #define SPAWNTEST_ENV_NAME      "PMGT_SPAWNTEST"
83 #define SPAWNTEST_ENV_VALUE     "bambam"
84 #define SPAWNTEST_ENV_SETSTR    SPAWNTEST_ENV_NAME "=" SPAWNTEST_ENV_VALUE
85
86 #define SPAWNBUFTEST_ARG2  "spawnbuftest"  /* spawn with buffer test child */
87
88 #define WAITTEST_ARG2  "waittest"    /* wait test child */
89
90 #define WNOHANGTEST_ARG2  "wnohangtest"    /* wait w/ WNOHANG test child */
91
92 #define SIGNALTEST_ARG2  "signaltest"  /* signal test child */
93
94 #define ABORTTEST_ARG2  "aborttest"  /* abort test child */
95
96
97 /* define utility functions */
98
99 /*
100  * TimedSleep() -- put thread to sleep for specified number of seconds.
101  */
102 #define FOREVER 0xFFFFFFFF
103
104 static void
105 TimedSleep(unsigned sec)
106 {
107 #ifdef AFS_NT40_ENV
108     if (sec == FOREVER) {
109         Sleep(INFINITE);
110     } else {
111         Sleep(sec * 1000);
112     }
113 #else
114     if (sec == FOREVER) {
115         while (1) {
116             select(0, 0, 0, 0, 0);
117         }
118     } else {
119         time_t timeStart = time(NULL);
120         struct timeval sleeptime;
121
122         sleeptime.tv_sec = sec;
123         sleeptime.tv_usec = 0;
124
125         while (1) {
126             if (select(0, 0, 0, 0, &sleeptime) == 0) {
127                 /* timeout */
128                 break;
129             } else {
130                 /* returned for reason other than timeout */
131                 double cumSec = difftime(time(NULL), timeStart);
132                 double remSec = (double)sec - cumSec;
133
134                 if (remSec <= 0.0) {
135                     break;
136                 }
137                 sleeptime.tv_sec = ceil(remSec);
138             }
139         }
140     }
141 #endif
142 }
143
144
145 /*
146  * Bailout() -- cleanup and exit test; parent only.
147  */
148 static void
149 Bailout(void)
150 {
151     int i;
152
153     /* kill any child processes */
154     for (i = 0; i < TEST_CHILD_MAX; i++) {
155         if (childPid[i] > (pid_t)0) {
156             (void) kill(childPid[i], SIGKILL);
157         }
158     }
159
160     printf("\nAbandoning test due to error\n");
161     exit(1);
162 }
163
164
165 /*
166  * ChildTableLookup() -- lookup child in childPid[] table and return index.
167  *
168  * Find specified child, or any child if pid is (pid_t)-1.
169  */
170 static int
171 ChildTableLookup(pid_t pid)
172 {
173     int i;
174
175     for (i = 0; i < TEST_CHILD_MAX; i++) {
176         if ((childPid[i] > (pid_t)0) &&
177             (pid == (pid_t)-1 || childPid[i] == pid)) {
178             break;
179         }
180     }
181
182     if (i >= TEST_CHILD_MAX) {
183         /* not found */
184         i = -1;
185     }
186     return i;
187 }
188
189
190 /*
191  * ChildTableClear() -- clear childPid[] table.
192  */
193 static void
194 ChildTableClear(void)
195 {
196     int i;
197
198     for (i = 0; i < TEST_CHILD_MAX; i++) {
199         childPid[i] = (pid_t)-1;
200     }
201 }
202
203 /*
204  * Signal catching routine.
205  */
206 static void
207 SignalCatcher(int signo)
208 {
209     lastSignalCaught = signo;
210
211     if (signo == SIGCHLD) {
212         chldSignalCaught = 1;
213     }
214 }
215
216
217 /*
218  * Basic API test -- single threaded, no child processes.
219  */
220 static void
221 BasicAPITest(void)
222 {
223     sigset_t sigSet;
224     void (*sigDisp)(int);
225     struct sigaction newAction, oldAction;
226
227     /* clear child pid vector for Bailout() */
228     ChildTableClear();
229
230     printf("\n\nBASIC API TEST: SINGLE THREADED, NO CHILDREN\n\n");
231
232     /* -------------------------------------------------------------- */
233
234     printf("Testing signal set (sigset_t) manipulation functions\n");
235
236     sigemptyset(&sigSet);
237
238     if (sigismember(&sigSet, SIGHUP) ||
239         sigismember(&sigSet, SIGINT) ||
240         sigismember(&sigSet, SIGQUIT) ||
241         sigismember(&sigSet, SIGILL) ||
242         sigismember(&sigSet, SIGABRT) ||
243         sigismember(&sigSet, SIGFPE) ||
244         sigismember(&sigSet, SIGKILL) ||
245         sigismember(&sigSet, SIGSEGV) ||
246         sigismember(&sigSet, SIGTERM) ||
247         sigismember(&sigSet, SIGUSR1) ||
248         sigismember(&sigSet, SIGUSR2) ||
249         sigismember(&sigSet, SIGCHLD) ||
250         sigismember(&sigSet, SIGTSTP)) {
251         printf("sigemptyset() did not clear all defined signals\n");
252         Bailout();
253     }
254
255     sigfillset(&sigSet);
256
257     if (!sigismember(&sigSet, SIGHUP) ||
258         !sigismember(&sigSet, SIGINT) ||
259         !sigismember(&sigSet, SIGQUIT) ||
260         !sigismember(&sigSet, SIGILL) ||
261         !sigismember(&sigSet, SIGABRT) ||
262         !sigismember(&sigSet, SIGFPE) ||
263         !sigismember(&sigSet, SIGKILL) ||
264         !sigismember(&sigSet, SIGSEGV) ||
265         !sigismember(&sigSet, SIGTERM) ||
266         !sigismember(&sigSet, SIGUSR1) ||
267         !sigismember(&sigSet, SIGUSR2) ||
268         !sigismember(&sigSet, SIGCHLD) ||
269         !sigismember(&sigSet, SIGTSTP)) {
270         printf("sigfillset() did not set all defined signals\n");
271         Bailout();
272     }
273
274     sigaddset(&sigSet, SIGUSR1);
275     sigaddset(&sigSet, SIGUSR2);
276     sigaddset(&sigSet, SIGINT);
277
278     if (!sigismember(&sigSet, SIGINT) ||
279         !sigismember(&sigSet, SIGUSR1) ||
280         !sigismember(&sigSet, SIGUSR2)) {
281         printf("sigaddset() did not add defined signal to set\n");
282         Bailout();
283     }
284
285     sigdelset(&sigSet, SIGUSR1);
286     sigdelset(&sigSet, SIGUSR2);
287     sigdelset(&sigSet, SIGINT);
288
289     if (sigismember(&sigSet, SIGINT) ||
290         sigismember(&sigSet, SIGUSR1) ||
291         sigismember(&sigSet, SIGUSR2)) {
292         printf("sigdelset() did not delete defined signal from set\n");
293         Bailout();
294     }
295
296
297     /* -------------------------------------------------------------- */
298
299     printf("Testing signal handler installation (sigaction(), signal())\n");
300
301     newAction.sa_handler = SignalCatcher;
302     sigemptyset(&newAction.sa_mask);
303     newAction.sa_flags = 0;
304
305     errno = 0;
306     if (!sigaction(SIGKILL, &newAction, NULL)) {
307         printf("sigaction() allowed a handler to be set for SIGKILL\n");
308         Bailout();
309     } else if (errno != EINVAL) {
310         printf("sigaction(SIGKILL,...) did not set errno to EINVAL\n");
311         Bailout();
312     }
313
314     errno = 0;
315     if (!sigaction(NSIG, &newAction, NULL)) {
316         printf("sigaction() allowed a handler for an invalid signo\n");
317         Bailout();
318     } else if (errno != EINVAL) {
319         printf("sigaction(NSIG,...) did not set errno to EINVAL\n");
320         Bailout();
321     }
322
323     errno = 0;
324     if (signal(SIGKILL, SignalCatcher) != SIG_ERR) {
325         printf("signal() allowed a handler to be set for SIGKILL\n");
326         Bailout();
327     } else if (errno != EINVAL) {
328         printf("signal(SIGKILL,...) did not set errno to EINVAL\n");
329         Bailout();
330     }
331
332     errno = 0;
333     if (signal(NSIG, SignalCatcher) != SIG_ERR) {
334         printf("signal() allowed a handler to be set for an invalid signo\n");
335         Bailout();
336     } else if (errno != EINVAL) {
337         printf("signal(NSIG,...) did not set errno to EINVAL\n");
338         Bailout();
339     }
340
341     if (sigaction(SIGTERM, &newAction, NULL)) {
342         printf("sigaction() failed to install valid signal handler\n");
343         Bailout();
344     }
345
346     if (sigaction(SIGTERM, NULL, &oldAction)) {
347         printf("sigaction() failed to retrieve old signal handler\n");
348         Bailout();
349     } else if (oldAction.sa_handler != newAction.sa_handler ||
350                oldAction.sa_flags   != newAction.sa_flags) {
351         printf("sigaction() returned incorrect old signal handler values\n");
352         Bailout();
353     }
354
355     if ((sigDisp = signal(SIGTERM, SIG_DFL)) == SIG_ERR) {
356         printf("signal() failed to install valid signal handler\n");
357         Bailout();
358     } else if (sigDisp != newAction.sa_handler) {
359         printf("signal() returned incorrect old signal handler\n");
360         Bailout();
361     }
362
363     if ((sigDisp = signal(SIGTERM, SIG_DFL)) == SIG_ERR) {
364         printf("signal() failed to install valid signal handler (2)\n");
365         Bailout();
366     } else if (sigDisp != SIG_DFL) {
367         printf("signal() returned incorrect old signal handler (2)\n");
368         Bailout();
369     }
370
371     if (sigaction(SIGTERM, NULL, &oldAction)) {
372         printf("sigaction() failed to retrieve old signal handler (2)\n");
373         Bailout();
374     } else if (oldAction.sa_handler != SIG_DFL) {
375         printf("sigaction() returned incorrect old signal handler (2)\n");
376         Bailout();
377     }
378
379
380     /* -------------------------------------------------------------- */
381
382     printf("Testing signal catching (sigaction(), signal(), kill(), raise())\n");
383
384     newAction.sa_handler = SIG_DFL;
385     sigemptyset(&newAction.sa_mask);
386     newAction.sa_flags = 0;
387
388     if (sigaction(SIGCHLD, &newAction, NULL)) {
389         printf("sigaction() failed to install valid signal handler\n");
390         Bailout();
391     }
392
393     if (raise(SIGCHLD)) {
394         printf("raise() failed to send SIGCHLD (errno = %d)\n", errno);
395         Bailout();
396     }
397
398     TimedSleep(1);  /* wait for signal delivery */
399
400     /* if made it here means SIGCHLD was (correctly) ignored */
401
402     newAction.sa_handler = SignalCatcher;
403     sigemptyset(&newAction.sa_mask);
404     newAction.sa_flags = 0;
405
406     if (sigaction(SIGTERM, &newAction, NULL) ||
407         sigaction(SIGUSR1, &newAction, NULL) ||
408         sigaction(SIGUSR2, &newAction, NULL)) {
409         printf("sigaction() failed to install valid signal handler (2)\n");
410         Bailout();
411     }
412
413     lastSignalCaught = NSIG;
414
415     if (raise(SIGTERM)) {
416         printf("raise() failed to send SIGTERM (errno = %d)\n", errno);
417         Bailout();
418     }
419
420     TimedSleep(1);  /* wait for signal delivery */
421
422     if (lastSignalCaught != SIGTERM) {
423         printf("raise() failed to deliver SIGTERM\n");
424         Bailout();
425     }
426
427     if (raise(SIGUSR1)) {
428         printf("raise() failed to send SIGUSR1 (errno = %d)\n", errno);
429         Bailout();
430     }
431
432     TimedSleep(1);  /* wait for signal delivery */
433
434     if (lastSignalCaught != SIGUSR1) {
435         printf("raise() failed to deliver SIGUSR1\n");
436         Bailout();
437     }
438
439     if (raise(SIGUSR2)) {
440         printf("raise() failed to send SIGUSR2 (errno = %d)\n", errno);
441         Bailout();
442     }
443
444     TimedSleep(1);  /* wait for signal delivery */
445
446     if (lastSignalCaught != SIGUSR2) {
447         printf("raise() failed to deliver SIGUSR2\n");
448         Bailout();
449     }
450
451     if (sigaction(SIGTERM, NULL, &oldAction)) {
452         printf("sigaction() failed to retrieve old SIGTERM handler\n");
453         Bailout();
454     } else if (oldAction.sa_handler != newAction.sa_handler ||
455                oldAction.sa_flags   != newAction.sa_flags) {
456         printf("sigaction() returned incorrect old SIGTERM handler values\n");
457         Bailout();
458     }
459
460     if (sigaction(SIGUSR1, NULL, &oldAction)) {
461         printf("sigaction() failed to retrieve old SIGUSR1 handler\n");
462         Bailout();
463     } else if (oldAction.sa_handler != newAction.sa_handler ||
464                oldAction.sa_flags   != newAction.sa_flags) {
465         printf("sigaction() returned incorrect old SIGUSR1 handler values\n");
466         Bailout();
467     }
468
469     if (sigaction(SIGUSR2, NULL, &oldAction)) {
470         printf("sigaction() failed to retrieve old SIGUSR2 handler\n");
471         Bailout();
472     } else if (oldAction.sa_handler != newAction.sa_handler ||
473                oldAction.sa_flags   != newAction.sa_flags) {
474         printf("sigaction() returned incorrect old SIGUSR2 handler values\n");
475         Bailout();
476     }
477
478     if (signal(SIGTERM, SignalCatcher) == SIG_ERR ||
479         signal(SIGUSR1, SignalCatcher) == SIG_ERR ||
480         signal(SIGUSR2, SignalCatcher) == SIG_ERR) {
481         printf("signal() failed to install valid signal handler (3)\n");
482         Bailout();
483     }
484
485     lastSignalCaught = NSIG;
486
487     if (kill(getpid(), SIGTERM)) {
488         printf("kill() failed to send SIGTERM (errno = %d)\n", errno);
489         Bailout();
490     }
491
492     TimedSleep(1);  /* wait for signal delivery */
493
494     if (lastSignalCaught != SIGTERM) {
495         printf("kill() failed to deliver SIGTERM\n");
496         Bailout();
497     }
498
499     if (kill(getpid(), SIGUSR1)) {
500         printf("kill() failed to send SIGUSR1 (errno = %d)\n", errno);
501         Bailout();
502     }
503
504     TimedSleep(1);  /* wait for signal delivery */
505
506     if (lastSignalCaught != SIGUSR1) {
507         printf("kill() failed to deliver SIGUSR1\n");
508         Bailout();
509     }
510
511     if (kill(getpid(), SIGUSR2)) {
512         printf("kill() failed to send SIGUSR2 (errno = %d)\n", errno);
513         Bailout();
514     }
515
516     TimedSleep(1);  /* wait for signal delivery */
517
518     if (lastSignalCaught != SIGUSR2) {
519         printf("kill() failed to deliver SIGUSR2\n");
520         Bailout();
521     }
522
523     if ((sigDisp = signal(SIGTERM, SIG_DFL)) == SIG_ERR) {
524         printf("signal() failed to retrieve old SIGTERM handler\n");
525         Bailout();
526     } else if (sigDisp != SIG_DFL) {
527 #ifdef TEST_SIGNAL_RESET
528         printf("signal() returned incorrect old SIGTERM handler\n");
529         Bailout();
530 #endif
531     }
532
533     if ((sigDisp = signal(SIGUSR1, SIG_DFL)) == SIG_ERR) {
534         printf("signal() failed to retrieve old SIGUSR1 handler\n");
535         Bailout();
536     } else if (sigDisp != SIG_DFL) {
537 #ifdef TEST_SIGNAL_RESET
538         printf("signal() returned incorrect old SIGUSR1 handler\n");
539         Bailout();
540 #endif
541     }
542
543     if ((sigDisp = signal(SIGUSR2, SIG_DFL)) == SIG_ERR) {
544         printf("signal() failed to retrieve old SIGUSR2 handler\n");
545         Bailout();
546     } else if (sigDisp != SIG_DFL) {
547 #ifdef TEST_SIGNAL_RESET
548         printf("signal() returned incorrect old SIGUSR2 handler\n");
549         Bailout();
550 #endif
551     }
552
553     /*
554      * NOTE: not testing effects of sa_mask in sigaction(); the NT process
555      *       management library currently serializes signals (to get Unix
556      *       signal handling semantics on a uniprocessor) so sa_mask is
557      *       effectively ignored (since all signals, except SIGKILL, are
558      *       blocked while a signal handler is running).
559      */
560     printf("\tNOTICE: effectiveness of sigaction()'s sa_mask not tested;\n");
561     printf("\tsee comments in test source\n");
562
563
564
565     /* -------------------------------------------------------------- */
566
567     printf("Testing childless waiting (wait(), waitpid())\n");
568
569     errno = 0;
570     if (waitpid((pid_t)17, NULL, 0) != -1) {
571         printf("waitpid(17,...) with no child did not return -1\n");
572         Bailout();
573     } else if (errno != ECHILD) {
574         printf("waitpid(17,...) with no child did not set errno to ECHILD\n");
575         Bailout();
576     }
577
578     errno = 0;
579     if (waitpid((pid_t)-1, NULL, 0) != -1) {
580         printf("waitpid(-1,...) with no child did not return -1\n");
581         Bailout();
582     } else if (errno != ECHILD) {
583         printf("waitpid(-1,...) with no child did not set errno to ECHILD\n");
584         Bailout();
585     }
586
587     errno = 0;
588     if (wait(NULL) != -1) {
589         printf("wait() with no child did not return -1\n");
590         Bailout();
591     } else if (errno != ECHILD) {
592         printf("wait() with no child did not set errno to ECHILD\n");
593         Bailout();
594     }
595 }
596
597
598
599 /*
600  * Process management test -- single threaded.
601  */
602 static void
603 SingleThreadMgmtTest(char *exeName)
604 {
605     struct sigaction newAction;
606     char *childArgv[SPAWNTEST_ARG_MAX + 10];
607     char childArgStr[50];
608     pid_t waitPid;
609     int waitStatus, waitIdx;
610     int signo;
611     int i, j;
612
613     printf("\n\nPROCESS MANAGEMENT TEST:  SINGLE THREADED\n\n");
614
615     /* -------------------------------------------------------------- */
616
617     printf("Testing child spawning (spawnprocve(), wait(), WIFEXITED(), WEXITSTATUS())\n");
618
619     /* clear child pid vector for Bailout() */
620     ChildTableClear();
621
622     /* Set SIGCHLD handler to SIG_DFL. NOTE: on some Unix systems, setting
623      * SIGCHLD handler to SIG_IGN changes the semantics of wait()/waitpid().
624      */
625     newAction.sa_handler = SIG_DFL;
626     sigfillset(&newAction.sa_mask);
627     newAction.sa_flags = 0;
628
629     if (sigaction(SIGCHLD, &newAction, NULL)) {
630         printf("sigaction() failed to install valid signal handler\n");
631         Bailout();
632     }
633
634     if (putenv(SPAWNTEST_ENV_SETSTR)) {
635         printf("putenv() failed\n");
636         Bailout();
637     }
638
639     childArgv[0] = exeName;
640     childArgv[1] = CHILD_ARG1;
641     childArgv[2] = SPAWNTEST_ARG2;
642
643     for (i = 0; i <= SPAWNTEST_ARG_MAX; i++) {
644         char countBuf[10];
645         sprintf(countBuf, "%d", i);
646
647         childArgv[3] = countBuf;
648
649         for (j = 0; j < i; j++) {
650             childArgv[4 + j] = SPAWNTEST_ARG[j];
651         }
652         childArgv[4 + j] = NULL;
653
654         if (i % 2 == 0) {
655             childPid[1] = spawnprocve(exeName,
656                                       childArgv, environ, CHILD_EXEC_FAILED);
657         } else {
658             childPid[1] = spawnprocv(exeName, childArgv, CHILD_EXEC_FAILED);
659         }
660
661         if (childPid[1] == (pid_t)-1) {
662             printf("spawnprocve(%s,...) failed to start child (errno = %d)\n",
663                    exeName, errno);
664             Bailout();
665         }
666
667         do {
668             waitPid = wait(&waitStatus);
669         } while (waitPid == (pid_t)-1 && errno == EINTR);
670
671         if (waitPid != childPid[1]) {
672             if (waitPid == (pid_t)-1) {
673                 printf("wait() failed getting child status (errno = %d)\n",
674                        errno);
675             } else {
676                 printf("wait() returned wrong pid (expected = %d, got = %d)\n",
677                        (int)childPid[1], (int)waitPid);
678             }
679             Bailout();
680         }
681
682         childPid[1] = (pid_t)-1;  /* clear child pid for Bailout() */
683
684         if (!WIFEXITED(waitStatus)) {
685             printf("WIFEXITED() returned FALSE, expected TRUE\n");
686             Bailout();
687         }
688
689         if (WEXITSTATUS(waitStatus) != i) {
690             if (WEXITSTATUS(waitStatus) == CHILD_ARG_BAD) {
691                 printf("WEXITSTATUS() indicates child got bad args\n");
692             } else if (WEXITSTATUS(waitStatus) == CHILD_EXEC_FAILED) {
693                 printf("WEXITSTATUS() indicates child exec() failed\n");
694             } else {
695                 printf("WEXITSTATUS() returned %d, expected %d\n",
696                        (int)WEXITSTATUS(waitStatus), i);
697             }
698             Bailout();
699         }
700     }
701
702
703     /* -------------------------------------------------------------- */
704
705 #if defined(AFS_NT40_ENV)
706
707     printf("Testing child spawning with data buffer (spawnprocveb(), wait(), WIFEXITED(), WEXITSTATUS())\n");
708
709     /* clear child pid vector for Bailout() */
710     ChildTableClear();
711
712     /* Set SIGCHLD handler to SIG_DFL. NOTE: on some Unix systems, setting
713      * SIGCHLD handler to SIG_IGN changes the semantics of wait()/waitpid().
714      */
715     newAction.sa_handler = SIG_DFL;
716     sigfillset(&newAction.sa_mask);
717     newAction.sa_flags = 0;
718
719     if (sigaction(SIGCHLD, &newAction, NULL)) {
720         printf("sigaction() failed to install valid signal handler\n");
721         Bailout();
722     }
723
724     if (putenv(SPAWNTEST_ENV_SETSTR)) {
725         printf("putenv() failed\n");
726         Bailout();
727     }
728
729     childArgv[0] = exeName;
730     childArgv[1] = CHILD_ARG1;
731     childArgv[2] = SPAWNBUFTEST_ARG2;
732
733     for (i = 0; i <= SPAWNTEST_ARG_MAX; i++) {
734         char countBuf[10];
735         sprintf(countBuf, "%d", i);
736
737         childArgv[3] = countBuf;
738
739         for (j = 0; j < i; j++) {
740             childArgv[4 + j] = SPAWNTEST_ARG[j];
741         }
742         childArgv[4 + j] = NULL;
743
744         childPid[1] =
745             spawnprocveb(exeName,
746                          childArgv, environ,
747                          spawntestDataBuffer, sizeof(spawntestDataBuffer));
748
749         if (childPid[1] == (pid_t)-1) {
750             printf("spawnprocveb(%s,...) failed to start child (errno = %d)\n",
751                    exeName, errno);
752             Bailout();
753         }
754
755         do {
756             waitPid = wait(&waitStatus);
757         } while (waitPid == (pid_t)-1 && errno == EINTR);
758
759         if (waitPid != childPid[1]) {
760             if (waitPid == (pid_t)-1) {
761                 printf("wait() failed getting child status (errno = %d)\n",
762                        errno);
763             } else {
764                 printf("wait() returned wrong pid (expected = %d, got = %d)\n",
765                        (int)childPid[1], (int)waitPid);
766             }
767             Bailout();
768         }
769
770         childPid[1] = (pid_t)-1;  /* clear child pid for Bailout() */
771
772         if (!WIFEXITED(waitStatus)) {
773             printf("WIFEXITED() returned FALSE, expected TRUE\n");
774             Bailout();
775         }
776
777         if (WEXITSTATUS(waitStatus) != i) {
778             if (WEXITSTATUS(waitStatus) == CHILD_ARG_BAD) {
779                 printf("WEXITSTATUS() indicates child got bad args\n");
780             } else {
781                 printf("WEXITSTATUS() returned %d, expected %d\n",
782                        (int)WEXITSTATUS(waitStatus), i);
783             }
784             Bailout();
785         }
786     }
787
788 #endif /* AFS_NT40_ENV */
789
790
791     /* -------------------------------------------------------------- */
792
793     printf("Testing child waiting (spawnprocve(), wait(), waitpid(), sigaction(), WIFEXITED(), WEXITSTATUS())\n");
794
795     /* clear child pid vector for Bailout() */
796     ChildTableClear();
797
798     TimedSleep(3);  /* wait for outstanding SIGCHLD's to get delivered */
799
800     lastSignalCaught = NSIG;
801     chldSignalCaught = 0;
802
803     newAction.sa_handler = SignalCatcher;
804     sigfillset(&newAction.sa_mask);
805     newAction.sa_flags = 0;
806
807     if (sigaction(SIGCHLD, &newAction, NULL)) {
808         printf("sigaction() failed to install valid signal handler\n");
809         Bailout();
810     }
811
812     childArgv[0] = exeName;
813     childArgv[1] = CHILD_ARG1;
814     childArgv[2] = WAITTEST_ARG2;
815     childArgv[3] = childArgStr;
816     childArgv[4] = NULL;
817
818     for (i = 0; i < TEST_CHILD_MAX; i++) {
819         sprintf(childArgStr, "%d", i);
820
821         childPid[i] =
822             spawnprocve(exeName, childArgv, environ, CHILD_EXEC_FAILED);
823
824         if (childPid[i] == (pid_t)-1) {
825             printf("spawnprocve(%s,...) failed to start child (errno = %d)\n",
826                    exeName, errno);
827             Bailout();
828         }
829     }
830
831     for (i = 0; i < TEST_CHILD_MAX; i++) {
832         if (i % 2 == 0) {
833             /* wait() */
834             do {
835                 waitPid = wait(&waitStatus);
836             } while (waitPid == (pid_t)-1 && errno == EINTR);
837
838             if (waitPid == (pid_t)-1) {
839                 printf("wait() failed getting child status (errno = %d)\n",
840                        errno);
841                 Bailout();
842             }
843
844             waitIdx = ChildTableLookup(waitPid);
845
846             if (waitIdx < 0) {
847                 printf("wait() returned unknown pid (%d)\n", (int)waitPid);
848                 Bailout();
849             }
850         } else {
851             /* waitpid() */
852             waitIdx = ChildTableLookup((pid_t)-1);
853
854             if (waitIdx < 0) {
855                 printf("Child table unexpectedly empty\n");
856                 Bailout();
857             }
858
859             do {
860                 waitPid = waitpid(childPid[waitIdx], &waitStatus, 0);
861             } while (waitPid == (pid_t)-1 && errno == EINTR);
862
863             if (waitPid != childPid[waitIdx]) {
864                 if (waitPid == (pid_t)-1) {
865                     printf("waitpid() failed getting status (errno = %d)\n",
866                            errno);
867                 } else {
868                     printf("waitpid() returned wrong pid "
869                            "(expected = %d, got = %d)\n",
870                            (int)childPid[waitIdx], (int)waitPid);
871                 }
872                 Bailout();
873             }
874         }
875
876         childPid[waitIdx] = (pid_t)-1; /* clear child pid for Bailout() */
877
878         if (!WIFEXITED(waitStatus)) {
879             printf("WIFEXITED() returned FALSE, expected TRUE\n");
880             Bailout();
881         }
882
883         if (WEXITSTATUS(waitStatus) != waitIdx) {
884             if (WEXITSTATUS(waitStatus) == CHILD_ARG_BAD) {
885                 printf("WEXITSTATUS() indicates child got bad args\n");
886             } else if (WEXITSTATUS(waitStatus) == CHILD_EXEC_FAILED) {
887                 printf("WEXITSTATUS() indicates child exec() failed\n");
888             } else {
889                 printf("WEXITSTATUS() returned %d, expected %d\n",
890                        (int)WEXITSTATUS(waitStatus), waitIdx);
891             }
892             Bailout();
893         }
894     }
895
896     TimedSleep(3);  /* wait for outstanding SIGCHLD's to get delivered */
897
898     if (!chldSignalCaught) {
899         printf("SIGCHLD never caught (last signo = %d)\n", lastSignalCaught);
900         Bailout();
901     }
902
903
904     /* -------------------------------------------------------------- */
905
906     printf("Testing child waiting with WNOHANG (spawnprocve(), waitpid(), kill())\n");
907
908     /* clear child pid vector for Bailout() */
909     ChildTableClear();
910
911     /* Set SIGCHLD handler to SIG_DFL. NOTE: on some Unix systems, setting
912      * SIGCHLD handler to SIG_IGN changes the semantics of wait()/waitpid().
913      */
914     newAction.sa_handler = SIG_DFL;
915     sigfillset(&newAction.sa_mask);
916     newAction.sa_flags = 0;
917
918     if (sigaction(SIGCHLD, &newAction, NULL)) {
919         printf("sigaction() failed to install valid signal handler\n");
920         Bailout();
921     }
922
923     childArgv[0] = exeName;
924     childArgv[1] = CHILD_ARG1;
925     childArgv[2] = WNOHANGTEST_ARG2;
926     childArgv[3] = NULL;
927
928     childPid[1] = spawnprocve(exeName, childArgv, environ, CHILD_EXEC_FAILED);
929
930     if (childPid[1] == (pid_t)-1) {
931         printf("spawnprocve(%s,...) failed to start child (errno = %d)\n",
932                exeName, errno);
933         Bailout();
934     }
935
936     for (i = 0; i < 20; i++) {
937         do {
938             waitPid = waitpid(childPid[1], &waitStatus, WNOHANG);
939         } while (waitPid == (pid_t)-1 && errno == EINTR);
940
941         if (waitPid != (pid_t)0) {
942             if (waitPid == (pid_t)-1) {
943                 printf("waitpid() failed getting child status (errno = %d)\n",
944                        errno);
945
946             } else {
947                 printf("waitpid() returned unexpected value (%d)\n", waitPid);
948             }
949             Bailout();
950         }
951     }
952
953     TimedSleep(2);  /* wait for child to init signal mechanism (NT only) */
954
955     if (kill(childPid[1], SIGKILL)) {
956         printf("kill() failed to send SIGKILL (errno = %d)\n", errno);
957         Bailout();
958     }
959
960     do {
961         waitPid = waitpid(childPid[1], &waitStatus, 0);
962     } while (waitPid == (pid_t)-1 && errno == EINTR);
963
964     if (waitPid != childPid[1]) {
965         if (waitPid == (pid_t)-1) {
966             printf("waitpid() failed getting child status (errno = %d)\n",
967                    errno);
968         } else {
969             printf("waitpid() returned wrong pid (expected = %d, got = %d)\n",
970                    (int)childPid[1], (int)waitPid);
971         }
972         Bailout();
973     }
974
975     childPid[1] = (pid_t)-1; /* clear child pid for Bailout() */
976
977
978     /* -------------------------------------------------------------- */
979
980     printf("Testing child signaling (spawnprocve(), kill(), waitpid(), sigaction(), WIFSIGNALED(), WTERMSIG())\n");
981
982     /* clear child pid vector for Bailout() */
983     ChildTableClear();
984
985     TimedSleep(3);  /* wait for outstanding SIGCHLD's to get delivered */
986
987     lastSignalCaught = NSIG;
988     chldSignalCaught = 0;
989
990     newAction.sa_handler = SignalCatcher;
991     sigfillset(&newAction.sa_mask);
992     newAction.sa_flags = 0;
993
994     if (sigaction(SIGCHLD, &newAction, NULL)) {
995         printf("sigaction() failed to install valid signal handler\n");
996         Bailout();
997     }
998
999     childArgv[0] = exeName;
1000     childArgv[1] = CHILD_ARG1;
1001     childArgv[2] = SIGNALTEST_ARG2;
1002     childArgv[3] = NULL;
1003
1004     for (i = 0; i < TEST_CHILD_MAX; i++) {
1005         childPid[i] =
1006             spawnprocve(exeName, childArgv, environ, CHILD_EXEC_FAILED);
1007
1008         if (childPid[i] == (pid_t)-1) {
1009             printf("spawnprocve(%s,...) failed to start child (errno = %d)\n",
1010                    exeName, errno);
1011             Bailout();
1012         }
1013     }
1014
1015     TimedSleep(4);  /* wait for children to init signal mechanism (NT only) */
1016
1017     for (i = 0; i < TEST_CHILD_MAX; i++) {
1018         if (i % 3 == 0) {
1019             signo = SIGTERM;
1020         } else if (i % 3 == 1) {
1021             signo = SIGKILL;
1022         } else {
1023             signo = SIGUSR1;
1024         }
1025
1026         if (kill(childPid[i], signo)) {
1027             printf("kill() failed to send signal (errno = %d)\n", errno);
1028             Bailout();
1029         }
1030     }
1031
1032     for (i = 0; i < TEST_CHILD_MAX; i++) {
1033         if (i % 3 == 0) {
1034             signo = SIGTERM;
1035         } else if (i % 3 == 1) {
1036             signo = SIGKILL;
1037         } else {
1038             signo = SIGUSR1;
1039         }
1040
1041         do {
1042             waitPid = waitpid(childPid[i], &waitStatus, 0);
1043         } while (waitPid == (pid_t)-1 && errno == EINTR);
1044
1045         if (waitPid != childPid[i]) {
1046             if (waitPid == (pid_t)-1) {
1047                 printf("waitpid() failed getting child status (errno = %d)\n",
1048                        errno);
1049             } else {
1050                 printf("waitpid() returned wrong pid "
1051                        "(expected = %d, got = %d)\n",
1052                        (int)childPid[i], (int)waitPid);
1053             }
1054             Bailout();
1055         }
1056
1057         childPid[i] = (pid_t)-1; /* clear child pid for Bailout() */
1058
1059         if (!WIFSIGNALED(waitStatus)) {
1060             printf("WIFSIGNALED() returned FALSE, expected TRUE\n");
1061             Bailout();
1062         }
1063
1064         if (WTERMSIG(waitStatus) != signo) {
1065             printf("WTERMSIG() returned %d, expected %d\n",
1066                    (int)WTERMSIG(waitStatus), signo);
1067             Bailout();
1068         }
1069     }
1070
1071     TimedSleep(3);  /* wait for outstanding SIGCHLD's to get delivered */
1072
1073     if (!chldSignalCaught) {
1074         printf("SIGCHLD never caught (last signo = %d)\n", lastSignalCaught);
1075         Bailout();
1076     }
1077
1078     if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
1079         printf("sigaction() failed to install valid signal handler\n");
1080         Bailout();
1081     }
1082
1083
1084     /* -------------------------------------------------------------- */
1085
1086     printf("Testing child aborting (spawnprocve(), waitpid(), WIFSIGNALED(), WTERMSIG())\n");
1087
1088     /* clear child pid vector for Bailout() */
1089     ChildTableClear();
1090
1091     TimedSleep(3);  /* wait for outstanding SIGCHLD's to get delivered */
1092
1093     lastSignalCaught = NSIG;
1094     chldSignalCaught = 0;
1095
1096     newAction.sa_handler = SignalCatcher;
1097     sigfillset(&newAction.sa_mask);
1098     newAction.sa_flags = 0;
1099
1100     if (sigaction(SIGCHLD, &newAction, NULL)) {
1101         printf("sigaction() failed to install valid signal handler\n");
1102         Bailout();
1103     }
1104
1105     childArgv[0] = exeName;
1106     childArgv[1] = CHILD_ARG1;
1107     childArgv[2] = ABORTTEST_ARG2;
1108     childArgv[3] = NULL;
1109
1110     childPid[1] =
1111         spawnprocve(exeName, childArgv, environ, CHILD_EXEC_FAILED);
1112
1113     if (childPid[1] == (pid_t)-1) {
1114         printf("spawnprocve(%s,...) failed to start child (errno = %d)\n",
1115                exeName, errno);
1116         Bailout();
1117     }
1118
1119     TimedSleep(2);  /* wait for child to init signal mechanism (NT only) */
1120
1121     do {
1122         waitPid = waitpid(childPid[1], &waitStatus, 0);
1123     } while (waitPid == (pid_t)-1 && errno == EINTR);
1124
1125     if (waitPid != childPid[1]) {
1126         if (waitPid == (pid_t)-1) {
1127             printf("waitpid() failed getting child status (errno = %d)\n",
1128                    errno);
1129         } else {
1130             printf("waitpid() returned wrong pid (expected = %d, got = %d)\n",
1131                    (int)childPid[1], (int)waitPid);
1132         }
1133         Bailout();
1134     }
1135
1136     childPid[1] = (pid_t)-1; /* clear child pid for Bailout() */
1137
1138     if (!WIFSIGNALED(waitStatus)) {
1139         printf("WIFSIGNALED() returned FALSE, expected TRUE\n");
1140         Bailout();
1141     }
1142
1143     if (WTERMSIG(waitStatus) != SIGABRT) {
1144         printf("WTERMSIG() returned %d, expected SIGABRT (%d)\n",
1145                (int)WTERMSIG(waitStatus), (int)SIGABRT);
1146         Bailout();
1147     }
1148
1149     TimedSleep(3);  /* wait for outstanding SIGCHLD's to get delivered */
1150
1151     if (!chldSignalCaught) {
1152         printf("SIGCHLD never caught (last signo = %d)\n", lastSignalCaught);
1153         Bailout();
1154     }
1155
1156     if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
1157         printf("sigaction() failed to install valid signal handler\n");
1158         Bailout();
1159     }
1160 }
1161
1162
1163
1164 /*
1165  * Parent process behavior.
1166  */
1167 static void
1168 BehaveLikeAParent(int argc, char *argv[])
1169 {
1170     BasicAPITest();
1171     SingleThreadMgmtTest(argv[0]);
1172
1173     printf("\nAll tests completed successfully.\n");
1174 }
1175
1176
1177 /*
1178  * Child process behavior.
1179  */
1180 static void
1181 BehaveLikeAChild(int argc, char *argv[])
1182 {
1183     int argvCount;
1184     char *testName;
1185
1186 #ifdef AFS_NT40_ENV
1187     /* Turn off debug message box used by abort()/assert() in debug
1188      * version of MSVC C run-time library.
1189      */
1190     (void) _CrtSetReportMode(_CRT_WARN, 0);
1191     (void) _CrtSetReportMode(_CRT_ERROR, 0);
1192     (void) _CrtSetReportMode(_CRT_ASSERT, 0);
1193 #endif
1194
1195     /* verify that argc and argv are in sync */
1196     for (argvCount = 0; argv[argvCount]; argvCount++);
1197
1198     if (argc != argvCount) {
1199         exit(CHILD_ARG_BAD);
1200     }
1201
1202     /* verify test argument format */
1203
1204     if (argc < 3) {
1205         /* all tests require at least argv[2] (test name) */
1206         exit(CHILD_ARG_BAD);
1207     }
1208
1209     /* perform as required for particular test */
1210
1211     testName = argv[2];
1212
1213     if (!strcmp(testName, SPAWNTEST_ARG2)) {
1214         /* SPAWN TEST child */
1215         int i;
1216         char *envstr;
1217
1218         if (((envstr = getenv(SPAWNTEST_ENV_NAME)) == NULL) ||
1219             (strcmp(envstr, SPAWNTEST_ENV_VALUE))) {
1220             exit(CHILD_ARG_BAD);
1221         }
1222
1223         if (atoi(argv[3]) != (argc - 4)) {
1224             exit(CHILD_ARG_BAD);
1225         }
1226
1227         for (i = 0; i < argc - 4; i++) {
1228             if (strcmp(argv[4 + i], SPAWNTEST_ARG[i])) {
1229                 exit(CHILD_ARG_BAD);
1230             }
1231         }
1232
1233 #if defined(AFS_NT40_ENV)
1234         if (spawnDatap != NULL || spawnDataLen != 0) {
1235             exit(CHILD_ARG_BAD);
1236         }
1237 #endif
1238         exit(i);
1239
1240
1241 #if defined(AFS_NT40_ENV)
1242     } else if (!strcmp(testName, SPAWNBUFTEST_ARG2)) {
1243         /* SPAWNBUF TEST child */
1244         int i;
1245         char *envstr;
1246
1247         if (((envstr = getenv(SPAWNTEST_ENV_NAME)) == NULL) ||
1248             (strcmp(envstr, SPAWNTEST_ENV_VALUE))) {
1249             exit(CHILD_ARG_BAD);
1250         }
1251
1252         if (atoi(argv[3]) != (argc - 4)) {
1253             exit(CHILD_ARG_BAD);
1254         }
1255
1256         for (i = 0; i < argc - 4; i++) {
1257             if (strcmp(argv[4 + i], SPAWNTEST_ARG[i])) {
1258                 exit(CHILD_ARG_BAD);
1259             }
1260         }
1261
1262         if (spawnDataLen != sizeof(spawntestDataBuffer) ||
1263             strcmp(spawnDatap, spawntestDataBuffer)) {
1264             exit(CHILD_ARG_BAD);
1265         }
1266
1267         exit(i);
1268 #endif /* AFS_NT40_ENV */
1269
1270
1271     } else if (!strcmp(testName, WAITTEST_ARG2)) {
1272         /* WAIT TEST child */
1273         int rc;
1274
1275         if (argc != 4) {
1276             exit(CHILD_ARG_BAD);
1277         }
1278
1279         rc = strtol(argv[3], NULL, 10);
1280
1281         exit(rc);
1282
1283     } else if (!strcmp(testName, WNOHANGTEST_ARG2)) {
1284         /* WNOHANG TEST child */
1285         TimedSleep(FOREVER);
1286         printf("\tchild unexpectedly returned from TimedSleep(FOREVER)\n");
1287         exit(1);  /* should never execute */
1288
1289     } else if (!strcmp(testName, SIGNALTEST_ARG2)) {
1290         /* SIGNAL TEST child */
1291         TimedSleep(FOREVER);
1292         printf("\tchild unexpectedly returned from TimedSleep(FOREVER)\n");
1293         exit(1);  /* should never execute */
1294
1295     } else if (!strcmp(testName, ABORTTEST_ARG2)) {
1296         /* ABORT TEST child */
1297
1298 #ifdef AFS_NT40_ENV
1299         printf("\tNOTICE:\n");
1300         printf("\t\tChild is calling abort().\n");
1301         printf("\t\tAbnormal termination message will appear.\n");
1302         printf("\t\tA software exception dialog will appear; press 'OK'.\n");
1303         printf("\t\tAutomatic debugger invocation MUST be disabled.\n");
1304         fflush(stdout);
1305 #endif
1306         abort();
1307         printf("\tchild unexpectedly returned from abort()\n");
1308         exit(1);  /* should never execute */
1309
1310     } else {
1311         /* UNKNOWN TEST */
1312         exit(CHILD_ARG_BAD);
1313     }
1314 }
1315
1316
1317 /*
1318  * Main function.
1319  */
1320 int main(int argc, char *argv[])
1321 {
1322     if (argc == 1) {
1323         /* PARENT process */
1324         BehaveLikeAParent(argc, argv);
1325     } else if ((argc > 1) && !strcmp(argv[1], CHILD_ARG1)) {
1326         /* CHILD process */
1327         BehaveLikeAChild(argc, argv);
1328     } else {
1329         printf("\nUsage: %s\n", argv[0]);
1330     }
1331
1332     return 0;
1333 }