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