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