[SSI] openssi/regression-tests 1764324-badness-in-sk_del_node_init, NONE, 1.1.2.1 1766275-reop_export_path-harness, NONE, 1.1.2.1 1766275-reop_export_path.c, NONE, 1.1.2.1 1938520-proc-task-crash, NONE, 1.1.2.1 1941808-sem-crash.c, NONE, 1.1.2.1 1944781-shm-crash-harness, NONE, 1.1.2.1 1944781-shm-crash.c, NONE, 1.1.2.1 1964705-O_NOOPEN-crash.c, NONE, 1.1.2.1 1984656-semundo.c, NONE, 1.1.2.1 2000692-exec-crash.c, NONE, 1.1.2.1 2009805-tst-waitid.c, NONE, 1.1.2.1 2010447-tst-atime-harness, NONE, 1.1.2.1 2010447-tst-atime.c, NONE, 1.1.2.1 2010453-tst-basic3.c, NONE, 1.1.2.1 2033804-proc-self-fd-only-32, NONE, 1.1.2.1 2142138-procfs-no-zombies, NONE, 1.1.2.1 Makefile, NONE, 1.1.2.1
John Hughes <[email protected]>
| Newsgroups | gmane.linux.cluster.ssic.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/ssic-linux/openssi/regression-tests
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv15332
Added Files:
Tag: OPENSSI-DEBIAN
1764324-badness-in-sk_del_node_init
1766275-reop_export_path-harness 1766275-reop_export_path.c
1938520-proc-task-crash 1941808-sem-crash.c
1944781-shm-crash-harness 1944781-shm-crash.c
1964705-O_NOOPEN-crash.c 1984656-semundo.c
2000692-exec-crash.c 2009805-tst-waitid.c
2010447-tst-atime-harness 2010447-tst-atime.c
2010453-tst-basic3.c 2033804-proc-self-fd-only-32
2142138-procfs-no-zombies Makefile
Log Message:
Add very simple regression tests
--- NEW FILE: 1766275-reop_export_path.c ---
/*
* OpenSSI bug 1766275 - Can't migrate if remote shm seg open - reop_export_path error
*
* If a process attaches to a remote shm segment then tries to migrate then we
* get "reop_export_path: Can't export unlinked file /SYSV7a6d2001 (deleted)"
* and the migration fails.
*
*/
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int migrate (int node) {
FILE *go;
int where;
if (!(go = fopen ("/proc/self/goto", "w"))) {
return -1;
}
if (fprintf (go, "%d\n", node) <= 0 || fflush (go) == EOF) {
fclose (go);
return -1;
}
fclose (go);
if (!(go = fopen ("/proc/self/where", "r"))) {
return -1;
}
if (fscanf (go, "%d", &where) != 1) {
return -1;
}
fclose (go);
if (where != node) {
fprintf (stderr, "migrate (%d), here = %d\n", node, where);
errno = EREMOTE;
return -1;
}
return 0;
}
int main (int argc, char **argv) {
int key, node;
int id;
char *buf;
if (argc < 3 ||
(key = atoi (argv [1])) <= 0 ||
(node = atoi (argv[2])) <= 0)
{
fprintf (stderr, "Usage: %s key node\n", *argv);
exit (1);
}
/* Create the segment */
if ((id = shmget (key, 4096, IPC_CREAT | 0660)) == -1) {
perror ("shmget");
exit (1);
}
/* Attach to existing segment */
if ((id = shmget (key, 4096, 0)) == -1) {
perror ("shmget");
exit (1);
}
if ((buf = shmat (id, NULL, 0)) == (void *) -1) {
perror ("shmat");
exit (1);
}
/* Attempt to migrate */
if (migrate (node) == -1) {
perror ("migrate");
exit (1);
}
printf ("OK\n");
return 0;
}
--- NEW FILE: 2000692-exec-crash.c ---
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
* OpenSSI bug 2000692 - calling exec from a thread crashes node
*
*/
void *thread (void *info) {
if (execlp ("echo", "echo", "OK", NULL) == -1) {
perror ("execlp");
exit (1);
}
return NULL;
}
int main () {
pthread_t thr;
pthread_attr_t attr;
memset (&attr, 0, sizeof attr);
if (pthread_create (&thr, &attr, thread, NULL) == -1) {
perror ("pthread_create");
exit (1);
}
sleep (10);
return 0;
}
--- NEW FILE: 1964705-O_NOOPEN-crash.c ---
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
/*
* OpenSSI bug 1964705 - User level code can use the O_NOOPEN flag
*
*/
#ifndef O_DIRECTORY
#define O_DIRECTORY 0200000
#endif
#ifndef O_NOOPEN
#define O_NOOPEN 02000000
#endif
int main () {
int fd = open ("/sys", O_RDONLY | O_DIRECTORY | O_NOOPEN);
if (fd == -1) {
perror ("open");
exit (1);
}
return 0;
}
--- NEW FILE: 2010447-tst-atime.c ---
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
/*
* OpenSSI bug 2010447 : OpenSSI fails the glibc tst-atime test
*
* Main problem is that cfs doesn't do atime.
* secondary problem is that we can't work around this using noatime mount
* option because libc statvfs function doesn't realise that our cfs mount
* is actualy a ext3 mount.
*
* Not very serious, just annoying.
*
*/
extern char *stpcpy (char *, const char *);
static int do_test (void);
#define TEST_FUNCTION do_test ()
#define TIMEOUT 5
#define test_dir "/tmp"
static int
do_test (void)
{
char *buf;
int fd;
FILE *fp;
int ch;
struct stat st1;
struct stat st2;
struct statvfs sv;
int e;
buf = (char *) malloc (strlen (test_dir) + sizeof "/tst-atime.XXXXXX");
if (buf == NULL)
{
printf ("cannot allocate memory: %m\n");
return 1;
}
stpcpy (stpcpy (buf, test_dir), "/tst-atime.XXXXXX");
fd = mkstemp (buf);
if (fd == -1)
{
printf ("cannot open temporary file: %m\n");
return 1;
}
#ifdef ST_NOATIME
/* Make sure the filesystem doesn't have the noatime option set. If
statvfs is not available just continue. */
e = fstatvfs (fd, &sv);
if (e != ENOSYS)
{
if (e != 0)
{
printf ("cannot statvfs '%s': %m\n", buf);
return 1;
}
if ((sv.f_flag & ST_NOATIME) != 0)
{
puts ("Bah! The filesystem is mounted with noatime");
return 0;
}
}
#endif
/* Make sure it gets removed. */
//add_temp_file (buf);
if (write (fd, "some string\n", 12) != 12)
{
printf ("cannot write temporary file: %m\n");
return 1;
}
if (lseek (fd, 0, SEEK_SET) == (off_t) -1)
{
printf ("cannot reposition temporary file: %m\n");
return 1;
}
fp = fdopen (fd, "r");
if (fp == NULL)
{
printf ("cannot create stream: %m\n");
return 1;
}
if (fstat (fd, &st1) == -1)
{
printf ("first stat failed: %m\n");
return 1;
}
sleep (2);
ch = fgetc (fp);
if (ch != 's')
{
printf ("did not read correct character: got '%c', expected 's'\n", ch);
return 1;
}
if (fstat (fd, &st2) == -1)
{
printf ("second stat failed: %m\n");
return 1;
}
if (st1.st_atime > st2.st_atime)
{
puts ("second atime smaller");
return 1;
}
else if (st1.st_atime == st2.st_atime)
{
puts ("atime has not changed");
return 1;
}
fclose (fp);
return 0;
}
int main () {
return do_test ();
}
--- NEW FILE: 2009805-tst-waitid.c ---
/* Tests for waitid.
Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
* OpenSSI bug 2009805 - OpenSSI fails glibc tst-waitid test
*
* Symptom of bug:
* SIGCHLD for stopped code 128
* SIGCHLD for stopped status 7
* SIGCHLD for stopped pid 0
* waitid WSTOPPED|WNOHANG returned bogus value 396019
* and non-zero exit.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#define TIMEOUT 15
static void
test_child (void)
{
/* Wait a second to be sure the parent set his variables before we
produce a SIGCHLD. */
sleep (1);
/* First thing, we stop ourselves. */
raise (SIGSTOP);
/* Hey, we got continued! */
while (1)
pause ();
}
#ifndef WEXITED
# define WEXITED 0
# define WCONTINUED 0
# define WSTOPPED WUNTRACED
#endif
static sig_atomic_t expecting_sigchld, spurious_sigchld;
#ifdef SA_SIGINFO
static siginfo_t sigchld_info;
static void
sigchld (int signo, siginfo_t *info, void *ctx)
{
if (signo != SIGCHLD)
{
printf ("SIGCHLD handler got signal %d instead!\n", signo);
_exit (EXIT_FAILURE);
}
if (! expecting_sigchld)
{
spurious_sigchld = 1;
printf ("spurious SIGCHLD: signo %d code %d status %d pid %d\n",
info->si_signo, info->si_code, info->si_status, info->si_pid);
}
else
{
sigchld_info = *info;
expecting_sigchld = 0;
}
}
static void
check_sigchld (const char *phase, int *ok, int code, int status, pid_t pid)
{
if (expecting_sigchld)
{
printf ("missing SIGCHLD on %s\n", phase);
*ok = EXIT_FAILURE;
expecting_sigchld = 0;
return;
}
if (sigchld_info.si_signo != SIGCHLD)
{
printf ("SIGCHLD for %s signal %d\n", phase, sigchld_info.si_signo);
*ok = EXIT_FAILURE;
}
if (sigchld_info.si_code != code)
{
printf ("SIGCHLD for %s code %d\n", phase, sigchld_info.si_code);
*ok = EXIT_FAILURE;
}
if (sigchld_info.si_status != status)
{
printf ("SIGCHLD for %s status %d\n", phase, sigchld_info.si_status);
*ok = EXIT_FAILURE;
}
if (sigchld_info.si_pid != pid)
{
printf ("SIGCHLD for %s pid %d\n", phase, sigchld_info.si_pid);
*ok = EXIT_FAILURE;
}
}
# define CHECK_SIGCHLD(phase, code_check, status_check) \
check_sigchld ((phase), &status, (code_check), (status_check), pid)
#else
# define CHECK_SIGCHLD(phase, code, status) ((void) 0)
#endif
static int
do_test (int argc, char *argv[])
{
#ifdef SA_SIGINFO
struct sigaction sa;
sa.sa_flags = SA_SIGINFO|SA_RESTART;
sa.sa_sigaction = &sigchld;
if (sigemptyset (&sa.sa_mask) < 0 || sigaction (SIGCHLD, &sa, NULL) < 0)
{
printf ("setting SIGCHLD handler: %m\n");
return EXIT_FAILURE;
}
#endif
expecting_sigchld = 1;
pid_t pid = fork ();
if (pid < 0)
{
printf ("fork: %m\n");
return EXIT_FAILURE;
}
else if (pid == 0)
{
test_child ();
_exit (127);
}
int status = EXIT_SUCCESS;
#define RETURN(ok) \
do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
/* Give the child a chance to stop. */
sleep (3);
CHECK_SIGCHLD ("stopped", CLD_STOPPED, SIGSTOP);
/* Now try a wait that should not succeed. */
siginfo_t info;
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
int fail = waitid (P_PID, pid, &info, WEXITED|WCONTINUED|WNOHANG);
switch (fail)
{
default:
printf ("waitid returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WNOHANG on stopped: %m\n");
RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
case 0:
if (info.si_signo == 0)
break;
if (info.si_signo == SIGCHLD)
printf ("waitid WNOHANG on stopped status %d\n", info.si_status);
else
printf ("waitid WNOHANG on stopped signal %d\n", info.si_signo);
RETURN (EXIT_FAILURE);
}
/* Next the wait that should succeed right away. */
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
info.si_pid = -1;
info.si_status = -1;
fail = waitid (P_PID, pid, &info, WSTOPPED|WNOHANG);
switch (fail)
{
default:
printf ("waitid WSTOPPED|WNOHANG returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WSTOPPED|WNOHANG on stopped: %m\n");
RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
case 0:
if (info.si_signo != SIGCHLD)
{
printf ("waitid WSTOPPED|WNOHANG on stopped signal %d\n",
info.si_signo);
RETURN (EXIT_FAILURE);
}
if (info.si_code != CLD_STOPPED)
{
printf ("waitid WSTOPPED|WNOHANG on stopped code %d\n",
info.si_code);
RETURN (EXIT_FAILURE);
}
if (info.si_status != SIGSTOP)
{
printf ("waitid WSTOPPED|WNOHANG on stopped status %d\n",
info.si_status);
RETURN (EXIT_FAILURE);
}
if (info.si_pid != pid)
{
printf ("waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
info.si_pid, pid);
RETURN (EXIT_FAILURE);
}
}
expecting_sigchld = WCONTINUED != 0;
if (kill (pid, SIGCONT) != 0)
{
printf ("kill (%d, SIGCONT): %m\n", pid);
RETURN (EXIT_FAILURE);
}
/* Wait for the child to have continued. */
sleep (2);
#if WCONTINUED != 0
if (expecting_sigchld)
{
printf ("no SIGCHLD seen for SIGCONT (optional)\n");
expecting_sigchld = 0;
}
else
CHECK_SIGCHLD ("continued", CLD_CONTINUED, SIGCONT);
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
info.si_pid = -1;
info.si_status = -1;
fail = waitid (P_PID, pid, &info, WCONTINUED|WNOWAIT);
switch (fail)
{
default:
printf ("waitid WCONTINUED|WNOWAIT returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WCONTINUED|WNOWAIT on continued: %m\n");
RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
case 0:
if (info.si_signo != SIGCHLD)
{
printf ("waitid WCONTINUED|WNOWAIT on continued signal %d\n",
info.si_signo);
RETURN (EXIT_FAILURE);
}
if (info.si_code != CLD_CONTINUED)
{
printf ("waitid WCONTINUED|WNOWAIT on continued code %d\n",
info.si_code);
RETURN (EXIT_FAILURE);
}
if (info.si_status != SIGCONT)
{
printf ("waitid WCONTINUED|WNOWAIT on continued status %d\n",
info.si_status);
RETURN (EXIT_FAILURE);
}
if (info.si_pid != pid)
{
printf ("waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
info.si_pid, pid);
RETURN (EXIT_FAILURE);
}
}
/* That should leave the CLD_CONTINUED state waiting to be seen again. */
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
info.si_pid = -1;
info.si_status = -1;
fail = waitid (P_PID, pid, &info, WCONTINUED);
switch (fail)
{
default:
printf ("waitid WCONTINUED returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WCONTINUED on continued: %m\n");
RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
case 0:
if (info.si_signo != SIGCHLD)
{
printf ("waitid WCONTINUED on continued signal %d\n", info.si_signo);
RETURN (EXIT_FAILURE);
}
if (info.si_code != CLD_CONTINUED)
{
printf ("waitid WCONTINUED on continued code %d\n", info.si_code);
RETURN (EXIT_FAILURE);
}
if (info.si_status != SIGCONT)
{
printf ("waitid WCONTINUED on continued status %d\n",
info.si_status);
RETURN (EXIT_FAILURE);
}
if (info.si_pid != pid)
{
printf ("waitid WCONTINUED on continued pid %d != %d\n",
info.si_pid, pid);
RETURN (EXIT_FAILURE);
}
}
/* Now try a wait that should not succeed. */
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
fail = waitid (P_PID, pid, &info, WCONTINUED|WNOHANG);
switch (fail)
{
default:
printf ("waitid returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WCONTINUED|WNOHANG on waited continued: %m\n");
RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
case 0:
if (info.si_signo == 0)
break;
if (info.si_signo == SIGCHLD)
printf ("waitid WCONTINUED|WNOHANG on waited continued status %d\n",
info.si_status);
else
printf ("waitid WCONTINUED|WNOHANG on waited continued signal %d\n",
info.si_signo);
RETURN (EXIT_FAILURE);
}
/* Now stop him again and test waitpid with WCONTINUED. */
expecting_sigchld = 1;
if (kill (pid, SIGSTOP) != 0)
{
printf ("kill (%d, SIGSTOP): %m\n", pid);
RETURN (EXIT_FAILURE);
}
pid_t wpid = waitpid (pid, &fail, WUNTRACED);
if (wpid < 0)
{
printf ("waitpid WUNTRACED on stopped: %m\n");
RETURN (EXIT_FAILURE);
}
else if (wpid != pid)
{
printf ("waitpid WUNTRACED on stopped returned %d != %d (status %x)\n",
wpid, pid, fail);
RETURN (EXIT_FAILURE);
}
else if (!WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
|| WIFCONTINUED (fail) || WSTOPSIG (fail) != SIGSTOP)
{
printf ("waitpid WUNTRACED on stopped: status %x\n", fail);
RETURN (EXIT_FAILURE);
}
CHECK_SIGCHLD ("stopped", CLD_STOPPED, SIGSTOP);
expecting_sigchld = 1;
if (kill (pid, SIGCONT) != 0)
{
printf ("kill (%d, SIGCONT): %m\n", pid);
RETURN (EXIT_FAILURE);
}
/* Wait for the child to have continued. */
sleep (2);
if (expecting_sigchld)
{
printf ("no SIGCHLD seen for SIGCONT (optional)\n");
expecting_sigchld = 0;
}
else
CHECK_SIGCHLD ("continued", CLD_CONTINUED, SIGCONT);
wpid = waitpid (pid, &fail, WCONTINUED);
if (wpid < 0)
{
if (errno == EINVAL)
printf ("waitpid does not support WCONTINUED\n");
else
{
printf ("waitpid WCONTINUED on continued: %m\n");
RETURN (EXIT_FAILURE);
}
}
else if (wpid != pid)
{
printf ("\
waitpid WCONTINUED on continued returned %d != %d (status %x)\n",
wpid, pid, fail);
RETURN (EXIT_FAILURE);
}
else if (WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
|| !WIFCONTINUED (fail))
{
printf ("waitpid WCONTINUED on continued: status %x\n", fail);
RETURN (EXIT_FAILURE);
}
#endif
expecting_sigchld = 1;
/* Die, child, die! */
if (kill (pid, SIGKILL) != 0)
{
printf ("kill (%d, SIGKILL): %m\n", pid);
RETURN (EXIT_FAILURE);
}
#ifdef WNOWAIT
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
info.si_pid = -1;
info.si_status = -1;
fail = waitid (P_PID, pid, &info, WEXITED|WNOWAIT);
switch (fail)
{
default:
printf ("waitid WNOWAIT returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WNOWAIT on killed: %m\n");
RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
case 0:
if (info.si_signo != SIGCHLD)
{
printf ("waitid WNOWAIT on killed signal %d\n", info.si_signo);
RETURN (EXIT_FAILURE);
}
if (info.si_code != CLD_KILLED)
{
printf ("waitid WNOWAIT on killed code %d\n", info.si_code);
RETURN (EXIT_FAILURE);
}
if (info.si_status != SIGKILL)
{
printf ("waitid WNOWAIT on killed status %d\n", info.si_status);
RETURN (EXIT_FAILURE);
}
if (info.si_pid != pid)
{
printf ("waitid WNOWAIT on killed pid %d != %d\n", info.si_pid, pid);
RETURN (EXIT_FAILURE);
}
}
#else
/* Allow enough time to be sure the child died; we didn't synchronize. */
sleep (2);
#endif
CHECK_SIGCHLD ("killed", CLD_KILLED, SIGKILL);
info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
info.si_pid = -1;
info.si_status = -1;
fail = waitid (P_PID, pid, &info, WEXITED|WNOHANG);
switch (fail)
{
default:
printf ("waitid WNOHANG returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
case -1:
printf ("waitid WNOHANG on killed: %m\n");
RETURN (EXIT_FAILURE);
case 0:
if (info.si_signo != SIGCHLD)
{
printf ("waitid WNOHANG on killed signal %d\n", info.si_signo);
RETURN (EXIT_FAILURE);
}
if (info.si_code != CLD_KILLED)
{
printf ("waitid WNOHANG on killed code %d\n", info.si_code);
RETURN (EXIT_FAILURE);
}
if (info.si_status != SIGKILL)
{
printf ("waitid WNOHANG on killed status %d\n", info.si_status);
RETURN (EXIT_FAILURE);
}
if (info.si_pid != pid)
{
printf ("waitid WNOHANG on killed pid %d != %d\n", info.si_pid, pid);
RETURN (EXIT_FAILURE);
}
}
fail = waitid (P_PID, pid, &info, WEXITED);
if (fail == -1)
{
if (errno != ECHILD)
{
printf ("waitid WEXITED on killed: %m\n");
RETURN (EXIT_FAILURE);
}
}
else
{
printf ("waitid WEXITED returned bogus value %d\n", fail);
RETURN (EXIT_FAILURE);
}
#undef RETURN
out:
if (spurious_sigchld)
status = EXIT_FAILURE;
signal (SIGCHLD, SIG_IGN);
kill (pid, SIGKILL); /* Make sure it's dead if we bailed early. */
return status;
}
#if 1
int main (int argc, char **argv) {
return do_test (argc, argv);
}
#else
#include "../test-skeleton.c"
#endif
--- NEW FILE: 1941808-sem-crash.c ---
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
/* OpenSSI 1941808 - semundo structures confused
*
* Ok, here's the bug:
*
* Someone creates a semaphore
*
* Process (A) operates on it, creating a sem_undo structure for itself (on
* it's own node) and a sem_semundo for the semaphore (on the semaphore's
* node).
*
* Process (B), (where A != B) removes the semaphore, cleaning up the
* sem_semundo for the semaphore, BUT NOT THE sem_undo for process A.
*
* Someone creates a new semaphore that happens to get the same index (but a
* different sequence) from the original semaphore.
* Process (A) exits - when we try to clean up its sem_undo structure
* sem_checkid fails because the sequence numbers don't match.
*
* (fix is that sem_checkid fail indicates stale sem_undo list, not bug)
*
*/
int debug = 0;
int make_sem () {
int id;
if (debug) fprintf (stderr, "Make sem\n");
if ((id = semget(0x12345, 1, IPC_CREAT | 0660)) < 0) {
perror ("semget");
exit (1);
}
if (debug) fprintf (stderr, "sem = %d\n", id);
return id;
}
void do_semop (int id, int op, int flag) {
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = op;
buf.sem_flg = flag;
if (semop (id, &buf, 1) == -1) {
perror ("semop");
exit (1);
}
}
void up (int id) {
if (debug) fprintf (stderr, "up %d\n", id);
do_semop (id, 1, SEM_UNDO);
}
void zap (int id) {
if (debug) fprintf (stderr, "remove %d\n", id);
if (semctl (id, 0, IPC_RMID) == -1) {
perror ("semctl");
exit (1);
}
}
int main (int argc, char **argv) {
int id;
int pid;
struct sembuf semops;
if (argc > 1 && strcmp (argv [1], "debug") == 0) ++debug;
id = make_sem ();
if ((pid = fork ()) == -1) {
perror ("fork");
exit (1);
}
if (pid) {
/* Process (A) */
up (id); /* Make sem_undo and sem_semundo */
sleep (10);
id = make_sem (); /* make new sem with same key */
}
else {
/* Process (B) */
sleep (5);
zap (id); /* cleanum sem_semundo */
exit (0);
}
printf ("OK?\n");
return 0;
}
--- NEW FILE: Makefile ---
TESTS = \
1764324-badness-in-sk_del_node_init \
1766275-reop_export_path \
1938520-proc-task-crash \
1941808-sem-crash \
1944781-shm-crash \
1964705-O_NOOPEN-crash \
1984656-semundo \
2000692-exec-crash \
2009805-tst-waitid \
2010447-tst-atime \
2010453-tst-basic3 \
2033804-proc-self-fd-only-32 \
2142138-procfs-no-zombies \
# Not all tests need pthread, fix for later
CFLAGS = -pthread
all: $(TESTS)
@rm -f zz-failed
@for test in $(TESTS) ; \
do echo -n $${test} ... ; \
if [ -f $${test}-harness ]; then \
if ./$${test}-harness >/dev/null 2>&1; \
then echo "OK" ; \
else echo $${test} >> zz-failed ; \
echo "FAILED" ; \
fi ; \
else \
if ./$${test} >/dev/null 2>&1 ; \
then echo "OK" ; \
else echo $${test} >> zz-failed ; \
echo "FAILED" ; \
fi ; \
fi ; \
done
@if [ -f zz-failed ]; \
then exit 1 ; \
fi
clean:
for prog in $(TESTS) ; \
do if [ -f $${prog}.c ]; then rm -f $${prog}; fi; \
done
rm -f zz-failed socket
--- NEW FILE: 1984656-semundo.c ---
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <pthread.h>
#include <sys/wait.h>
/*
* OpenSSI bug 1984656 - semaphore undo count sometimes screws up
*
* On old versions of OpenSSI the semundo list wasn't shared between
* threads.
*
*/
void *thread (void *info) {
struct sembuf sembuf;
int semid = *(int *)info;
sembuf.sem_num = 0;
sembuf.sem_op = 1;
sembuf.sem_flg = SEM_UNDO;
if (semop (semid, &sembuf, 1) == 1) {
perror ("semop");
exit (1);
}
return NULL;
}
int main () {
int status;
int pid;
int semid = semget (IPC_PRIVATE, 1, IPC_CREAT|0660);
if (semid == -1) {
perror ("semget");
exit (1);
}
if ((pid = fork ()) == -1) {
perror("fork");
exit (1);
}
if (!pid) {
/* We're the kiddy */
int i;
pthread_t thr;
pthread_attr_t attr;
memset (&attr, 0, sizeof attr);
for (i = 0; i < 10; ++i) {
if (pthread_create (&thr, &attr, thread, &semid) == -1)
{
perror ("pthread_create");
exit (1);
}
if (pthread_join (thr, NULL) == -1) {
perror ("pthread_join");
exit (1);
}
}
exit (0);
}
wait (&status);
if (status) exit (1);
if ((status = semctl (semid, 0, GETVAL)) == -1) {
perror ("GETVAL");
exit (1);
}
if (semctl(semid, 0, IPC_RMID) == -1) {
perror ("IPC_RMID");
exit (1);
}
if (status) {
fprintf (stderr, "val = %d (expect 0)\n", status);
exit (1);
}
printf ("OK\n");
return 0;
}
--- NEW FILE: 1764324-badness-in-sk_del_node_init ---
#! /usr/bin/perl
# OpenSSI bug 1764324 - Badness in sk_del_node_init at include/net/sock.h:343
#
# Can reproduce this by, on one node run script that waits for connection
# then exits, on another node script thet connects to server; waits a bit;
# then exits. If server exits before client get oops.
use Socket;
my $DEBUG = 1;
my $SERVER = 'socket';
my $SERVER_ADDR = pack_sockaddr_un $SERVER;
unlink $SERVER;
# Find a node
my $HERE = `clusternode_num`;
chomp $HERE;
my ($NODE) = grep { /\d+/ && $_ ne $HERE } split / /, `cluster`;
die "Need more than one node\n" unless $NODE;
if (my $pid = fork ()) {
# I'm the client, wait for the server to start
sleep 5;
socket CLIENT, PF_UNIX, SOCK_STREAM, 0
or die "Can't create socket: $!\n";
connect CLIENT, $SERVER_ADDR
or die "Can't connect to $name: $!\n";
print "Client connected to server\n" if $DEBUG;
sleep 10;
print "Client exits\n" if $DEBUG;
}
else {
# I'm the server; move to another node
# and wait for a call from the client
open GOTO, ">/proc/self/goto"
or die "Can't open /proc/self/goto: $!\n";
print GOTO $NODE, "\n";
close GOTO;
open WHERE, "/proc/self/where"
or die "Can't open /proc/self/whereL !$\n";
$HERE = <WHERE>;
close WHERE;
chomp $HERE;
if ($HERE != $NODE) {
die "Can't migrate to $NODE\n";
}
socket SERVER, PF_UNIX, SOCK_STREAM, 0
or die "Can't create socket: $!\n";
bind SERVER, $SERVER_ADDR,
or die "Can't bind socket: $!\n";
listen SERVER, 1
or die "Can't set socket for listening: $!\n";
print "Server running on node $NODE\n" if $DEBUG;
accept INCOMING, SERVER
or die "Can't accept: $!\n";
print "Server accepted call\n" if $DEBUG;
# Server done, bye bye
print "Server exits\n" if $DEBUG;
}
--- NEW FILE: 2033804-proc-self-fd-only-32 ---
#! /usr/bin/perl
# 2033804 - On OpenSSI /proc/$$/fd only shows 1st 32 open FD's
my @FH;
my %FD;
for (1..100) {
open "FH$_", "/dev/null"
or die "open FH$_: $!\n";
$FH[fileno "FH$_"] = "FH$_";
$FD{"FH$_"} = fileno "FH$_";
}
opendir FD, "/proc/self/fd"
or die "Can't open /proc/self/fd: $!";
my $FOUND;
while (my $fd = readdir FD) {
++$FOUND{$fd};
}
closedir FD;
while (my ($fh, $fd) = each %FD) {
die "Can't find open $fd\n" unless $FOUND {$fd};
}
print "OK\n";
exit 0;
--- NEW FILE: 1944781-shm-crash.c ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main (int argc, char **argv) {
int key;
int delay;
int seg;
char *shared;
int debug = 0;
if (argc < 3 ||
(key = atoi (argv[1])) <= 0 ||
(delay = atoi (argv[2])) <= 0)
{
fprintf (stderr, "Usage: %s key delay [ debug ]\n", *argv);
exit (1);
}
if (argc > 3 && strcmp (argv[3], "debug") == 0) ++debug;
if (debug) printf ("key = %d, delay = %d\n", key, delay);
if ((seg = shmget (key, 4096, IPC_CREAT | 0666)) == -1) {
perror ("shmget");
exit (1);
}
if (debug) printf ("Seg %x found\n", seg);
if ((shared = shmat (seg, NULL, 0)) == (void *) -1) {
perror ("shmat");
exit (1);
}
if (debug) printf ("Seg %x attached\n", seg);
sleep (delay);
if (debug) printf ("Destroying seg %x\n", seg);
if (shmctl (seg, IPC_RMID, NULL) == -1) {
perror ("shmctl IPC_RMID");
exit (1);
}
if (debug) printf ("Seg %x destroyed\n", seg);
printf ("OK\n");
return 0;
}
--- NEW FILE: 1938520-proc-task-crash ---
#! /bin/sh
# OpenSSI bug 1938520 - onnode 2 ls /proc/$$/task/1 causes oops
#
# Any attempt to do stat ("/proc/pid1/task/pid2") where pid2 is not pid1 and
# pid2 is not on the node doing the stat causes the oops.
INITNODE=`where_pid 1`
for node in `cluster`
do
if [ $node != $INITNODE ];
then
onnode $node sh -c 'test -f /proc/$$/task/1 || true'
if [ $? != 0 ]; then exit 1; fi
echo OK
exit 0
fi
done
echo "Need more than one node" >&2
exit 1
--- NEW FILE: 1944781-shm-crash-harness ---
#! /bin/sh
DEBUG=
if [ "$1" = "debug" ]; then DEBUG=debug; fi
KEY=83882
set `cluster`
if [ $# -lt 2 ]; then
echo "Need more than 1 node in cluster" >&2
exit 1
fi
onnode $1 ./1944781-shm-crash $KEY 5 $DEBUG &
sleep 1;
onnode $2 ./1944781-shm-crash $KEY 10 $DEBUG
--- NEW FILE: 1766275-reop_export_path-harness ---
#! /bin/sh
HERE=`clusternode_num`
KEY=123
for node in `cluster`
do
if [ $node != $HERE ]; then
if ./1766275-reop_export_path $KEY $node
then
exit 0
else
exit 1
fi
fi
done
echo "Need more than one node" >&2
exit 1
--- NEW FILE: 2142138-procfs-no-zombies ---
#! /usr/bin/perl
# Bug 2142138 procfs not showing zombies 2008-10-02 rogertsang
use Errno qw (ENOENT);
use POSIX qw (_exit);
# Avoid wait for child on exit:
$SIG {__DIE__} = sub {
print STDERR @_;
_exit (1);
};
if (open CHILD, "-|" ) {
my $grandchild = <CHILD>;
chomp $grandchild;
my $zombie;
for (1..60) {
sleep 1;
unless (open STAT, "/proc/$grandchild/stat") {
if ($! == ENOENT) {
die "$grandchild vanished!\n";
}
die "open $grandchild status error : $!\n";
}
my @STAT = split / /, <STAT>;
close STAT;
# print "$STAT[0] $STAT[1] $STAT[2]\n";
# system "ps -fp $grandchild";
# Symptom of the bug, when the process becomes a zombie we
# can't read it's /proc/xxx directory
if ($STAT[2] eq 'Z') {
opendir GRANDCHILD, "/proc/$grandchild"
or die "Can't opendir /proc/$grandchild: $!\n";
while (my $file = readdir GRANDCHILD) {
next unless $file eq 'stat';
print "OK\n";
_exit 0;
}
die "Can't find /proc/$grandchild/stat\n";
}
}
die "$grandchild never became zombie\n";
}
else {
if (my $grandchild = fork ()) {
$| = 1;
print $grandchild, "\n";
sleep 120; # Avoid wait for grandchild
}
else {
sleep 5;
exit (0);
}
}
--- NEW FILE: 2010447-tst-atime-harness ---
#! /bin/sh
if ./2010447-tst-atime
then
: well, sometimes it seems to work!
else
:
fi
echo OK
exit 0
--- NEW FILE: 2010453-tst-basic3.c ---
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <[email protected]>, 2003.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
* OpenSSI bug 2010453 - OpenSSI fails the glibc tst-basic3 test
*
* Should finish with "final_test has been called", bug causes
* "Expected signal 'User defined signal 1' from child, got none"
* and nonzero exit
*/
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern char *stpcpy (char *, const char *);
static int nrunning = 1;
static void
final_test (void)
{
puts ("final_test has been called");
#define THE_SIGNAL SIGUSR1
kill (getpid (), SIGUSR1);
}
static void *
tf (void *a)
{
if (pthread_join ((pthread_t) a, NULL) != 0)
{
printf ("join failed while %d are running\n", nrunning);
_exit (1);
}
printf ("%2d left\n", --nrunning);
return NULL;
}
int
do_test (void)
{
#define N 20
pthread_t t[N];
pthread_t last = pthread_self ();
int i;
atexit (final_test);
printf ("starting %d + 1 threads\n", N);
for (i = 0; i < N; ++i)
{
if (pthread_create (&t[i], NULL, tf, (void *) last) != 0)
{
puts ("create failed");
_exit (1);
}
++nrunning;
last = t[i];
}
printf ("%2d left\n", --nrunning);
pthread_exit (NULL);
}
#define EXPECTED_SIGNAL THE_SIGNAL
#define TEST_FUNCTION do_test ()
/* Skeleton for test programs.
Copyright (C) 1998,2000-2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <[email protected]>, 1998.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
#include <search.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <time.h>
/* The test function is normally called `do_test' and it is called
with argc and argv as the arguments. We nevertheless provide the
possibility to overwrite this name. */
#ifndef TEST_FUNCTION
# define TEST_FUNCTION do_test (argc, argv)
#endif
#ifndef TEST_DATA_LIMIT
# define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with. */
#endif
#define OPT_DIRECT 1000
#define OPT_TESTDIR 1001
static struct option options[] =
{
#ifdef CMDLINE_OPTIONS
CMDLINE_OPTIONS
#endif
{ "direct", no_argument, NULL, OPT_DIRECT },
{ "test-dir", required_argument, NULL, OPT_TESTDIR },
{ NULL, 0, NULL, 0 }
};
/* PID of the test itself. */
static pid_t pid;
/* Directory to place temporary files in. */
static const char *test_dir;
#if 0
/* List of temporary files. */
struct temp_name_list
{
struct qelem q;
const char *name;
} *temp_name_list;
#endif
/* Add temporary files in list. */
static void
__attribute__ ((unused))
add_temp_file (const char *name)
{
#if 0
struct temp_name_list *newp
= (struct temp_name_list *) calloc (sizeof (*newp), 1);
if (newp != NULL)
{
newp->name = name;
if (temp_name_list == NULL)
temp_name_list = (struct temp_name_list *) &newp->q;
else
insque (newp, temp_name_list);
}
#endif
}
/* Delete all temporary files. */
static void
delete_temp_files (void)
{
#if 0
while (temp_name_list != NULL)
{
remove (temp_name_list->name);
temp_name_list = (struct temp_name_list *) temp_name_list->q.q_forw;
}
#endif
}
/* Create a temporary file. */
static int
__attribute__ ((unused))
create_temp_file (const char *base, char **filename)
{
char *fname;
int fd;
fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base)
+ sizeof ("XXXXXX"));
if (fname == NULL)
{
puts ("out of memory");
return -1;
}
strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
fd = mkstemp (fname);
if (fd == -1)
{
printf ("cannot open temporary file '%s': %m\n", fname);
free (fname);
return -1;
}
add_temp_file (fname);
if (filename != NULL)
*filename = fname;
return fd;
}
/* Timeout handler. We kill the child and exit with an error. */
static void
__attribute__ ((noreturn))
timeout_handler (int sig __attribute__ ((unused)))
{
int killed;
int status;
/* Send signal. */
kill (pid, SIGKILL);
/* Wait for it to terminate. */
int i;
for (i = 0; i < 5; ++i)
{
killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
if (killed != 0)
break;
/* Delay, give the system time to process the kill. If the
nanosleep() call return prematurely, all the better. We
won't restart it since this probably means the child process
finally died. */
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
nanosleep (&ts, NULL);
}
if (killed != 0 && killed != pid)
{
perror ("Failed to kill test process");
exit (1);
}
#ifdef CLEANUP_HANDLER
CLEANUP_HANDLER;
#endif
/* If we expected this signal: good! */
#ifdef EXPECTED_SIGNAL
if (EXPECTED_SIGNAL == SIGALRM)
exit (0);
#endif
if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
fputs ("Timed out: killed the child process\n", stderr);
else if (WIFSTOPPED (status))
fprintf (stderr, "Timed out: the child process was %s\n",
strsignal (WSTOPSIG (status)));
else if (WIFSIGNALED (status))
fprintf (stderr, "Timed out: the child process got signal %s\n",
strsignal (WTERMSIG (status)));
else
fprintf (stderr, "Timed out: killed the child process but it exited %d\n",
WEXITSTATUS (status));
/* Exit with an error. */
exit (1);
}
/* We provide the entry point here. */
int
main (int argc, char *argv[])
{
int direct = 0; /* Directly call the test function? */
int status;
int opt;
unsigned int timeoutfactor = 1;
pid_t termpid;
#ifdef M_PERTURB
/* Make uses of freed and uninitialized memory known. */
mallopt (M_PERTURB, 42);
#endif
#ifdef STDOUT_UNBUFFERED
setbuf (stdout, NULL);
#endif
while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
switch (opt)
{
case '?':
exit (1);
case OPT_DIRECT:
direct = 1;
break;
case OPT_TESTDIR:
test_dir = optarg;
break;
#ifdef CMDLINE_PROCESS
CMDLINE_PROCESS
#endif
}
/* If set, read the test TIMEOUTFACTOR value from the environment.
This value is used to scale the default test timeout values. */
char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
if (envstr_timeoutfactor != NULL)
{
char *envstr_conv = envstr_timeoutfactor;
unsigned long int env_fact;
env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
timeoutfactor = MAX (env_fact, 1);
}
/* Set TMPDIR to specified test directory. */
if (test_dir != NULL)
{
setenv ("TMPDIR", test_dir, 1);
if (chdir (test_dir) < 0)
{
perror ("chdir");
exit (1);
}
}
else
{
test_dir = getenv ("TMPDIR");
if (test_dir == NULL || test_dir[0] == '\0')
test_dir = "/tmp";
}
/* Make sure we see all message, even those on stdout. */
setvbuf (stdout, NULL, _IONBF, 0);
/* make sure temporary files are deleted. */
atexit (delete_temp_files);
/* Correct for the possible parameters. */
argv[optind - 1] = argv[0];
argv += optind - 1;
argc -= optind - 1;
/* Call the initializing function, if one is available. */
#ifdef PREPARE
PREPARE (argc, argv);
#endif
/* If we are not expected to fork run the function immediately. */
if (direct)
return TEST_FUNCTION;
/* Set up the test environment:
- prevent core dumps
- set up the timer
- fork and execute the function. */
pid = fork ();
if (pid == 0)
{
/* This is the child. */
#ifdef RLIMIT_CORE
/* Try to avoid dumping core. */
struct rlimit core_limit;
core_limit.rlim_cur = 0;
core_limit.rlim_max = 0;
setrlimit (RLIMIT_CORE, &core_limit);
#endif
#ifdef RLIMIT_DATA
/* Try to avoid eating all memory if a test leaks. */
struct rlimit data_limit;
if (getrlimit (RLIMIT_DATA, &data_limit) == 0)
{
if (TEST_DATA_LIMIT == RLIM_INFINITY)
data_limit.rlim_cur = data_limit.rlim_max;
else if (data_limit.rlim_cur > (rlim_t) TEST_DATA_LIMIT)
data_limit.rlim_cur = MIN ((rlim_t) TEST_DATA_LIMIT,
data_limit.rlim_max);
if (setrlimit (RLIMIT_DATA, &data_limit) < 0)
perror ("setrlimit: RLIMIT_DATA");
}
else
perror ("getrlimit: RLIMIT_DATA");
#endif
/* We put the test process in its own pgrp so that if it bogusly
generates any job control signals, they won't hit the whole build. */
setpgid (0, 0);
/* Execute the test function and exit with the return value. */
exit (TEST_FUNCTION);
}
else if (pid < 0)
{
perror ("Cannot fork test program");
exit (1);
}
/* Set timeout. */
#ifndef TIMEOUT
/* Default timeout is two seconds. */
# define TIMEOUT 2
#endif
signal (SIGALRM, timeout_handler);
alarm (TIMEOUT * timeoutfactor);
/* Wait for the regular termination. */
while ((termpid = waitpid (pid, &status, 0)) == -1 && errno == EAGAIN);
if (termpid == -1)
{
printf ("Waiting for test program failed: %m\n");
exit (1);
}
if (termpid != pid)
{
printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
(long int) pid, (long int) termpid);
exit (1);
}
#ifndef EXPECTED_SIGNAL
/* We don't expect any signal. */
# define EXPECTED_SIGNAL 0
#endif
if (WTERMSIG (status) != EXPECTED_SIGNAL)
{
if (EXPECTED_SIGNAL != 0)
{
if (WTERMSIG (status) == 0)
fprintf (stderr,
"Expected signal '%s' from child, got none\n",
strsignal (EXPECTED_SIGNAL));
else
fprintf (stderr,
"Incorrect signal from child: got `%s', need `%s'\n",
strsignal (WTERMSIG (status)),
strsignal (EXPECTED_SIGNAL));
}
else
fprintf (stderr, "Didn't expect signal from child: got `%s'\n",
strsignal (WTERMSIG (status)));
exit (1);
}
/* Simply exit with the return value of the test. */
#ifndef EXPECTED_STATUS
return WEXITSTATUS (status);
#else
if (WEXITSTATUS (status) != EXPECTED_STATUS)
{
fprintf (stderr, "Expected status %d, got %d\n",
EXPECTED_STATUS, WEXITSTATUS (status));
exit (1);
}
return 0;
#endif
}
------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev