]> Zhao Yanbai Git Server - minix.git/commitdiff
ipc tests by GQ
authorBen Gras <ben@minix3.org>
Mon, 21 Sep 2009 14:53:53 +0000 (14:53 +0000)
committerBen Gras <ben@minix3.org>
Mon, 21 Sep 2009 14:53:53 +0000 (14:53 +0000)
98 files changed:
test/ipc/Makefile [new file with mode: 0644]
test/ipc/lib/Makefile [new file with mode: 0644]
test/ipc/lib/ipcmsg.h [new file with mode: 0644]
test/ipc/lib/ipcsem.h [new file with mode: 0644]
test/ipc/lib/ipcshm.h [new file with mode: 0644]
test/ipc/lib/libipc.c [new file with mode: 0644]
test/ipc/lib/parse_opts.c [new file with mode: 0644]
test/ipc/lib/rmobj.c [new file with mode: 0644]
test/ipc/lib/rmobj.h [new file with mode: 0644]
test/ipc/lib/test.h [new file with mode: 0644]
test/ipc/lib/tst_res.c [new file with mode: 0644]
test/ipc/lib/tst_sig.c [new file with mode: 0644]
test/ipc/lib/tst_tmpdir.c [new file with mode: 0644]
test/ipc/lib/usctest.h [new file with mode: 0644]
test/ipc/msgctl/Makefile [new file with mode: 0644]
test/ipc/msgctl/msgctl01.c [new file with mode: 0644]
test/ipc/msgctl/msgctl02.c [new file with mode: 0644]
test/ipc/msgctl/msgctl03.c [new file with mode: 0644]
test/ipc/msgctl/msgctl04.c [new file with mode: 0644]
test/ipc/msgctl/msgctl05.c [new file with mode: 0644]
test/ipc/msgctl/msgctl06.c [new file with mode: 0644]
test/ipc/msgctl/msgctl07.c [new file with mode: 0644]
test/ipc/msgctl/msgctl08.c [new file with mode: 0644]
test/ipc/msgctl/msgctl09.c [new file with mode: 0644]
test/ipc/msgget/Makefile [new file with mode: 0644]
test/ipc/msgget/msgget01.c [new file with mode: 0644]
test/ipc/msgget/msgget02.c [new file with mode: 0644]
test/ipc/msgget/msgget03.c [new file with mode: 0644]
test/ipc/msgget/msgget04.c [new file with mode: 0644]
test/ipc/msgrcv/Makefile [new file with mode: 0644]
test/ipc/msgrcv/msgrcv01.c [new file with mode: 0644]
test/ipc/msgrcv/msgrcv02.c [new file with mode: 0644]
test/ipc/msgrcv/msgrcv03.c [new file with mode: 0644]
test/ipc/msgrcv/msgrcv04.c [new file with mode: 0644]
test/ipc/msgrcv/msgrcv05.c [new file with mode: 0644]
test/ipc/msgrcv/msgrcv06.c [new file with mode: 0644]
test/ipc/msgsnd/Makefile [new file with mode: 0644]
test/ipc/msgsnd/msgsnd01.c [new file with mode: 0644]
test/ipc/msgsnd/msgsnd02.c [new file with mode: 0644]
test/ipc/msgsnd/msgsnd03.c [new file with mode: 0644]
test/ipc/msgsnd/msgsnd04.c [new file with mode: 0644]
test/ipc/msgsnd/msgsnd05.c [new file with mode: 0644]
test/ipc/msgsnd/msgsnd06.c [new file with mode: 0644]
test/ipc/semctl/Makefile [new file with mode: 0644]
test/ipc/semctl/semctl01.c [new file with mode: 0644]
test/ipc/semctl/semctl02.c [new file with mode: 0644]
test/ipc/semctl/semctl03.c [new file with mode: 0644]
test/ipc/semctl/semctl04.c [new file with mode: 0644]
test/ipc/semctl/semctl05.c [new file with mode: 0644]
test/ipc/semctl/semctl06.c [new file with mode: 0644]
test/ipc/semctl/semctl07.c [new file with mode: 0644]
test/ipc/semctl/test.sh [new file with mode: 0644]
test/ipc/semget/Makefile [new file with mode: 0644]
test/ipc/semget/semget01.c [new file with mode: 0644]
test/ipc/semget/semget02.c [new file with mode: 0644]
test/ipc/semget/semget03.c [new file with mode: 0644]
test/ipc/semget/semget05.c [new file with mode: 0644]
test/ipc/semget/semget06.c [new file with mode: 0644]
test/ipc/semget/test.sh [new file with mode: 0644]
test/ipc/semop/Makefile [new file with mode: 0644]
test/ipc/semop/semop01.c [new file with mode: 0644]
test/ipc/semop/semop02.c [new file with mode: 0644]
test/ipc/semop/semop03.c [new file with mode: 0644]
test/ipc/semop/semop04.c [new file with mode: 0644]
test/ipc/semop/semop05.c [new file with mode: 0644]
test/ipc/semop/test.sh [new file with mode: 0644]
test/ipc/shmat/Makefile [new file with mode: 0644]
test/ipc/shmat/shmat01.c [new file with mode: 0644]
test/ipc/shmat/shmat02.c [new file with mode: 0644]
test/ipc/shmat/shmat03.c [new file with mode: 0644]
test/ipc/shmat/test.sh [new file with mode: 0644]
test/ipc/shmctl/Makefile [new file with mode: 0644]
test/ipc/shmctl/shmctl01.c [new file with mode: 0644]
test/ipc/shmctl/shmctl02.c [new file with mode: 0644]
test/ipc/shmctl/shmctl03.c [new file with mode: 0644]
test/ipc/shmctl/shmctl04.c [new file with mode: 0644]
test/ipc/shmctl/test.sh [new file with mode: 0644]
test/ipc/shmdt/Makefile [new file with mode: 0644]
test/ipc/shmdt/shmdt01.c [new file with mode: 0644]
test/ipc/shmdt/shmdt02.c [new file with mode: 0644]
test/ipc/shmdt/test.sh [new file with mode: 0644]
test/ipc/shmget/Makefile [new file with mode: 0644]
test/ipc/shmget/shmget01.c [new file with mode: 0644]
test/ipc/shmget/shmget02.c [new file with mode: 0644]
test/ipc/shmget/shmget04.c [new file with mode: 0644]
test/ipc/shmget/shmget05.c [new file with mode: 0644]
test/ipc/shmget/test.sh [new file with mode: 0644]
test/ipc/shmt/Makefile [new file with mode: 0644]
test/ipc/shmt/shmt01.c [new file with mode: 0644]
test/ipc/shmt/shmt02.c [new file with mode: 0644]
test/ipc/shmt/shmt03.c [new file with mode: 0644]
test/ipc/shmt/shmt04.c [new file with mode: 0644]
test/ipc/shmt/shmt05.c [new file with mode: 0644]
test/ipc/shmt/shmt06.c [new file with mode: 0644]
test/ipc/shmt/shmt07.c [new file with mode: 0644]
test/ipc/shmt/shmt08.c [new file with mode: 0644]
test/ipc/shmt/shmt10.c [new file with mode: 0644]
test/ipc/shmt/testshm.sh [new file with mode: 0644]

diff --git a/test/ipc/Makefile b/test/ipc/Makefile
new file mode 100644 (file)
index 0000000..0aeac0e
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  Copyright (c) International Business Machines  Corp., 2001
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+all test clean:
+#      cd ./msgctl && $(MAKE) $@
+#      cd ./msgget && $(MAKE) $@
+#      cd ./msgrcv && $(MAKE) $@
+#      cd ./msgsnd && $(MAKE) $@
+       cd ./semctl && $(MAKE) $@
+       cd ./semget && $(MAKE) $@
+       cd ./semop && $(MAKE) $@
+       cd ./shmat && $(MAKE) $@
+       cd ./shmctl && $(MAKE) $@
+       cd ./shmdt && $(MAKE) $@
+       cd ./shmget && $(MAKE) $@
+       cd ./shmt && $(MAKE) $@
diff --git a/test/ipc/lib/Makefile b/test/ipc/lib/Makefile
new file mode 100644 (file)
index 0000000..0ade066
--- /dev/null
@@ -0,0 +1,33 @@
+#
+#  Copyright (c) International Business Machines  Corp., 2001
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+SRCS   = libipc.c
+OBJS   = $(SRCS:.c=.o)
+LIBIPC = ../libipc.a
+
+CFLAGS += -I../../../../../include -Wall
+
+all: $(LIBIPC)
+
+$(LIBIPC): $(OBJS)
+       $(AR) -rc $@ $(OBJS)
+
+install:
+
+clean:
+       rm -f $(OBJS) $(LIBIPC)
diff --git a/test/ipc/lib/ipcmsg.h b/test/ipc/lib/ipcmsg.h
new file mode 100644 (file)
index 0000000..4265afd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * ipcmsg.h - common definitions for the IPC message tests.
+ */
+
+#ifndef __IPCMSG_H
+#define __IPCMSG_H     1
+
+#include <errno.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#include "test.h"
+#include "usctest.h"
+
+void cleanup(void);
+void setup(void);
+
+#define MSG_RD  0400            /* read permission for the queue */
+#define MSG_WR  0200            /* write permission for the queue */
+#define MSG_RW MSG_RD | MSG_WR
+
+#define MSGSIZE        1024            /* a resonable size for a message */
+#define MSGTYPE 1              /* a type ID for a message */
+
+typedef struct mbuf {          /* a generic message structure */
+       long mtype;
+       char mtext[MSGSIZE + 1];  /* add 1 here so the message can be 1024   */
+} MSGBUF;                        /* characters long with a '\0' termination */
+
+#if (!defined CONFIG_COLDFIRE || defined LIBIPC)
+key_t msgkey;                   /* the ftok() generated message key */
+#else
+extern key_t msgkey;                   /* the ftok() generated message key */
+#endif
+
+void check_root();
+void init_buf(MSGBUF *, int, int);
+void rm_queue(int);
+
+int getipckey();
+int getuserid(char *);
+
+#endif /* ipcmsg.h */
diff --git a/test/ipc/lib/ipcsem.h b/test/ipc/lib/ipcsem.h
new file mode 100644 (file)
index 0000000..c89b76b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * ipcsem.h - common definitions for the IPC semaphore tests
+ */
+
+#ifndef __IPCSEM_H
+#define __IPCSEM_H
+
+#include <errno.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+
+#include "test.h"
+#include "usctest.h"
+
+void cleanup(void);
+void setup(void);
+
+#define SEM_RD 0400
+#define SEM_ALT        0200
+#define SEM_RA SEM_RD | SEM_ALT
+
+#define PSEMS  10              /* a reasonable value for the number of */
+                               /* "primitive semaphores" per ID        */
+
+#if (!defined CONFIG_COLDFIRE || defined LIBIPC)
+key_t semkey;                  /* an IPC key generated by ftok() */
+#else
+extern key_t semkey;            /* an IPC key generated by ftok() */
+#endif
+
+union semun {
+       int val;                        /* value for SETVAL */
+       struct semid_ds *buf;           /* buffer for IPC_STAT & IPC_SET */
+       unsigned short *array;          /* array for GETALL & SETALL */
+       struct seminfo *ipc_buf;        /* buffer for IPC_INFO */
+};
+
+void rm_sema(int sem_id);
+void check_root(void);
+
+int getipckey(void);
+int getuserid(char *);
+
+#endif /* ipcsem.h */
diff --git a/test/ipc/lib/ipcshm.h b/test/ipc/lib/ipcshm.h
new file mode 100644 (file)
index 0000000..0030466
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * ipcshm.h - common definitions for the IPC shared memory tests
+ */
+
+#ifndef __IPCSHM_H
+#define __IPCSHM_H
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "test.h"
+#include "usctest.h"
+
+void cleanup(void);
+void setup(void);
+
+#define SHM_RD 0400
+#define SHM_WR 0200
+#define SHM_RW SHM_RD | SHM_WR
+
+#define SHM_SIZE       2048    /* a resonable size for a memory segment */
+#define INT_SIZE       4       /* instead of sizeof(int) */
+
+#define MODE_MASK      0x01FF  /* to get the lower nine permission bits */
+                               /* from shmid_ds.ipc_perm.mode           */
+
+key_t shmkey;                  /* an IPC key generated by ftok() */
+
+void rm_shm(int shm_id);
+void check_root(void);
+
+int getipckey(void);
+int getuserid(char*);
+
+#endif /* ipcshm.h */
diff --git a/test/ipc/lib/libipc.c b/test/ipc/lib/libipc.c
new file mode 100644 (file)
index 0000000..30374da
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     libmsg.c
+ *
+ * DESCRIPTION
+ *     common routines for the IPC system call tests.
+ *
+ *     The library contains the following routines:
+ *
+ *     getipckey()
+ *     rm_queue()
+ *     init_buf()
+ *     rm_sema()
+ *     check_root()
+ *     getuserid()
+ *     rm_shm()
+ */
+
+#define LIBIPC
+#if 0
+#include "ipcmsg.h"
+#endif
+#include "ipcsem.h"
+
+#include <pwd.h>
+#include <sys/timeb.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+
+/*
+ * getipckey() - generates and returns a message key used by the "get"
+ *              calls to create an IPC resource.
+ */
+int
+getipckey()
+{
+       const char a = 'a';
+       int ascii_a = (int)a;
+       char *curdir = NULL;
+       char curdira[PATH_MAX];
+       size_t size = sizeof(curdira);
+       key_t ipc_key;
+       struct timeb time_info;
+
+       if (NULL == (curdir = getcwd(curdira, size))) {
+               tst_brkm(TBROK, cleanup, "Can't get current directory "
+                        "in getipckey()");
+       }
+
+       /*
+        * Get a Sys V IPC key
+        *
+        * ftok() requires a character as a second argument.  This is
+        * refered to as a "project identifier" in the man page.  In
+        * order to maximize the chance of getting a unique key, the
+        * project identifier is a "random character" produced by
+        * generating a random number between 0 and 25 and then adding
+        * that to the ascii value of 'a'.  The "seed" for the random
+        * number is the millisecond value that is set in the timeb
+        * structure after calling ftime().
+        */
+       (void)ftime(&time_info);
+       srandom((unsigned int)time_info.millitm);
+
+       if ((ipc_key = ftok(curdir, ascii_a + random()%26)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't get msgkey from ftok()");
+       }
+
+       return(ipc_key);
+}
+
+#if 0
+/*
+ * rm_queue() - removes a message queue.
+ */
+void
+rm_queue(int queue_id)
+{
+       if (queue_id == -1) {           /* no queue to remove */
+               return;
+       }
+
+       if (msgctl(queue_id, IPC_RMID, NULL) == -1) {
+               tst_resm(TINFO, "WARNING: message queue deletion failed.");
+               tst_resm(TINFO, "This could lead to IPC resource problems.");
+               tst_resm(TINFO, "id = %d", queue_id);
+       }
+}
+#endif
+
+#if 0
+/*
+ * init_buf() - initialize the message buffer with some text and a type.
+ */
+void
+init_buf(MSGBUF *m_buf, int type, int size)
+{
+       int i;
+       int ascii_a = (int)'a';         /* the ascii value for 'a' */
+
+       /* this fills the message with a repeating alphabet string */
+       for (i=0; i<size; i++) {
+               m_buf->mtext[i] = ascii_a + (i % 26);
+       }
+
+       /* terminate the message */
+       m_buf->mtext[i] = (char)NULL;
+
+       /* if the type isn't valid, set it to 1 */
+       if (type < 1) {
+               m_buf->mtype = 1;
+       } else {
+               m_buf->mtype = type;
+       }
+}
+#endif
+
+/*
+ * rm_sema() - removes a semaphore.
+ */
+void
+rm_sema(int sem_id)
+{
+       union semun arr;
+
+       if (sem_id == -1) {             /* no semaphore to remove */
+               return;
+       }
+
+       if (semctl(sem_id, 0, IPC_RMID, arr) == -1) {
+               tst_resm(TINFO, "WARNING: semaphore deletion failed.");
+               tst_resm(TINFO, "This could lead to IPC resource problems.");
+               tst_resm(TINFO, "id = %d", sem_id);
+       }
+}
+
+/*
+ * check_root() - make sure the process ID is root
+ */
+void
+check_root(void)
+{
+       if (geteuid() != 0) {
+               tst_brkm(TBROK, cleanup, "test must be run as root");
+       }
+}
+
+/*
+ * getuserid() - return the integer value for the "user" id
+ */
+int
+getuserid(char *user)
+{
+       struct passwd *ent;
+
+       /* allocate some space for the passwd struct */
+       if ((ent = (struct passwd *)malloc(sizeof(struct passwd))) == NULL) {
+            tst_brkm(TBROK, cleanup, "couldn't allocate space for passwd"
+                     " structure");
+        }
+
+       /* get the uid value for the user */
+       if ((ent = getpwnam(user)) == NULL) {
+               tst_brkm(TBROK, cleanup, "Couldn't get password entry for %s",
+                        user);
+       }
+
+       return(ent->pw_uid);
+}
+
+/*
+ * rm_shm() - removes a shared memory segment.
+ */
+void
+rm_shm(int shm_id)
+{
+       if (shm_id == -1) {             /* no segment to remove */
+               return;
+       }
+
+       /*
+        * check for # of attaches ? 
+        */
+
+       if (shmctl(shm_id, IPC_RMID, NULL) == -1) {
+               tst_resm(TINFO, "WARNING: shared memory deletion failed.");
+               tst_resm(TINFO, "This could lead to IPC resource problems.");
+               tst_resm(TINFO, "id = %d", shm_id);
+       }
+}
diff --git a/test/ipc/lib/parse_opts.c b/test/ipc/lib/parse_opts.c
new file mode 100644 (file)
index 0000000..43e3d47
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: parse_opts.c,v 1.10 2006/04/19 18:23:40 mreed10 Exp $ */
+
+/**********************************************************
+ * 
+ *    OS Testing - Silicon Graphics, Inc.
+ * 
+ *    FUNCTION NAME    : parse_opts
+ * 
+ *    FUNCTION TITLE   : parse standard & user options for system call tests
+ * 
+ *    SYNOPSIS:
+ *     #include "usctest.h"
+ *
+ *     char *parse_opts(ac, av, user_optarr, uhf)
+ *     int    ac;
+ *     char **av;
+ *     option_t user_optarr[];
+ *     void (*uhf)();
+ * 
+ *    AUTHOR           : William Roske/Richard Logan
+ * 
+ *    INITIAL RELEASE  : UNICOS 7.0
+ * 
+ *    DESCRIPTION
+ *     The parse_opts library routine takes that argc and argv parameters
+ *     recevied by main() and an array of structures defining user options.
+ *     It parses the command line setting flag and argument locations
+ *      associated with the options.  It uses getopt to do the actual cmd line
+ *      parsing.  uhf() is a function to print user define help
+ *
+ *      This module contains the functions usc_global_setup_hook and
+ *      usc_test_looping, which are called by marcos defined in usctest.h.
+ * 
+ *    RETURN VALUE
+ *     parse_opts returns a pointer to an error message if an error occurs.
+ *     This pointer is (char *)NULL if parsing is successful.
+ * 
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+#if UNIT_TEST
+#include <time.h>
+#endif /* UNIT_TEST */
+
+#include "test.h"
+#define _USC_LIB_   1  /* indicates we are the library to the usctest.h include */
+#include "usctest.h"
+
+#ifndef USC_COPIES
+#define USC_COPIES   "USC_COPIES"
+#endif
+
+#ifndef UNIT_TEST
+#define UNIT_TEST      0
+#endif
+
+#ifndef DEBUG
+#define DEBUG  0
+#endif
+
+/* The timing information block. */
+struct tblock tblock={0,((long) -1)>>1,0,0};
+
+
+/* Define flags and args for standard options */
+int STD_FUNCTIONAL_TEST=1,     /* flag indicating to do functional testing code */
+    STD_TIMING_ON=0,           /* flag indicating to print timing stats */
+    STD_PAUSE=0,               /* flag indicating to pause before actual start, */
+                               /* for contention mode */
+    STD_INFINITE=0,            /* flag indciating to loop forever */
+    STD_LOOP_COUNT=1,          /* number of iterations */
+    STD_COPIES=1,              /* number of copies */
+    STD_ERRNO_LOG=0;           /* flag indicating to do errno logging */
+
+float STD_LOOP_DURATION=0.0,    /* duration value in fractional seconds */
+      STD_LOOP_DELAY=0.0;      /* loop delay value in fractional seconds */
+
+
+char **STD_opt_arr = NULL;     /* array of option strings */
+int    STD_nopts=0,            /* number of elements in STD_opt_arr */
+       STD_argind=1;           /* argv index to next argv element */
+                               /* (first argument) */
+                               /* To getopt users, it is like optind */
+
+/*
+ * The following variables are to support system testing additions.
+ */
+static int  STD_TP_barrier=0;  /* flag to do barrier in TEST_PAUSE */
+                               /* 2 - wait_barrier(), 3 - set_barrier(), * - barrier() */
+static int  STD_LP_barrier=0;  /* flag to do barrier in TEST_LOOPING */
+                               /* 2 - wait_barrier(), 3 - set_barrier(), * - barrier() */
+static int  STD_TP_shmem_sz=0; /* shmalloc this many words per pe in TEST_PAUSE */
+static int  STD_LD_shmem=0;    /* flag to do shmem_puts and shmem_gets during delay */
+static int  STD_LP_shmem=0;    /* flag to do shmem_puts and gets during TEST_LOOPING */
+static int  STD_LD_recfun=0;   /* do recressive function calls in loop delay */
+static int  STD_LP_recfun=0;   /* do recressive function calls in TEST_LOOPING */
+static int  STD_TP_sbrk=0;     /* do sbrk in TEST_PAUSE */
+static int  STD_LP_sbrk=0;     /* do sbrk in TEST_LOOPING */
+static char *STD_start_break=0; /* original sbrk size */
+static int  Debug=0;
+
+struct std_option_t {
+    char *optstr;
+    char *help;
+    char *flag;
+    char **arg;
+} std_options[] = {
+    { "c:", "  -c n    Run n copies concurrently\n", NULL, NULL},
+    { "e" , "  -e      Turn on errno logging\n", NULL, NULL},
+    { "f" , "  -f      Turn off functional testing\n", NULL, NULL},
+    { "h" , "  -h      Show this help screen\n", NULL, NULL},
+    { "i:", "  -i n    Execute test n times\n", NULL, NULL},
+    { "I:", "  -I x    Execute test for x seconds\n", NULL, NULL},
+    { "p" , "  -p      Pause for SIGUSR1 before starting\n", NULL, NULL}, 
+    { "P:", "  -P x    Pause for x seconds between iterations\n", NULL, NULL},
+    { "t" , "  -t      Turn on syscall timing\n", NULL, NULL},
+#ifdef UCLINUX
+    { "C:", "  -C ARG  Run the child process with arguments ARG (for internal use)\n",
+      NULL, NULL},
+#endif
+    {NULL, NULL, NULL, NULL}};
+
+void print_help(void (*user_help)(void));
+
+/*
+ * Structure for usc_recressive_func argument
+ */
+struct usc_bigstack_t {
+   char space[4096];
+};
+
+static struct usc_bigstack_t *STD_bigstack=NULL;
+
+/*
+ * Counter of errnos returned (-e option).  Indexed by errno.
+ * Make the array USC_MAX_ERRNO long.  That is the first Fortran
+ * Lib errno.  No syscall should return an errno that high.
+ */
+int STD_ERRNO_LIST[USC_MAX_ERRNO];
+
+/* define the string length for Mesg and Mesg2 strings */
+#define STRLEN 2048
+
+static char Mesg2[STRLEN];     /* holds possible return string */
+static void usc_recressive_func(int, int, struct usc_bigstack_t *);
+
+/*
+ * Define bits for options that might have env variable default
+ */
+#define  OPT_iteration                 01
+#define  OPT_nofunccheck       02
+#define  OPT_duration          04
+#define  OPT_delay             010
+#define  OPT_copies            020
+
+#ifdef UCLINUX
+/* Allocated and used in self_exec.c: */
+extern char *child_args;       /* Arguments to child when -C is used */
+#endif
+
+/**********************************************************************
+ * parse_opts: 
+ **********************************************************************/
+char *
+parse_opts(int ac, char **av, option_t *user_optarr, void (*uhf)(void))
+{
+    int found;         /* flag to indicate that an option specified was */
+                       /* found in the user's list */
+    int k;             /* scratch integer for returns and short time usage */
+    float  ftmp;       /* tmp float for parsing env variables */
+    char *ptr;         /* used in getting env variables */
+    int options=0;     /* no options specified */
+    int optstrlen, i;
+    char *optionstr;
+    int opt;           /* return of getopt */
+
+    /*
+     * If not the first time this function is called, release the old STD_opt_arr
+     * vector.
+     */
+
+    if ( STD_opt_arr != NULL ) {
+       free(STD_opt_arr);
+       STD_opt_arr=NULL;
+    }
+    /* Calculate how much space we need for the option string */
+    optstrlen = 0;
+    for (i = 0; std_options[i].optstr; ++i) 
+       optstrlen += strlen(std_options[i].optstr);
+    if (user_optarr)
+       for (i = 0; user_optarr[i].option; ++i) {
+           if (strlen(user_optarr[i].option) > 2)
+               return "parse_opts: ERROR - Only short options are allowed";
+           optstrlen += strlen(user_optarr[i].option);
+       }
+    optstrlen += 1;
+
+    /* Create the option string for getopt */
+    optionstr = (char *)malloc(optstrlen);
+    if (!optionstr) 
+       return "parse_opts: ERROR - Could not allocate memory for optionstr";
+
+    optionstr[0] = '\0';
+
+    for (i = 0; std_options[i].optstr; ++i)
+       strcat(optionstr, std_options[i].optstr);
+    if (user_optarr)
+       for (i = 0; user_optarr[i].option; ++i)
+           /* only add the option if it wasn't there already */
+           if (strchr(optionstr, user_optarr[i].option[0]) == NULL) 
+               strcat(optionstr, user_optarr[i].option);
+
+#if DEBUG > 1
+    printf("STD_nopts = %d\n", STD_nopts);
+#endif
+
+    /*
+     *  Loop through av parsing options.
+     */
+    while ( (opt = getopt(ac, av, optionstr)) > 0) {
+
+       STD_argind = optind;
+#if DEBUG > 0
+       printf("parse_opts: getopt returned '%c'\n", opt);
+#endif
+
+       switch (opt) {
+               case '?': /* Unknown option */
+                       return "Unknown option";
+                       break;
+               case ':': /* Missing Arg */
+                       return "Missing argument";
+                       break;
+               case 'i': /* Iterations */
+                       options |= OPT_iteration;
+                       STD_LOOP_COUNT = atoi(optarg);
+                       if (STD_LOOP_COUNT == 0) STD_INFINITE = 1;
+                       break;
+               case 'P': /* Delay between iterations */
+                       options |= OPT_delay;
+                       STD_LOOP_DELAY = atof(optarg);
+                       break;
+               case 'I': /* Time duration */
+                       options |= OPT_duration;
+                       STD_LOOP_DURATION = atof(optarg);
+                       if ( STD_LOOP_DURATION == 0.0 ) STD_INFINITE=1; 
+                       break;
+               case 'c': /* Copies */
+                       options |= OPT_copies;
+                       STD_COPIES = atoi(optarg);
+                       break;
+               case 'f': /* Functional testing */
+                       STD_FUNCTIONAL_TEST = 0;
+                       break;
+               case 'p': /* Pause for SIGUSR1 */
+                       STD_PAUSE = 1;
+                       break;
+               case 't': /* syscall timing */
+                       STD_TIMING_ON = 1;
+                       break;
+               case 'e': /* errno loggin */
+                       STD_ERRNO_LOG = 1;
+                       break;
+               case 'h': /* Help */
+                       print_help(uhf);
+                       exit(0);
+                       break;
+#ifdef UCLINUX
+               case 'C': /* Run child */
+                       child_args = optarg;
+                       break;
+#endif
+               default:
+                       
+            /* Check all the user specified options */
+            found=0;
+           for(i = 0; user_optarr[i].option; ++i) {
+
+               if (opt == user_optarr[i].option[0]) {
+                    /* Yup, This is a user option, set the flag and look for argument */
+                   if ( user_optarr[i].flag ) {
+                        *user_optarr[i].flag=1;
+                   }
+                    found++;
+
+                   /* save the argument at the user's location */
+                    if ( user_optarr[i].option[strlen(user_optarr[i].option)-1] == ':' ) {  
+                        *user_optarr[i].arg=optarg;
+                    }
+                    break;  /* option found - break out of the for loop */
+                }
+            }
+           /* This condition "should never happen".  SO CHECK FOR IT!!!! */
+            if ( ! found ) { 
+                sprintf(Mesg2,
+                   "parse_opts: ERROR - option:\"%c\" NOT FOUND... INTERNAL ERROR", opt);
+                return(Mesg2);
+            }
+       }
+
+    }    /* end of while */
+    free(optionstr);
+
+    STD_argind = optind;
+
+    /*
+     * Turn on debug
+     */
+    if ( (ptr=getenv("USC_DEBUG")) != NULL ) {
+       Debug=1;
+        printf("env USC_DEBUG is defined, turning on debug\n");
+    }
+    if ( (ptr=getenv("USC_VERBOSE")) != NULL ) {
+       Debug=1;
+        printf("env USC_VERBOSE is defined, turning on debug\n");
+    }
+
+    /*
+     * If the USC_ITERATION_ENV environmental variable is set to
+     * a number, use that number as iteration count (same as -c option).
+     * The -c option with arg will be used even if this env var is set.
+     */
+    if ( !(options & OPT_iteration) && (ptr=getenv(USC_ITERATION_ENV)) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1) {
+            if ( k == 0 ) {   /* if arg is 0, set infinite loop flag */
+                STD_INFINITE=1;
+               if ( Debug )
+                  printf("Using env %s, set STD_INFINITE to 1\n",
+                       USC_ITERATION_ENV);
+            } else {            /* else, set the loop count to the arguement */
+                STD_LOOP_COUNT=k;
+               if ( Debug )
+                  printf("Using env %s, set STD_LOOP_COUNT to %d\n",
+                       USC_ITERATION_ENV, k);
+            }
+        }
+    }
+
+    /*
+     * If the USC_NO_FUNC_CHECK environmental variable is set, we'll
+     * unset the STD_FUNCTIONAL_TEST variable.
+     */
+    if ( !(options & OPT_nofunccheck) && (ptr=getenv(USC_NO_FUNC_CHECK)) != NULL ) {
+        STD_FUNCTIONAL_TEST=0; /* Turn off functional testing */
+       if ( Debug )
+           printf("Using env %s, set STD_FUNCTIONAL_TEST to 0\n",
+               USC_NO_FUNC_CHECK);
+    }
+
+    /*
+     * If the USC_LOOP_WALLTIME environmental variable is set,
+     * use that number as duration (same as -I option).
+     * The -I option with arg will be used even if this env var is set.
+     */
+
+    if ( !(options & OPT_duration) && (ptr=getenv(USC_LOOP_WALLTIME)) != NULL ) {
+        if ( sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0 ) {
+           STD_LOOP_DURATION=ftmp;
+           if ( Debug )
+               printf("Using env %s, set STD_LOOP_DURATION to %f\n",
+                   USC_LOOP_WALLTIME, ftmp);
+            if ( STD_LOOP_DURATION == 0.0 ) {   /* if arg is 0, set infinite loop flag */
+                STD_INFINITE=1;
+               if ( Debug )
+                   printf("Using env %s, set STD_INFINITE to 1\n", USC_LOOP_WALLTIME);
+           }
+        }
+    }
+    if ( !(options & OPT_duration) && (ptr=getenv("USC_DURATION")) != NULL ) {
+        if ( sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0 ) {
+           STD_LOOP_DURATION=ftmp;
+           if ( Debug )
+               printf("Using env USC_DURATION, set STD_LOOP_DURATION to %f\n", ftmp);
+            if ( STD_LOOP_DURATION == 0.0 ) {   /* if arg is 0, set infinite loop flag */
+                STD_INFINITE=1;
+               if ( Debug )
+                   printf("Using env USC_DURATION, set STD_INFINITE to 1\n");
+           }
+        }
+    }
+    /*
+     * If the USC_LOOP_DELAY environmental variable is set,
+     * use that number as delay in factional seconds (same as -P option).
+     * The -P option with arg will be used even if this env var is set.
+     */
+    if ( !(options & OPT_delay) && (ptr=getenv(USC_LOOP_DELAY)) != NULL ) {
+        if ( sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0 ) {
+           STD_LOOP_DELAY=ftmp;
+           if ( Debug )
+               printf("Using env %s, set STD_LOOP_DELAY = %f\n",
+                   USC_LOOP_DELAY, ftmp);
+        }
+    }
+
+    /*
+     * If the USC_COPIES environmental variable is set,
+     * use that number as copies (same as -c option).
+     * The -c option with arg will be used even if this env var is set.
+     */
+    if ( !(options & OPT_copies) && (ptr=getenv(USC_COPIES)) != NULL ) {
+        if ( sscanf(ptr, "%d", &STD_COPIES) == 1 && STD_COPIES >= 0 ) {
+           if ( Debug )
+               printf("Using env %s, set STD_COPIES = %d\n",
+                   USC_COPIES, STD_COPIES);
+        }
+    }
+
+    /*
+     * The following are special system testing envs to turn on special
+     * hooks in the code.
+     */
+    if ( (ptr=getenv("USC_TP_BARRIER")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+           STD_TP_barrier=k;
+       }
+        else
+           STD_TP_barrier=1;
+       if ( Debug )
+           printf("using env USC_TP_BARRIER, Set STD_TP_barrier to %d\n",
+               STD_TP_barrier);
+    }
+
+    if ( (ptr=getenv("USC_LP_BARRIER")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+           STD_LP_barrier=k;
+       }
+        else
+           STD_LP_barrier=1;
+       if ( Debug ) 
+           printf("using env USC_LP_BARRIER, Set STD_LP_barrier to %d\n",
+               STD_LP_barrier);
+    }
+
+    if ( (ptr=getenv("USC_TP_SHMEM")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+            STD_TP_shmem_sz=k;
+           if ( Debug )
+               printf("Using env USC_TP_SHMEM, Set STD_TP_shmem_sz to %d\n",
+                   STD_TP_shmem_sz);
+        }
+    }
+
+    if ( (ptr=getenv("USC_LP_SHMEM")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+            STD_LP_shmem=k;
+           if ( Debug )
+               printf("Using env USC_LP_SHMEM, Set STD_LP_shmem to %d\n",
+                   STD_LP_shmem);
+        }
+    }
+
+    if ( (ptr=getenv("USC_LD_SHMEM")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+            STD_LD_shmem=k;
+           if ( Debug )
+               printf("Using env USC_LD_SHMEM, Set STD_LD_shmem to %d\n",
+                   STD_LD_shmem);
+        }
+    }
+
+    if ( (ptr=getenv("USC_TP_SBRK")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+            STD_TP_sbrk=k;
+           if ( Debug )
+               printf("Using env USC_TP_SBRK, Set STD_TP_sbrk to %d\n",
+                   STD_TP_sbrk);
+        }
+    }
+
+#if !defined(UCLINUX)
+    if ( (ptr=getenv("USC_LP_SBRK")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+            STD_LP_sbrk=k;
+           if ( Debug )
+               printf("Using env USC_LP_SBRK, Set STD_LP_sbrk to %d\n",
+                   STD_LP_sbrk);
+        }
+    }
+#endif /* if !defined(UCLINUX) */
+
+    if ( (ptr=getenv("USC_LP_RECFUN")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+           STD_LP_recfun=k;
+           if ( STD_bigstack != (struct usc_bigstack_t *)NULL )
+               STD_bigstack=(struct usc_bigstack_t *)
+                       malloc(sizeof(struct usc_bigstack_t));
+           if ( Debug )
+                printf("Using env USC_LP_RECFUN, Set STD_LP_recfun to %d\n",
+                   STD_LP_recfun);
+        }
+    }
+
+    if ( (ptr=getenv("USC_LD_RECFUN")) != NULL ) {
+        if ( sscanf(ptr, "%i", &k) == 1 && k >= 0 ) {
+           STD_LD_recfun=k;
+           if ( STD_bigstack != (struct usc_bigstack_t *)NULL )
+               STD_bigstack=(struct usc_bigstack_t *)
+                       malloc(sizeof(struct usc_bigstack_t));
+           if ( Debug )
+                printf("Using env USC_LD_RECFUN, Set STD_LD_recfun to %d\n",
+                   STD_LD_recfun);
+        }
+    }
+#if UNIT_TEST
+    printf("The following variables after option and env parsing:\n");
+    printf("STD_FUNCTIONAL_TEST = %d\n", STD_FUNCTIONAL_TEST);
+    printf("STD_LOOP_DURATION   = %f\n", STD_LOOP_DURATION);
+    printf("STD_LOOP_DELAY      = %f\n", STD_LOOP_DELAY);
+    printf("STD_COPIES          = %d\n", STD_COPIES);
+    printf("STD_LOOP_COUNT      = %d\n", STD_LOOP_COUNT);
+    printf("STD_INFINITE        = %d\n", STD_INFINITE);
+    printf("STD_TIMING_ON       = %d\n", STD_TIMING_ON);
+    printf("STD_ERRNO_LOG       = %d\n", STD_ERRNO_LOG);
+    printf("STD_PAUSE           = %d\n", STD_PAUSE);
+#endif
+
+    return((char *) NULL);
+
+}    /* end of parse_opts */
+
+/*********************************************************************
+ * print_help() - print help message and user help message
+ *********************************************************************/
+void print_help(void (*user_help)(void))
+{
+    STD_opts_help();
+
+    if (user_help) user_help();
+}
+
+/*********************************************************************
+ * STD_opts_help() - return a help string for the STD_OPTIONS.
+ *********************************************************************/
+void
+STD_opts_help(void)
+{
+    int i;
+
+    for(i = 0; std_options[i].optstr; ++i) {
+       if (std_options[i].help)
+           printf(std_options[i].help);
+    }
+}
+
+/* 
+ * routine to goto when we get the SIGUSR1 for STD_PAUSE
+ */
+void STD_go(int sig)
+{
+   return;
+}
+
+/***********************************************************************
+ * This function will do desired end of global setup test
+ * hooks.
+ * Currently it will only do a pause waiting for sigusr1 if
+ * STD_PAUSE is set.
+ *
+ ***********************************************************************/
+int
+usc_global_setup_hook(void)
+{
+#ifndef UCLINUX
+    int cnt;
+    /* temp variable to store old signal action to be restored after pause */
+    int (*_TMP_FUNC)(void);
+
+    /*
+     * Fork STD_COPIES-1 copies.
+     */
+    for(cnt=1;cnt<STD_COPIES;cnt++) {
+        switch(fork() ) {
+           case -1:
+               fprintf(stderr, "%s: fork() failed, errno:%d %s\n",
+                __FILE__, errno, strerror(errno));
+               break;
+           case 0:  /* child */
+               cnt=STD_COPIES;   /* to stop the forking */
+               break;
+
+           default: /* parent */
+               break;
+       }
+    }
+    
+    /*
+     * pause waiting for sigusr1.
+     */
+    if ( STD_PAUSE ) {                                      
+        _TMP_FUNC = (int (*)(void))signal(SIGUSR1, STD_go);   
+        pause();                                          
+        signal(SIGUSR1, (void (*)(int))_TMP_FUNC);          
+    }
+
+#if !defined(UCLINUX)
+
+    if ( STD_TP_sbrk || STD_LP_sbrk) {
+       STD_start_break=sbrk(0);        /* get original sbreak size */
+    }
+
+    if ( STD_TP_sbrk ) {
+       sbrk(STD_TP_sbrk);
+       if ( Debug ) 
+           printf("after sbrk(%d)\n", STD_TP_sbrk);
+    }
+
+#endif /* if !defined(UCLINUX) */
+#endif
+    return 0;
+}
+
+#define USECS_PER_SEC  1000000  /* microseconds per second */
+
+/***********************************************************************
+ * This function returns the number of get_current_time()'s return
+ * per second.
+ ***********************************************************************/
+
+static int
+get_timepersec(void)
+{
+    return  USECS_PER_SEC;   /* microseconds per second */
+
+}
+
+/***********************************************************************
+ * this function will get current time in microseconds since 1970.
+ ***********************************************************************/
+static int
+get_current_time(void)
+{
+    struct timeval curtime;
+
+    gettimeofday(&curtime, NULL);
+
+    /* microseconds since 1970 */
+    return (curtime.tv_sec*USECS_PER_SEC) + curtime.tv_usec;
+
+
+}
+
+/***********************************************************************
+ *
+ * This function will determine if test should continue iterating
+ * If the STD_INFINITE flag is set, return 1.
+ * If the STD_LOOP_COUNT variable is set, compare it against
+ * the counter.
+ * If the STD_LOOP_DURATION variable is set, compare current time against
+ * calculated stop_time.
+ * This function will return 1 until all desired looping methods
+ * have been met.  
+ *
+ * counter integer is supplied by the user program.
+ ***********************************************************************/
+int
+usc_test_looping(counter)
+int counter;
+{
+    static int first_time = 1;
+    static int stop_time = 0;  /* stop time in rtc or usecs */
+    static int delay;          /* delay in clocks or usecs  */
+    int hertz=0;                       /* clocks per second or usecs per second */
+    int ct, end;               /* current time, end delay time */
+    int keepgoing=0;           /* used to determine return value */
+
+    /*
+     * If this is the first iteration and we are looping for 
+     * duration of STD_LOOP_DURATION seconds (fractional) or
+     * doing loop delays, get the clocks per second.
+     */
+    if ( first_time ) {
+
+       first_time=0;
+       if ( STD_LOOP_DELAY || STD_LOOP_DURATION ) {
+           hertz = get_timepersec();
+       }
+
+       /*
+        * If looping for duration, calculate stop time in
+        * clocks.
+        */
+       
+       if ( STD_LOOP_DURATION) {
+           ct=get_current_time();
+           stop_time=(int)((float)hertz * STD_LOOP_DURATION) + ct;
+       }
+
+       /*
+        * If doing delay each iteration, calcuate the number
+        * of clocks for each delay.
+        */
+       if ( STD_LOOP_DELAY ) {
+           delay=(int)((float)hertz * STD_LOOP_DELAY);
+       }
+
+    }
+       
+    /*
+     * if delay each iteration, loop for delay clocks.
+     * This will not be done on first iteration.
+     * The delay will happen before determining if
+     * there will be another iteration.
+     */
+    else if ( STD_LOOP_DELAY ) {
+       ct=get_current_time();
+        end=ct+delay;
+        while ( ct < end ) {
+           /*
+            * The following are special test hooks in the delay loop.
+            */
+           if ( STD_LD_recfun ) {
+               if ( Debug )
+                   printf("calling usc_recressive_func(0, %d, STD_bigstack)\n", 
+                       STD_LD_recfun);
+               usc_recressive_func(0, STD_LD_recfun, STD_bigstack);
+           }
+
+           ct=get_current_time();
+       }
+    }
+
+    if ( STD_INFINITE ) {
+       keepgoing++;
+    }
+
+    if ( STD_LOOP_COUNT && counter < STD_LOOP_COUNT ) {
+       keepgoing++;
+    }
+
+    if ( STD_LOOP_DURATION != 0.0 && get_current_time() < stop_time ) {
+       keepgoing++;
+    }
+
+    if ( keepgoing == 0 )
+       return 0;
+
+    /*
+     * The following code allows special system testing hooks.
+     */
+
+    if ( STD_LP_recfun ) {
+       if ( Debug )
+           printf("calling usc_recressive_func(0, %d, STD_bigstack)\n", 
+               STD_LP_recfun);
+       usc_recressive_func(0, STD_LP_recfun, STD_bigstack);
+    }
+
+#if !defined(UCLINUX)
+
+    if ( STD_LP_sbrk ) {
+       if ( Debug )
+           printf("about to do sbrk(%d)\n", STD_LP_sbrk);
+       sbrk(STD_LP_sbrk);
+    }
+#endif
+
+
+    if ( keepgoing )
+       return 1;
+    else
+        return 0;      /* done - stop iterating */
+}
+
+
+/*
+ * This function recressively calls itself max times.
+ */ 
+static void
+usc_recressive_func(cnt, max, bstack)
+int cnt;
+int max;
+struct usc_bigstack_t *bstack;
+{
+    if ( cnt < max )
+       usc_recressive_func(cnt+1, max, bstack);
+
+}
+
+#if UNIT_TEST
+/******************************************************************************
+ * UNIT TEST CODE
+ * UNIT TEST CODE
+ * 
+ * this following code is provide so that unit testing can
+ * be done fairly easily.
+ ******************************************************************************/
+
+int Help = 0;
+int Help2 = 0;
+char *ptr;
+
+/*
+ * Code from usctest.h that not part of this file since we are the library.
+ */
+
+struct usc_errno_t TEST_VALID_ENO[USC_MAX_ERRNO];
+
+  /***********************************************************************
+   * Globals for returning the return code and errno from the system call
+   * test macros.
+   ***********************************************************************/
+int TEST_RETURN;
+int TEST_ERRNO;
+
+  /***********************************************************************
+   * temporary variables for determining max and min times in TEST macro
+   ***********************************************************************/
+long btime, etime, tmptime;
+
+
+
+/* for test specific parse_opts options */
+option_t Options[] = {
+        { "help",  &Help2, NULL },      /* -help option */
+        { "h",  &Help, NULL },          /* -h option */
+       { TIMING, NULL, NULL},          /* disable -timing option */
+
+#if INVALID_TEST_CASES
+       { "missingflag", NULL, &ptr },  /* error */
+       { "missingarg:", &Help, NULL },  /* error */
+#endif  /* INVALID_TEST_CASES */
+
+        { NULL, NULL, NULL }
+};
+
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+    int lc;
+    char *msg;
+    struct timeval t;
+    int cnt;
+
+    if ( (msg=parse_opts(argc, argv,
+                       (option_t *) Options)) != (char *) NULL ) {
+       printf("ERROR : %s\n", msg);
+       exit(1);
+    }
+
+    TEST_PAUSE;
+
+    for (lc=0; TEST_LOOPING(lc); lc++) {
+    
+        TEST( gettimeofday(&t, NULL) );
+        printf("iter=%d: sec:%d, usec:%6.6d %s", lc+1, t.tv_sec,
+           t.tv_usec, ctime(&t.tv_sec));
+    }
+
+
+    TEST_CLEANUP;
+
+    exit(0);
+}
+
+#endif /* UNIT_TEST */
diff --git a/test/ipc/lib/rmobj.c b/test/ipc/lib/rmobj.c
new file mode 100644 (file)
index 0000000..e5656ad
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: rmobj.c,v 1.4 2003/07/28 16:03:02 robbiew Exp $ */
+
+/**********************************************************
+ *
+ *    OS Testing - Silicon Graphics, Inc.
+ *
+ *    FUNCTION NAME     : rmobj()
+ *
+ *    FUNCTION TITLE    : Remove an object
+ *
+ *    SYNOPSIS:
+ *      int rmobj(char *obj, char **errmsg)
+ *
+ *    AUTHOR            : Kent Rogers
+ *
+ *    INITIAL RELEASE   : UNICOS 7.0
+ *
+ *    USER DESCRIPTION
+ *      This routine will remove the specified object.  If the specified
+ *      object is a directory, it will recursively remove the directory
+ *      and everything underneath it.  It assumes that it has privilege
+ *      to remove everything that it tries to remove.  If rmobj() encounters
+ *      any problems, and errmsg is not NULL, errmsg is set to point to a
+ *      string explaining the error.
+ *
+ *    DETAILED DESCRIPTION
+ *      Allocate space for the directory and its contents
+ *      Open the directory to get access to what is in it
+ *      Loop through the objects in the directory:
+ *        If the object is not "." or "..":
+ *          Determine the file type by calling lstat()
+ *          If the object is not a directory:
+ *            Remove the object with unlink()
+ *         Else:
+ *            Call rmobj(object) to remove the object's contents
+ *            Determine the link count on object by calling lstat()
+ *            If the link count >= 3:
+ *              Remove the directory with unlink()
+ *            Else
+ *               Remove the directory with rmdir()
+ *      Close the directory and free the pointers
+ *
+ *    RETURN VALUE
+ *      If there are any problems, rmobj() will set errmsg (if it was not
+ *      NULL) and return -1.  Otherwise it will return 0.
+ *
+ ************************************************************/
+#include <errno.h>         /* for errno */
+#include <stdio.h>         /* for NULL */
+#include <stdlib.h>        /* for malloc() */
+#include <string.h>        /* for string function */
+#include <limits.h>        /* for PATH_MAX */
+#include <sys/types.h>     /* for opendir(), readdir(), closedir(), stat() */
+#include <sys/stat.h>      /* for [l]stat() */
+#include <dirent.h>        /* for opendir(), readdir(), closedir() */
+#include <unistd.h>        /* for rmdir(), unlink() */
+#include "rmobj.h"
+
+#define SYSERR strerror(errno)
+
+int
+rmobj(char *obj, char **errmsg)
+{
+   int           ret_val = 0;       /* return value from this routine */
+   DIR           *dir;              /* pointer to a directory */
+   struct dirent *dir_ent;          /* pointer to directory entries */
+   char          dirobj[PATH_MAX];  /* object inside directory to modify */
+   struct stat   statbuf;           /* used to hold stat information */
+   static char   err_msg[1024];     /* error message */
+
+   /* Determine the file type */
+   if ( lstat(obj, &statbuf) < 0 ) {
+      if ( errmsg != NULL ) {
+         sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
+                 obj, errno, SYSERR);
+         *errmsg = err_msg;
+      }
+      return -1;
+   }
+
+   /* Take appropriate action, depending on the file type */
+   if ( (statbuf.st_mode & S_IFMT) == S_IFDIR ) {
+      /* object is a directory */
+
+      /* Do NOT perform the request if the directory is "/" */
+      if ( !strcmp(obj, "/") ) {
+         if ( errmsg != NULL ) {
+            sprintf(err_msg, "Cannot remove /");
+            *errmsg = err_msg;
+         }
+         return -1;
+      }
+
+      /* Open the directory to get access to what is in it */
+      if ( (dir = opendir(obj)) == NULL ) {
+         if ( rmdir(obj) != 0 ) {
+            if ( errmsg != NULL ) {
+               sprintf(err_msg, "rmdir(%s) failed; errno=%d: %s",
+                       obj, errno, SYSERR);
+               *errmsg = err_msg;
+            }
+            return -1;
+         } else {
+            return 0;
+         }
+      }
+
+      /* Loop through the entries in the directory, removing each one */
+      for ( dir_ent = (struct dirent *)readdir(dir);
+            dir_ent != NULL;
+            dir_ent = (struct dirent *)readdir(dir)) {
+
+         /* Don't remove "." or ".." */
+         if ( !strcmp(dir_ent->d_name, ".") || !strcmp(dir_ent->d_name, "..") )
+            continue;
+
+         /* Recursively call this routine to remove the current entry */
+         sprintf(dirobj, "%s/%s", obj, dir_ent->d_name);
+         if ( rmobj(dirobj, errmsg) != 0 )
+            ret_val = -1;
+      }
+
+      /* Close the directory */
+      closedir(dir);
+
+      /* If there were problems removing an entry, don't attempt to
+         remove the directory itself */
+      if ( ret_val == -1 )
+         return -1;
+
+      /* Get the link count, now that all the entries have been removed */
+      if ( lstat(obj, &statbuf) < 0 ) {
+         if ( errmsg != NULL ) {
+            sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
+                    obj, errno, SYSERR);
+            *errmsg = err_msg;
+         }
+         return -1;
+      }
+
+      /* Remove the directory itself */
+      if ( statbuf.st_nlink >= 3 ) {
+         /* The directory is linked; unlink() must be used */
+         if ( unlink(obj) < 0 ) {
+            if ( errmsg != NULL ) {
+               sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
+                       obj, errno, SYSERR);
+               *errmsg = err_msg;
+            }
+            return -1;
+         }
+      } else {
+         /* The directory is not linked; rmdir() can be used */
+         if ( rmdir(obj) < 0 ) {
+            if ( errmsg != NULL ) {
+               sprintf(err_msg, "remove(%s) failed; errno=%d: %s",
+                       obj, errno, SYSERR);
+               *errmsg = err_msg;
+            }
+            return -1;
+         }
+      }
+   } else {
+      /* object is not a directory; just use unlink() */
+      if ( unlink(obj) < 0 ) {
+         if ( errmsg != NULL ) {
+            sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
+                    obj, errno, SYSERR);
+            *errmsg = err_msg;
+         }
+         return -1;
+      }
+   }  /* if obj is a directory */
+
+   /*
+    * Everything must have went ok.
+    */
+   return 0;
+}  /* rmobj() */
diff --git a/test/ipc/lib/rmobj.h b/test/ipc/lib/rmobj.h
new file mode 100644 (file)
index 0000000..4808ca2
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _RMOBJ_H_
+#define _RMOBJ_H_
+
+/*
+ * rmobj() - Remove the specified object.  If the specified object is a
+ *           directory, recursively remove everything inside of it.  If
+ *           there are any problems, set errmsg (if it is not NULL) and
+ *           return -1.  Otherwise return 0.
+ */
+int rmobj( char *object , char **errmesg );
+
+#endif
diff --git a/test/ipc/lib/test.h b/test/ipc/lib/test.h
new file mode 100644 (file)
index 0000000..ca93e32
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: test.h,v 1.10 2006/05/26 06:17:53 vapier Exp $ */
+
+#ifndef __TEST_H__
+#define __TEST_H__
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TPASS    0    /* Test passed flag */
+#define TFAIL    1    /* Test failed flag */
+#define TBROK    2    /* Test broken flag */
+#define TWARN    4    /* Test warning flag */
+#define TRETR    8    /* Test retire flag */
+#define TINFO    16   /* Test information flag */
+#define TCONF    32   /* Test not appropriate for configuration flag */
+
+/*
+ * To determine if you are on a Umk or Unicos system,
+ * use sysconf(_SC_CRAY_SYSTEM).  But since _SC_CRAY_SYSTEM
+ * is not defined until 90, it will be define here if not already
+ * defined.
+ * if ( sysconf(_SC_CRAY_SYSTEM) == 1 )
+ *    on UMK
+ * else   # returned 0 or -1 
+ *    on Unicos
+ * This is only being done on CRAY systems.
+ */
+#ifdef CRAY
+#ifndef _SC_CRAY_SYSTEM
+#define _SC_CRAY_SYSTEM  140
+#endif /* ! _SC_CRAY_SYSTEM */
+#endif /* CRAY */
+
+/*
+ * Ensure that NUMSIGS is defined.
+ * It should be defined in signal.h or sys/signal.h on
+ * UNICOS/mk and IRIX systems.   On UNICOS systems,
+ * it is not defined, thus it is being set to UNICOS's NSIG.
+ * Note:  IRIX's NSIG (signals are 1-(NSIG-1)) 
+ *      is not same meaning as UNICOS/UMK's NSIG  (signals 1-NSIG)
+ */
+#define NSIG _NSIG
+#define SIGCLD SIGCHLD
+#ifndef NUMSIGS
+#define NUMSIGS NSIG
+#endif
+
+
+/* defines for unexpected signal setup routine (set_usig.c) */
+#define FORK    1              /* SIGCLD is to be ignored */
+#define NOFORK  0              /* SIGCLD is to be caught */
+#define DEF_HANDLER 0  /* tells set_usig() to use default signal handler */
+
+/*
+ * The following defines are used to control tst_res and t_result reporting.
+ */
+
+#define TOUTPUT           "TOUTPUT"            /* The name of the environment variable */
+                                       /* that can be set to one of the following */
+                                       /* strings to control tst_res output */
+                                       /* If not set, TOUT_VERBOSE_S is assumed */
+
+#define TOUT_VERBOSE_S  "VERBOSE"      /* All test cases reported */
+#define TOUT_CONDENSE_S "CONDENSE"     /* ranges are used where identical messages*/
+                                       /* occur for sequential test cases */
+#define TOUT_NOPASS_S   "NOPASS"       /* No pass test cases are reported */
+#define TOUT_DISCARD_S  "DISCARD"      /* No output is reported */
+
+#define TST_NOBUF      "TST_NOBUF"     /* The name of the environment variable */
+                                       /* that can be set to control whether or not */
+                                       /* tst_res will buffer output into 4096 byte */
+                                       /* blocks of output */
+                                       /* If not set, buffer is done.  If set, no */
+                                       /* internal buffering will be done in tst_res */
+                                       /* t_result does not have internal buffering */
+
+/*
+ * The following defines are used to control tst_tmpdir, tst_wildcard and t_mkchdir
+ */
+
+#define TDIRECTORY  "TDIRECTORY"       /* The name of the environment variable */
+                                       /* that if is set, the value (directory) */
+                                       /* is used by all tests as their working */
+                                       /* directory.  tst_rmdir and t_rmdir will */
+                                       /* not attempt to clean up. */
+                                       /* This environment variable should only */
+                                       /* be set when doing system testing since */
+                                       /* tests will collide and break and fail */
+                                       /* because of setting it. */
+
+#define TEMPDIR        "/tmp"                  /* This is the default temporary directory. */
+                                       /* The environment variable TMPDIR is */
+                                       /* used prior to this valid by tempnam(3). */
+                                       /* To control the base location of the */
+                                       /* temporary directory, set the TMPDIR */
+                                       /* environment variable to desired path */
+
+/*
+ * The following contains support for error message passing.
+ * See test_error.c for details.
+ */
+#define  TST_ERR_MESG_SIZE      1023    /* max size of error message */
+#define  TST_ERR_FILE_SIZE      511     /* max size of module name used by compiler */
+#define  TST_ERR_FUNC_SIZE      127     /* max size of func name */
+
+typedef struct {
+    int  te_line;                       /* line where last error was reported.  Use */
+                                        /* "__LINE__" and let compiler do the rest */
+    int  te_level;                      /* If set, will prevent current stored */
+                                        /* error to not be overwritten */
+    char te_func[TST_ERR_FUNC_SIZE+1];  /* name of function of last error */
+                                        /* Name of function or NULL */
+    char te_file[TST_ERR_FILE_SIZE+1];  /* module of last error.  Use */
+                                        /* "__FILE__" and let compiler do the rest */
+    char te_mesg[TST_ERR_MESG_SIZE+1];  /* string of last error */
+
+} _TST_ERROR;
+
+extern _TST_ERROR Tst_error;            /* defined in test_error.c */
+#if __STDC__
+extern void tst_set_error(char *file, int line, char *func, char *fmt, ...);
+#else
+extern void tst_set_error(void);
+#endif
+extern void tst_clear_error(void);
+
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify the number of iterations.
+ * It is supported in parse_opts.c and USC_setup.c.
+ */
+#define USC_ITERATION_ENV       "USC_ITERATIONS"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify to iteration until desired time
+ * in floating point seconds has gone by.
+ * Supported in USC_setup.c.
+ */
+#define USC_LOOP_WALLTIME      "USC_LOOP_WALLTIME"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify that no functional checks are wanted.
+ * It is supported in parse_opts.c and USC_setup.c.
+ */
+#define USC_NO_FUNC_CHECK      "USC_NO_FUNC_CHECK"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify the delay between each loop iteration.
+ * The value is in seconds (fractional numbers are allowed).
+ * It is supported in parse_opts.c.
+ */
+#define USC_LOOP_DELAY         "USC_LOOP_DELAY"
+
+/*
+ * fork() can't be used on uClinux systems, so use FORK_OR_VFORK instead,
+ * which will run vfork() on uClinux.
+ * mmap() doesn't support MAP_PRIVATE on uClinux systems, so use
+ * MAP_PRIVATE_EXCEPT_UCLINUX instead, which will skip the option on uClinux.
+ * If MAP_PRIVATE really is required, the test can not be run on uClinux.
+ */
+#ifdef UCLINUX
+#define FORK_OR_VFORK                  vfork
+#define MAP_PRIVATE_EXCEPT_UCLINUX     0       
+#else
+#define FORK_OR_VFORK                  fork
+#define MAP_PRIVATE_EXCEPT_UCLINUX     MAP_PRIVATE
+#endif
+
+/*
+ * The following prototypes are needed to remove compile errors
+ * on IRIX systems when compiled with -n32 and -64.
+ */
+extern void tst_res(int ttype, char *fname, char *arg_fmt, ...);
+extern void tst_resm(int ttype, char *arg_fmt, ...);
+extern void tst_brk(int ttype, char *fname, void (*func)(void), 
+                                                       char *arg_fmt, ...);
+extern void tst_brkloop(int ttype, char *fname, void (*func)(void), 
+                                                       char *arg_fmt, ...);
+extern void tst_brkm(int ttype, void (*func)(void), char *arg_fmt, ...);
+extern void tst_brkloopm(int ttype, void (*func)(void), char *arg_fmt, ...);
+
+extern int  tst_environ(void);
+extern void tst_exit(void);
+extern void tst_flush(void);
+
+/* prototypes for the t_res.c functions */
+extern void t_result(char *tcid, int tnum, int ttype, char *tmesg);
+extern void tt_exit(void);
+extern int  t_environ(void);
+extern void t_breakum(char *tcid, int total, int typ, char *msg, void (*fnc)(void));
+
+extern void tst_sig(int fork_flag, void (*handler)(int), void (*cleanup)(void));
+extern void tst_tmpdir(void);
+extern void tst_rmdir(void);
+
+extern char * get_high_address(void);
+
+extern void get_kver(int*, int*, int*);
+extern int tst_kvercmp(int, int, int);
+
+extern int tst_is_cwd_tmpfs(void);
+extern int tst_cwd_has_free(int required_kib);
+
+extern int Tst_count;
+
+/* self_exec.c functions */
+void maybe_run_child(void (*child)(void), char *fmt, ...);
+int self_exec(char *argv0, char *fmt, ...);
+
+#endif /* end of __TEST_H__ */
diff --git a/test/ipc/lib/tst_res.c b/test/ipc/lib/tst_res.c
new file mode 100644 (file)
index 0000000..0b426ac
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+
+/* $Id: tst_res.c,v 1.3 2005/12/22 20:18:22 robbiew Exp $ */
+
+/**********************************************************
+ *
+ *    OS Testing - Silicon Graphics, Inc.
+ *
+ *    FUNCTION NAME     :
+ *      tst_res() -       Print result message (include file contents)
+ *      tst_resm() -      Print result message
+ *      tst_brk() -       Print result message (include file contents)
+ *                        and break remaining test cases
+ *      tst_brkm() -      Print result message and break remaining test
+ *                        cases
+ *      tst_brkloop() -   Print result message (include file contents)
+ *                        and break test cases remaining in current loop
+ *      tst_brkloopm() -  Print result message and break test case
+ *                        remaining in current loop
+ *      tst_flush() -     Print any messages pending because of
+ *                        CONDENSE mode, and flush output stream
+ *      tst_exit() -      Exit test with a meaningful exit value.
+ *      tst_environ() -   Keep results coming to original stdout
+ *
+ *    FUNCTION TITLE    : Standard automated test result reporting mechanism
+ *
+ *    SYNOPSIS:
+ *      #include "test.h"
+ *
+ *      void tst_res(ttype, fname, tmesg [,arg]...)
+ *      int  ttype;
+ *      char *fname;
+ *      char *tmesg;
+ *
+ *      void tst_resm(ttype, tmesg [,arg]...)
+ *      int  ttype;
+ *      char *tmesg;
+ *
+ *      void tst_brk(ttype, fname, cleanup, tmesg, [,argv]...)
+ *      int  ttype;
+ *      char *fname;
+ *      void (*cleanup)();
+ *      char *tmesg;
+ *
+ *      void tst_brkm(ttype, cleanup, tmesg [,arg]...)
+ *      int  ttype;
+ *      void (*cleanup)();
+ *      char *tmesg;
+ *
+ *      void tst_brkloop(ttype, fname, cleanup, char *tmesg, [,argv]...)
+ *      int  ttype;
+ *      char *fname;
+ *      void (*cleanup)();
+ *      char *tmesg;
+ *
+ *      void tst_brkloopm(ttype, cleanup, tmesg [,arg]...)
+ *      int  ttype;
+ *      void (*cleanup)();
+ *      char *tmesg;
+ *
+ *      void tst_flush()
+ *
+ *      void tst_exit()
+ *
+ *      int  tst_environ()
+ *
+ *    AUTHOR            : Kent Rogers (from Dave Fenner's original)
+ *
+ *    CO-PILOT          : Rich Logan
+ *
+ *    DATE STARTED      : 05/01/90 (rewritten 1/96)
+ *
+ *    DESCRIPTION
+ *      See the man page(s).
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>         /* for I/O functions, BUFSIZ */
+#include <stdlib.h>        /* for getenv() */
+#include <stdarg.h>        /* for varargs stuff */
+#include <unistd.h>        /* for access() */
+#include "test.h"          /* for output display mode & result type */
+                           /* defines */
+
+/*
+ * Define some useful macros.
+ */
+#define VERBOSE      1     /* flag values for the T_mode variable */
+#define CONDENSE     2
+#define NOPASS       3
+#define DISCARD      4
+
+#define MAXMESG      80    /* max length of internal messages */
+#define USERMESG     2048  /* max length of user message */
+#define TRUE         1
+#define FALSE        0
+
+/*
+ * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
+ *                   message into the specified string.
+ */
+#define EXPAND_VAR_ARGS(arg_fmt, str) {   \
+   va_list ap; /* varargs mechanism */    \
+                                          \
+   if ( arg_fmt != NULL ) {               \
+      if ( Expand_varargs == TRUE ) {     \
+         va_start(ap, arg_fmt);           \
+         vsprintf(str, arg_fmt, ap);      \
+         va_end(ap);                      \
+         Expand_varargs = FALSE;          \
+      } else {                            \
+         strcpy(str, arg_fmt);            \
+      }                                   \
+   } else {                               \
+      str[0] = '\0';                      \
+   }                                      \
+}  /* EXPAND_VAR_ARGS() */
+
+/*
+ * Define local function prototypes.
+ */
+static void check_env(void);
+static void tst_condense(int tnum, int ttype, char *tmesg);
+static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg);
+static void cat_file(char *filename);
+
+
+/*
+ * Define some static/global variables.
+ */
+static FILE *T_out = NULL;    /* tst_res() output file descriptor */
+static char *File;            /* file whose contents is part of result */
+static int  T_exitval = 0;    /* exit value used by tst_exit() */
+static int  T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
+                              /* CONDENSE, NOPASS, DISCARD */
+
+static int  Expand_varargs = TRUE;  /* if TRUE, expand varargs stuff */
+static char Warn_mesg[MAXMESG];  /* holds warning messages */
+
+/*
+ * These are used for condensing output when NOT in verbose mode.
+ */
+static int  Buffered = FALSE; /* TRUE if condensed output is currently */
+                              /* buffered (i.e. not yet printed) */
+static char *Last_tcid;       /* previous test case id */
+static int  Last_num;         /* previous test case number */
+static int  Last_type;        /* previous test result type */
+static char *Last_mesg;       /* previous test result message */
+
+
+/*
+ * These globals may be externed by the test.
+ */
+int Tst_count = 0;      /* current count of test cases executed; NOTE: */
+                        /* Tst_count may be externed by other programs */
+int Tst_lptotal = 0;    /* tst_brkloop() external */
+int Tst_lpstart = 0;    /* tst_brkloop() external */
+int Tst_range = 1;      /* for specifying multiple results */
+int Tst_nobuf = 1;      /* this is a no-op; buffering is never done, but */
+                        /* this will stay for compatibility reasons */
+
+/*
+ * These globals must be defined in the test.
+ */
+extern char *TCID;      /* Test case identifier from the test source */
+extern int  TST_TOTAL;  /* Total number of test cases from the test */
+                        /* source */
+
+/*
+ * This global is used by the temp. dir. maintenance functions,
+ * tst_tmpdir()/tst_rmdir(), tst_wildcard()/tst_tr_rmdir().  It is the
+ * name of the directory created (if any).  It is defined here, so that
+ * it only has to be declared once and can then be referenced from more
+ * than one module.  Also, since the temp. dir. maintenance functions
+ * rely on the tst_res.c package this seemed like a reasonable place.
+ */
+char *TESTDIR = NULL;
+
+/*
+ * tst_res() - Main result reporting function.  Handle test information
+ *             appropriately depending on output display mode.  Call
+ *             tst_condense() or tst_print() to actually print results.
+ *             All result functions (tst_resm(), tst_brk(), etc.)
+ *             eventually get here to print the results.
+ */
+void
+tst_res(int ttype, char *fname, char *arg_fmt, ...)
+{
+   int  i;
+   char tmesg[USERMESG];     /* expanded message */
+
+#if DEBUG
+   printf("IN tst_res; Tst_count = %d; Tst_range = %d\n",
+          Tst_count, Tst_range); fflush(stdout);
+#endif
+
+   /*
+    * Expand the arg_fmt string into tmesg, if necessary.
+    */
+   EXPAND_VAR_ARGS(arg_fmt, tmesg);
+
+   /*
+    * Save the test result type by ORing ttype into the current exit
+    * value (used by tst_exit()).
+    */
+   T_exitval |= ttype;
+
+   /*
+    * Unless T_out has already been set by tst_environ(), make tst_res()
+    * output go to standard output.
+    */
+   if ( T_out == NULL )
+       T_out = stdout;
+
+   /*
+    * Check TOUTPUT environment variable (if first time) and set T_mode
+    * flag.
+    */
+   check_env();
+
+   /*
+    * A negative or NULL range is invalid.
+    */
+   if ( Tst_range <= 0 ) {
+      Tst_range = 1;
+      tst_print(TCID, 0, 1, TWARN,
+                "tst_res(): Tst_range must be positive");
+   }
+
+   /*
+    * If a filename was specified, set 'File' if it exists.
+    */
+   if ( fname != NULL && access(fname, F_OK) == 0 )
+      File = fname;
+
+   /*
+    * Set the test case number and print the results, depending on the
+    * display type.
+    */
+   if ( ttype == TWARN || ttype == TINFO ) {
+      /*
+       * Handle WARN and INFO results (test case number is 0).
+       */
+      if ( Tst_range > 1 ) {
+         tst_print(TCID, 0, 1, TWARN,
+                   "tst_res(): Range not valid for TINFO or TWARN types");
+      }
+      tst_print(TCID, 0, 1, ttype, tmesg);
+   } else {
+      /*
+       * Handle all other types of results other than WARN and INFO.
+       */
+      if ( Tst_count < 0 )
+         tst_print(TCID, 0, 1, TWARN,
+                   "tst_res(): Tst_count < 0 is not valid");
+
+      /*
+       * Process each display type.
+       */
+      switch ( T_mode ) {
+      case DISCARD:
+         /* do not print any results */
+         break;
+
+      case NOPASS:   /* passing result types are filtered by tst_print() */
+      case CONDENSE:
+         tst_condense(Tst_count + 1, ttype, tmesg);
+         break;
+
+      default: /* VERBOSE */
+         for ( i = 1 ; i <= Tst_range ; i++ )
+            tst_print(TCID, Tst_count + i, Tst_range, ttype, tmesg);
+         break;
+      }  /* end switch() */
+
+      /*
+       * Increment Tst_count.
+       */
+      Tst_count += Tst_range;
+   }  /* if ( ttype == TWARN || ttype == TINFO ) */
+
+   /*
+    * Reset some values.
+    */
+   Tst_range = 1;
+   Expand_varargs = TRUE;
+}  /* tst_res() */
+
+
+/*
+ * tst_condense() - Handle test cases in CONDENSE or NOPASS mode (i.e.
+ *                  buffer the current result and print the last result
+ *                  if different than the current).  If a file was
+ *                  specified, print the current result and do not
+ *                  buffer it.
+ */
+static void
+tst_condense(int tnum, int ttype, char *tmesg)
+{
+   char *file;
+
+#if DEBUG
+   printf("IN tst_condense: tcid = %s, tnum = %d, ttype = %d, tmesg = %s\n",
+          TCID, tnum, ttype, tmesg);
+   fflush(stdout);
+#endif
+
+   /*
+    * If this result is the same as the previous result, return.
+    */
+   if ( Buffered == TRUE ) {
+      if ( strcmp(Last_tcid, TCID) == 0 && Last_type == ttype &&
+           strcmp(Last_mesg, tmesg) == 0 && File == NULL )
+         return;
+
+      /*
+       * This result is different from the previous result.  First,
+       * print the previous result.
+       */
+      file = File;
+      File = NULL;
+      tst_print(Last_tcid, Last_num, tnum - Last_num, Last_type,
+                Last_mesg);
+      free(Last_tcid);
+      free(Last_mesg);
+      File = file;
+   }  /* if ( Buffered == TRUE ) */
+
+   /*
+    * If a file was specified, print the current result since we have no
+    * way of retaining the file contents for comparing with future
+    * results.  Otherwise, buffer the current result info for next time.
+    */
+   if ( File != NULL ) {
+      tst_print(TCID, tnum, Tst_range, ttype, tmesg);
+      Buffered = FALSE;
+   } else {
+      Last_tcid = (char *)malloc(strlen(TCID) + 1);
+      strcpy(Last_tcid, TCID);
+      Last_num = tnum;
+      Last_type = ttype;
+      Last_mesg = (char *)malloc(strlen(tmesg) + 1);
+      strcpy(Last_mesg, tmesg);
+      Buffered = TRUE;
+   }
+}  /* tst_condense() */
+
+
+/*
+ * tst_flush() - Print any messages pending because of CONDENSE mode,
+ *               and flush T_out.
+ */
+void
+tst_flush(void)
+{
+#if DEBUG
+   printf("IN tst_flush\n");
+   fflush(stdout);
+#endif
+
+   /*
+    * Print out last line if in CONDENSE or NOPASS mode.
+    */
+   if ( Buffered == TRUE && (T_mode == CONDENSE || T_mode == NOPASS) ) {
+      tst_print(Last_tcid, Last_num, Tst_count - Last_num + 1,
+                Last_type, Last_mesg);
+      Buffered = FALSE;
+   }
+   fflush(T_out);
+}  /* tst_flush() */
+
+
+/*
+ * tst_print() - Actually print a line or range of lines to the output
+ *               stream.
+ */
+static void
+tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg)
+{
+   char type[5];
+
+#if DEBUG
+   printf("IN tst_print: tnum = %d, trange = %d, ttype = %d, tmesg = %s\n",
+          tnum, trange, ttype, tmesg);
+   fflush(stdout);
+#endif
+
+   /*
+    * Save the test result type by ORing ttype into the current exit
+    * value (used by tst_exit()).  This is already done in tst_res(), but
+    * is also done here to catch internal warnings.  For internal warnings, 
+    * tst_print() is called directly with a case of TWARN.
+    */
+   T_exitval |= ttype;
+
+   /*
+    * If output mode is DISCARD, or if the output mode is NOPASS and
+    * this result is not one of FAIL, BROK, or WARN, just return.  This
+    * check is necessary even though we check for DISCARD mode inside of
+    * tst_res(), since occasionally we get to this point without going
+    * through tst_res() (e.g. internal TWARN messages).
+    */
+   if ( T_mode == DISCARD || (T_mode == NOPASS && ttype != TFAIL &&
+                              ttype != TBROK && ttype != TWARN) )
+      return;
+
+   /*
+    * Fill in the type string according to ttype.
+    */
+   switch ( ttype ) {
+   case TPASS:
+      strcpy(type, "PASS");
+      break;
+   case TFAIL:
+      strcpy(type, "FAIL");
+      break;
+   case TBROK:
+      strcpy(type, "BROK");
+      break;
+   case TRETR:
+      strcpy(type, "RETR");
+      break;
+   case TCONF:
+      strcpy(type, "CONF");
+      break;
+   case TWARN:
+      strcpy(type, "WARN");
+      break;
+   case TINFO:
+      strcpy(type, "INFO");
+      break;
+   default:
+      strcpy(type, "????");
+      break;
+   }  /* switch ( ttype ) */
+
+   /*
+    * Build the result line and print it.
+    */
+   if ( T_mode == VERBOSE ) {
+      fprintf(T_out, "%-8s %4d  %s  :  %s\n", tcid, tnum, type, tmesg);
+   } else {
+      /* condense results if a range is specified */
+      if ( trange > 1 )
+         fprintf(T_out, "%-8s %4d-%-4d  %s  :  %s\n",
+                 tcid, tnum, tnum + trange - 1, type, tmesg);
+      else
+         fprintf(T_out, "%-8s %4d       %s  :  %s\n",
+                 tcid, tnum, type, tmesg);
+   }
+
+   /*
+    * If tst_res() was called with a file, append file contents to the
+    * end of last printed result.
+    */
+   if ( File != NULL )
+      cat_file(File);
+   File = NULL;
+}  /* tst_print() */
+
+
+/*
+ * check_env() - Check the value of the environment variable TOUTPUT and
+ *               set the global variable T_mode.  The TOUTPUT environment
+ *               variable should be set to "VERBOSE", "CONDENSE",
+ *               "NOPASS", or "DISCARD".  If TOUTPUT does not exist or
+ *               is not set to a valid value, the default is "VERBOSE".
+ */
+static void
+check_env(void)
+{
+   static int first_time = 1;
+   char       *value;      /* value of TOUTPUT environment variable */
+
+#if DEBUG
+   printf("IN check_env\n");
+   fflush(stdout);
+#endif
+
+   if ( !first_time )
+      return;
+
+   first_time = 0;
+
+   if ( (value = getenv(TOUTPUT)) == NULL ) {
+      /* TOUTPUT not defined, use default */
+      T_mode = VERBOSE;
+   } else if ( strcmp(value, TOUT_CONDENSE_S) == 0 ) {
+      T_mode = CONDENSE;
+   } else if ( strcmp(value, TOUT_NOPASS_S) == 0 ) {
+      T_mode = NOPASS;
+   } else if ( strcmp(value, TOUT_DISCARD_S) == 0 ) {
+      T_mode = DISCARD;
+   } else {
+      /* default */
+      T_mode = VERBOSE;
+   }
+
+   return;
+}  /* check_env() */
+
+
+/*
+ * tst_exit() - Call exit() with the value T_exitval, set up by
+ *              tst_res().  T_exitval has a bit set for most of the
+ *              result types that were seen (including TPASS, TFAIL,
+ *              TBROK, TWARN, TCONF).  Also, print the last result (if
+ *              necessary) before exiting.
+ */
+void
+tst_exit(void)
+{
+#if DEBUG
+   printf("IN tst_exit\n"); fflush(stdout);
+   fflush(stdout);
+#endif
+
+   /*
+    * Call tst_flush() flush any ouput in the buffer or the last
+    * result not printed because of CONDENSE mode.
+    */
+   tst_flush();
+
+   /*
+    * Mask out TRETR, TINFO, and TCONF results from the exit status.
+    */
+   exit(T_exitval & ~(TRETR | TINFO | TCONF));
+}  /* tst_exit() */
+
+
+/*
+ * tst_environ() - Preserve the tst_res() output location, despite any
+ *                 changes to stdout.
+ */
+int
+tst_environ()
+{
+#if defined UCLINUX && EMBED && CONFIG_BLACKFIN
+   FILE *fdopen;
+#else
+   FILE *fdopen(int fd, const char *mode);
+#endif
+
+   if ( (T_out = fdopen(dup(fileno(stdout)), "w")) == NULL )
+      return(-1);
+   else
+      return(0);
+}  /* tst_environ() */
+
+
+/*
+ * tst_brk() - Fail or break current test case, and break the remaining
+ *             tests cases.
+ */
+void
+tst_brk(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
+{
+   char    tmesg[USERMESG];      /* expanded message */
+
+#if DEBUG
+   printf("IN tst_brk\n"); fflush(stdout);
+   fflush(stdout);
+#endif
+
+   /*
+    * Expand the arg_fmt string into tmesg, if necessary.
+    */
+   EXPAND_VAR_ARGS(arg_fmt, tmesg);
+
+   /*
+    * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
+    */
+   if ( ttype != TFAIL && ttype != TBROK && ttype != TCONF &&
+        ttype != TRETR ) {
+      sprintf(Warn_mesg, "tst_brk(): Invalid Type: %d.  Using TBROK",
+              ttype);
+      tst_print(TCID, 0, 1, TWARN, Warn_mesg);
+      ttype = TBROK;
+   }
+
+   /*
+    * Print the first result, if necessary.
+    */
+   if ( Tst_count < TST_TOTAL )
+      tst_res(ttype, fname, tmesg);
+
+   /*
+    * Determine the number of results left to report.
+    */
+   Tst_range = TST_TOTAL - Tst_count;
+
+   /*
+    * Print the rest of the results, if necessary.
+    */
+   if ( Tst_range > 0 ) {
+      if ( ttype == TCONF )
+         tst_res(ttype, NULL,
+                 "Remaining cases not appropriate for configuration");
+      else if ( ttype == TRETR )
+         tst_res(ttype, NULL, "Remaining cases retired");
+      else
+         tst_res(TBROK, NULL, "Remaining cases broken");
+   } else {
+      Tst_range = 1;
+      Expand_varargs = TRUE;
+   }  /* if ( Tst_range > 0 ) */
+
+   /*
+    * If no cleanup function was specified, just return to the caller.
+    * Otherwise call the specified function.  If specified function
+    * returns, call tst_exit().
+    */
+   if ( func != NULL ) {
+      (*func)();
+      tst_exit();
+   }
+
+   return;
+}  /* tst_brk() */
+
+
+/*
+ * tst_brkloop() - Fail or break current test case, and break the
+ *                 remaining test cases within test case loop.
+ */
+void
+tst_brkloop(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
+{
+   char    tmesg[USERMESG];      /* expanded message */
+
+#if DEBUG
+   printf("IN tst_brkloop\n"); fflush(stdout);
+   fflush(stdout);
+#endif
+
+   /*
+    * Expand the arg_fmt string into tmesg.
+    */
+   EXPAND_VAR_ARGS(arg_fmt, tmesg);
+
+   /*
+    * Verify that Tst_lpstart & Tst_lptotal are valid.
+    */
+   if ( Tst_lpstart < 0 || Tst_lptotal < 0 ) {
+      tst_print(TCID, 0, 1, TWARN,
+                "tst_brkloop(): Tst_lpstart & Tst_lptotal must both be assigned non-negative values");
+      Expand_varargs = TRUE;
+      return;
+   }
+
+   /*
+    * Only FAIL, BROK, CONF, and RETR are supported by tst_brkloop().
+    */
+   if ( ttype != TFAIL && ttype != TBROK && ttype != TCONF &&
+        ttype != TRETR ) {
+      sprintf(Warn_mesg,
+              "tst_brkloop(): Invalid Type: %d.  Using TBROK",
+              ttype);
+      tst_print(TCID, 0, 1, TWARN, Warn_mesg);
+      ttype = TBROK;
+   }
+
+   /*
+    * Print the first result, if necessary.
+    */
+   if ( Tst_count < Tst_lpstart + Tst_lptotal )
+      tst_res(ttype, fname, tmesg);
+
+   /*
+    * Determine the number of results left to report.
+    */
+   Tst_range = Tst_lptotal + Tst_lpstart - Tst_count;
+
+   /*
+    * Print the rest of the results, if necessary.
+    */
+   if ( Tst_range > 0 ) {
+      if ( ttype == TCONF )
+         tst_res(ttype, NULL,
+                 "Remaining cases in loop not appropriate for configuration");
+      else if ( ttype == TRETR )
+         tst_res(ttype, NULL, "Remaining cases in loop retired");
+      else
+         tst_res(TBROK, NULL, "Remaining cases in loop broken");
+   } else {
+      Tst_range = 1;
+      Expand_varargs = TRUE;
+   }  /* if ( Tst_range > 0 ) */
+
+   /*
+    * If a cleanup function was specified, call it.
+    */
+   if ( func != NULL )
+      (*func)();
+}  /* tst_brkloop() */
+
+
+/*
+ * tst_resm() - Interface to tst_res(), with no filename.
+ */
+void
+tst_resm(int ttype, char *arg_fmt, ...)
+{
+   char    tmesg[USERMESG];      /* expanded message */
+
+#if DEBUG
+   printf("IN tst_resm\n"); fflush(stdout);
+   fflush(stdout);
+#endif
+
+   /*
+    * Expand the arg_fmt string into tmesg.
+    */
+   EXPAND_VAR_ARGS(arg_fmt, tmesg);
+
+   /*
+    * Call tst_res with a null filename argument.
+    */
+   tst_res(ttype, NULL, tmesg);
+}  /* tst_resm() */
+
+
+/*
+ * tst_brkm() - Interface to tst_brk(), with no filename.
+ */
+void
+tst_brkm(int ttype, void (*func)(void), char *arg_fmt, ...)
+{
+   char    tmesg[USERMESG];      /* expanded message */
+
+#if DEBUG
+   printf("IN tst_brkm\n"); fflush(stdout);
+   fflush(stdout);
+#endif
+
+   /*
+    * Expand the arg_fmt string into tmesg.
+    */
+   EXPAND_VAR_ARGS(arg_fmt, tmesg);
+
+   /*
+    * Call tst_brk with a null filename argument.
+    */
+   tst_brk(ttype, NULL, func, tmesg);
+}  /* tst_brkm() */
+
+
+/*
+ * tst_brkloopm() - Interface to tst_brkloop(), with no filename.
+ */
+void
+tst_brkloopm(int ttype, void (*func)(void), char *arg_fmt, ...)
+{
+   char    tmesg[USERMESG];      /* expanded message */
+
+#if DEBUG
+   printf("IN tst_brkloopm\n");
+   fflush(stdout);
+#endif
+
+   /*
+    * Expand the arg_fmt string into tmesg.
+    */
+   EXPAND_VAR_ARGS(arg_fmt, tmesg);
+
+   /*
+    * Call tst_brkloop with a null filename argument.
+    */
+   tst_brkloop(ttype, NULL, func, tmesg);
+}  /* tst_brkloopm() */
+
+
+/*
+ * cat_file() - Print the contents of a file to standard out.
+ */
+static void
+cat_file(char *filename)
+{
+   FILE *fp;                  /* file pointer */
+   int  b_read;               /* number of bytes read with read() */
+   int  b_written;            /* number of bytes written with write() */
+   char buffer[BUFSIZ];       /* read/write buffer; BUFSIZ defined in */
+                              /* stdio.h */
+
+#if DEBUG
+   printf("IN cat_file\n"); fflush(stdout);
+#endif
+
+   /*
+    * Open the file for reading.
+    */
+   if ( (fp = fopen(filename, "r")) == NULL ) {
+      sprintf(Warn_mesg,
+              "tst_res(): fopen(%s, \"r\") failed; errno = %d: %s",
+              filename, errno, strerror(errno));
+      tst_print(TCID, 0, 1, TWARN, Warn_mesg);
+      return;
+   }  /* if ( fopen(filename, "r") == -1 ) */
+
+   /*
+    * While something to read, continue to read blocks.
+    * From fread(3) man page: 
+    *   If an error occurs, or the end-of-file is reached, the return
+    *   value is zero.
+    */
+   errno = 0;
+   while ( (b_read = fread((void *)buffer, 1, BUFSIZ, fp)) != (size_t)0 ) {
+      /*
+       * Write what was read to the result output stream.
+       */
+      if ( (b_written = fwrite((void *)buffer, 1, b_read, T_out)) !=
+           b_read ) {
+         sprintf(Warn_mesg,
+                 "tst_res(): While trying to cat \"%s\", fwrite() wrote only %d of %d bytes",
+                 filename, b_written, b_read);
+         tst_print(TCID, 0, 1, TWARN, Warn_mesg);
+         break;
+      }  /* if ( b_written != b_read ) */
+   }  /* while ( fread() != 0 ) */
+
+   /*
+    * Check for an fread() error.
+    */
+   if ( !feof(fp) ) {
+      sprintf(Warn_mesg,
+              "tst_res(): While trying to cat \"%s\", fread() failed, errno = %d: %s",
+              filename, errno, strerror(errno));
+      tst_print(TCID, 0, 1, TWARN, Warn_mesg);
+   }  /* if ( !feof() ) */
+
+   /*
+    * Close the file.
+    */
+   if ( fclose(fp) == EOF ) {
+      sprintf(Warn_mesg,
+              "tst_res(): While trying to cat \"%s\", fclose() failed, errno = %d: %s",
+              filename, errno, strerror(errno));
+      tst_print(TCID, 0, 1, TWARN, Warn_mesg);
+   }  /* if ( fclose(fp) == EOF ) */
+}  /* cat_file() */
+
+
+
+#ifdef UNIT_TEST
+/****************************************************************************
+ * Unit test code: Takes input from stdin and can make the following
+ *                 calls: tst_res(), tst_resm(), tst_brk(), tst_brkm(),
+ *                 tst_flush_buf(), tst_exit().
+ ****************************************************************************/
+int  TST_TOTAL = 10;
+char *TCID = "TESTTCID";
+
+#define RES  "tst_res.c UNIT TEST message; ttype = %d; contents of \"%s\":"
+#define RESM "tst_res.c UNIT TEST message; ttype = %d"
+
+main(void)
+{
+   int  ttype;
+   int  range;
+   char *chrptr;
+   char chr;
+   char fname[MAXMESG];
+
+   printf("UNIT TEST of tst_res.c.  Options for ttype:\n\
+   -1 : call tst_exit()\n\
+   -2 : call tst_flush()\n\
+   -3 : call tst_brk()\n\
+   -4 : call tst_brkloop()\n\
+   -5 : call tst_res() with a range\n\
+    0 : call tst_res(TPASS, ...)\n\
+    1 : call tst_res(TFAIL, ...)\n\
+    2 : call tst_res(TBROK, ...)\n\
+    4 : call tst_res(TWARN, ...)\n\
+    8 : call tst_res(TRETR, ...)\n\
+   16 : call tst_res(TINFO, ...)\n\
+   32 : call tst_res(TCONF, ...)\n\n");
+
+   while ( 1 ) {
+      printf("Enter ttype (-5,-4,-3,-2,-1,0,1,2,4,8,16,32): ");
+      (void) scanf("%d%c", &ttype, &chr);
+
+
+      switch ( ttype ) {
+      case -1:
+         tst_exit();
+         break;
+
+      case -2:
+         tst_flush();
+         break;
+
+      case -3:
+         printf("Enter the current type (1=FAIL, 2=BROK, 8=RETR, 32=CONF): ");
+         (void) scanf("%d%c", &ttype, &chr);
+         printf("Enter file name (<cr> for none): ");
+         gets(fname);
+         if ( strcmp(fname, "") == 0 )
+            tst_brkm(ttype, tst_exit, RESM, ttype);
+         else
+            tst_brk(ttype, fname, tst_exit, RES, ttype, fname);
+         break;
+
+      case -4:
+         printf("Enter the size of the loop: ");
+         (void) scanf("%d%c", &range, &chr);
+         Tst_lpstart = Tst_count;
+         Tst_lptotal = range;
+         printf("Enter the current type (1=FAIL, 2=BROK, 8=RETR, 32=CONF): ");
+         (void) scanf("%d%c", &ttype, &chr);
+         printf("Enter file name (<cr> for none): ");
+         gets(fname);
+         if ( strcmp(fname, "") == 0 )
+            tst_brkloopm(ttype, NULL, RESM, ttype);
+         else
+            tst_brkloop(ttype, fname, NULL, RES, ttype, fname);
+         break;
+
+      case -5:
+         printf("Enter the size of the range: ");
+         (void) scanf("%d%c", &Tst_range, &chr);
+         printf("Enter the current type (0,1,2,4,8,16,32): ");
+         (void) scanf("%d%c", &ttype, &chr);
+         /* fall through to tst_res() call */
+
+      default:
+         printf("Enter file name (<cr> for none): ");
+         gets(fname);
+         if ( strcmp(fname, "") == 0 )
+            tst_resm(ttype, RESM, ttype);
+         else
+            tst_res(ttype, fname, RES, ttype, fname);
+         break;
+      }  /* switch() */
+   }  /* while() */
+}
+#endif  /* UNIT_TEST */
diff --git a/test/ipc/lib/tst_sig.c b/test/ipc/lib/tst_sig.c
new file mode 100644 (file)
index 0000000..658df49
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: tst_sig.c,v 1.10 2005/01/04 21:00:35 mridge Exp $ */
+
+/*****************************************************************************
+       OS Testing  - Silicon Graphics, Inc.
+
+       FUNCTION IDENTIFIER : tst_sig  Set up for unexpected signals.
+
+       AUTHOR          : David D. Fenner
+
+       CO-PILOT        : Bill Roske
+
+       DATE STARTED    : 06/06/90
+
+       This module may be linked with c-modules requiring unexpected
+       signal handling.  The parameters to tst_sig are as follows:
+
+               fork_flag - set to FORK or NOFORK depending upon whether the
+                       calling program executes a fork() system call.  It
+                       is normally the case that the calling program treats
+                       SIGCLD as an expected signal if fork() is being used.
+
+               handler - a pointer to the unexpected signal handler to
+                       be executed after an unexpected signal has been
+                       detected.  If handler is set to DEF_HANDLER, a 
+                       default handler is used.  This routine should be
+                       declared as function returning an int.
+
+               cleanup - a pointer to a cleanup routine to be executed
+                       by the unexpected signal handler before tst_exit is
+                       called.  This parameter is set to NULL if no cleanup
+                       routine is required.  An external variable, T_cleanup
+                       is set so that other user-defined handlers have 
+                       access to the cleanup routine.  This routine should be
+                       declared as returning type void.
+
+***************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include "test.h"
+
+#define MAXMESG 150            /* size of mesg string sent to tst_res */
+
+void (*T_cleanup)(void);               /* pointer to cleanup function */
+
+/****************************************************************************
+ * STD_COPIES is defined in parse_opts.c but is externed here in order to
+ * test whether SIGCHILD should be ignored or not.
+ ***************************************************************************/
+extern int STD_COPIES;
+
+static void def_handler(int);          /* default signal handler */
+static void (*tst_setup_signal( int, void (*)(int)))(int);
+
+/****************************************************************************
+ * tst_sig() : set-up to catch unexpected signals.  fork_flag is set to NOFORK
+ *    if SIGCLD is to be an "unexpected signal", otherwise it is set to
+ *    FORK.  cleanup points to a cleanup routine to be executed before
+ *    tst_exit is called (cleanup is set to NULL if no cleanup is desired).
+ *    handler is a pointer to the signal handling routine (if handler is
+ *    set to NULL, a default handler is used).
+ ***************************************************************************/
+
+void
+tst_sig(int fork_flag, void (*handler)(int), void (*cleanup)(void))
+{
+       char mesg[MAXMESG];             /* message buffer for tst_res */
+       int sig;
+#ifdef _SC_SIGRT_MIN
+        long sigrtmin, sigrtmax;
+#endif
+
+       /*
+        * save T_cleanup and handler function pointers
+        */
+       T_cleanup = cleanup;            /* used by default handler */
+
+       if (handler == DEF_HANDLER) {
+               /* use default handler */
+               handler = def_handler;
+       }
+  
+#ifdef _SC_SIGRT_MIN
+        sigrtmin = sysconf(_SC_SIGRT_MIN);
+        sigrtmax = sysconf(_SC_SIGRT_MAX);
+#endif
+
+       /*
+        * now loop through all signals and set the handlers
+        */
+
+       for (sig = 1; sig < NSIG; sig++) {
+           /*
+            * SIGKILL is never unexpected.
+            * SIGCLD is only unexpected when
+            *    no forking is being done.
+            * SIGINFO is used for file quotas and should be expected
+            */
+
+#ifdef _SC_SIGRT_MIN
+            if (sig >= sigrtmin && sig <= sigrtmax)
+                continue;
+#endif
+
+           switch (sig) {
+               case SIGKILL:
+               case SIGSTOP:
+               case SIGCONT:
+#if !defined(_SC_SIGRT_MIN) && defined(__SIGRTMIN) && defined(__SIGRTMAX)
+            /* Ignore all real-time signals */
+               case __SIGRTMIN:
+               case __SIGRTMIN+1:
+               case __SIGRTMIN+2:
+               case __SIGRTMIN+3:
+               case __SIGRTMIN+4:
+               case __SIGRTMIN+5:
+               case __SIGRTMIN+6:
+               case __SIGRTMIN+7:
+               case __SIGRTMIN+8:
+               case __SIGRTMIN+9:
+               case __SIGRTMIN+10:
+               case __SIGRTMIN+11:
+               case __SIGRTMIN+12:
+               case __SIGRTMIN+13:
+               case __SIGRTMIN+14:
+               case __SIGRTMIN+15:
+/* __SIGRTMIN is 37 on HPPA rather than 32 *
+ * as on i386, etc.                        */
+#if !defined(__hppa__)
+               case __SIGRTMAX-15:
+               case __SIGRTMAX-14:
+               case __SIGRTMAX-13:
+               case __SIGRTMAX-12:
+               case __SIGRTMAX-11:
+#endif
+               case __SIGRTMAX-10:
+               case __SIGRTMAX-9:
+               case __SIGRTMAX-8:
+               case __SIGRTMAX-7:
+               case __SIGRTMAX-6:
+               case __SIGRTMAX-5:
+               case __SIGRTMAX-4:
+               case __SIGRTMAX-3:
+               case __SIGRTMAX-2:
+               case __SIGRTMAX-1:
+               case __SIGRTMAX:
+#endif
+#ifdef CRAY
+               case SIGINFO:
+               case SIGRECOVERY:       /* allow chkpnt/restart */
+#endif  /* CRAY */
+
+#ifdef SIGSWAP
+               case SIGSWAP:
+#endif /* SIGSWAP */
+
+#ifdef SIGCKPT
+               case SIGCKPT:
+#endif
+#ifdef SIGRESTART
+               case SIGRESTART:
+#endif
+                /*
+                 * pthread-private signals SIGPTINTR and SIGPTRESCHED.
+                 * Setting a handler for these signals is disallowed when
+                 * the binary is linked against libpthread.
+                 */
+#ifdef SIGPTINTR
+                case SIGPTINTR:
+#endif /* SIGPTINTR */
+#ifdef SIGPTRESCHED
+                case SIGPTRESCHED:
+#endif /* SIGPTRESCHED */
+#ifdef _SIGRESERVE
+              case _SIGRESERVE:
+#endif
+#ifdef _SIGDIL
+              case _SIGDIL:
+#endif
+#ifdef _SIGCANCEL
+              case _SIGCANCEL:
+#endif
+#ifdef _SIGGFAULT
+              case _SIGGFAULT:
+#endif
+                   break;
+
+               case SIGCLD:
+                   if ( fork_flag == FORK || STD_COPIES > 1)
+                       continue;
+
+               default:
+                   if (tst_setup_signal(sig, handler) == SIG_ERR) {
+                       (void) sprintf(mesg,
+                           "signal() failed for signal %d. error:%d %s.",
+                           sig, errno, strerror(errno));
+                       tst_resm(TWARN, mesg);
+                   }
+               break;
+            }
+#ifdef __sgi
+           /* On irix  (07/96), signal() fails when signo is 33 or higher */
+           if ( sig+1 >= 33 )
+               break;
+#endif  /*  __sgi */
+
+       } /* endfor */
+}
+
+
+
+/****************************************************************************
+ * def_handler() : default signal handler that is invoked when
+ *      an unexpected signal is caught.
+ ***************************************************************************/
+
+static void
+def_handler(int sig)
+{
+
+       /*
+         * Break remaining test cases, do any cleanup, then exit
+        */
+       tst_brkm(TBROK, 0, "Unexpected signal %d received.", sig);
+
+       /* now cleanup and exit */
+       if (T_cleanup) {
+               (*T_cleanup)();
+       }
+
+       tst_exit();
+}
+
+/*
+ * tst_setup_signal - A function like signal(), but we have
+ *                    control over its personality.
+ */
+static void (*tst_setup_signal( int sig, void (*handler)(int)))(int)
+{ 
+  struct sigaction my_act,old_act;
+  int ret;
+
+  my_act.sa_handler = handler;
+  my_act.sa_flags = SA_RESTART;
+  sigemptyset(&my_act.sa_mask);
+
+  ret = sigaction(sig, &my_act, &old_act);
+
+  if ( ret == 0 )
+    return( old_act.sa_handler );
+  else
+    return( SIG_ERR );
+}
+
diff --git a/test/ipc/lib/tst_tmpdir.c b/test/ipc/lib/tst_tmpdir.c
new file mode 100644 (file)
index 0000000..ea2ff46
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: tst_tmpdir.c,v 1.10 2005/01/04 21:00:35 mridge Exp $ */
+
+/**********************************************************
+ *
+ *    OS Testing - Silicon Graphics, Inc.
+ *
+ *    FUNCTION NAME     : tst_tmpdir, tst_rmdir
+ *
+ *    FUNCTION TITLE    : Create/remove a testing temp dir
+ *
+ *    SYNOPSIS:
+ *      void tst_tmpdir();
+ *      void tst_rmdir();
+ *
+ *    AUTHOR            : Dave Fenner
+ *
+ *    INITIAL RELEASE   : UNICOS 8.0
+ *
+ *    DESCRIPTION
+ *      tst_tmpdir() is used to create a unique, temporary testing
+ *      directory, and make it the current working directory.
+ *      tst_rmdir() is used to remove the directory created by
+ *      tst_tmpdir().
+ *
+ *      Setting the env variable "TDIRECTORY" will override the creation
+ *      of a new temp dir.  The directory specified by TDIRECTORY will
+ *      be used as the temporary directory, and no removal will be done
+ *      in tst_rmdir().
+ *
+ *    RETURN VALUE
+ *      Neither tst_tmpdir() or tst_rmdir() has a return value.
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>        /* for getenv() */
+#include <string.h>        /* for string functions */
+#include <unistd.h>        /* for sysconf(), getcwd(), rmdir() */
+#include <sys/types.h>     /* for mkdir() */
+#include <sys/stat.h>      /* for mkdir() */
+#include "test.h"
+#include "rmobj.h"
+
+/*
+ * Define some useful macros.
+ */
+#define PREFIX_SIZE     4
+#define STRING_SIZE     256
+#define DIR_MODE        0777  /* mode of tmp dir that will be created */
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+/*
+ * Define function prototypes.
+ */
+static void tmpdir_cleanup(void);
+
+/*
+ * Define global variables.
+ */
+extern char *TCID;            /* defined/initialized in main() */
+extern int  TST_TOTAL;        /* defined/initialized in main() */
+extern char *TESTDIR;         /* the directory created; defined in */
+                              /* tst_res.c */
+
+/*
+ * tst_tmpdir() - Create a unique temporary directory and chdir() to it.
+ *                It expects the caller to have defined/initialized the
+ *                TCID/TST_TOTAL global variables.  The TESTDIR global
+ *                variable will be set to the directory that gets used
+ *                as the testing directory.
+ *
+ *                NOTE: This function must be called BEFORE any activity
+ *                that would require CLEANUP.  If tst_tmpdir() fails, it
+ *                cleans up afer itself and calls tst_exit() (i.e. does
+ *                not return).
+ */
+#undef   FN_NAME
+#define  FN_NAME  "tst_tmpdir()"
+
+void
+tst_tmpdir()
+{
+       char template[PATH_MAX];      /* template for mkstemp, mkdtemp */
+       int  no_cleanup = 0;          /* !0 means TDIRECTORY env var was set */
+       char *env_tmpdir;            /* temporary storage for TMPDIR env var */
+/* This is an AWEFUL hack to figure out if mkdtemp() is available */
+#if defined(__GLIBC_PREREQ)
+# if __GLIBC_PREREQ(2,2)
+#  define HAVE_MKDTEMP 1
+# else
+#  define HAVE_MKDTEMP 0
+       int tfd;
+# endif
+#else 
+# define HAVE_MKDTEMP 0
+       int tfd;
+#endif
+       /*
+        * If the TDIRECTORY env variable is not set, a temp dir will be
+        * created.
+        */
+       if ((TESTDIR = getenv(TDIRECTORY))) {
+               /*
+                * The TDIRECTORY env. variable is set, so no temp dir is created.
+                * Also, no clean up will be done via tst_rmdir().
+                */
+               no_cleanup++;
+#if UNIT_TEST
+               printf("TDIRECTORY env var is set\n");
+#endif
+       } else {
+               /*
+                * Create a template for the temporary directory.  Use the 
+                * environment variable TMPDIR if it is available, otherwise
+                * use our default TEMPDIR.
+                */
+               if ((env_tmpdir = getenv("TMPDIR"))) {
+                       snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", env_tmpdir, TCID);
+               } else {
+                       snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", TEMPDIR, TCID);
+               }
+               
+
+#if HAVE_MKDTEMP
+               /*
+                * Make the temporary directory in one shot using mkdtemp()
+                */
+               if (mkdtemp(template) == NULL)
+                       tst_brkm(TBROK, tmpdir_cleanup, 
+                               "%s: mkdtemp(%s) failed; errno = %d: %s", 
+                               FN_NAME, template, errno, strerror(errno));
+               TESTDIR = strdup(template);
+#else 
+               /*
+                * Make the template name, then the directory
+                */
+               if ((tfd = mkstemp(template)) == -1)
+                       tst_brkm(TBROK, tmpdir_cleanup, 
+                               "%s: mkstemp(%s) failed; errno = %d: %s", 
+                               FN_NAME, template, errno, strerror(errno));
+               close(tfd);
+               unlink(template);
+               TESTDIR = strdup(template);
+               if (mkdir(TESTDIR, DIR_MODE)) {
+                       /* If we start failing with EEXIST, wrap this section in 
+                        * a loop so we can try again.
+                        */
+                       tst_brkm(TBROK, tmpdir_cleanup, 
+                               "%s: mkdir(%s, %#o) failed; errno = %d: %s", 
+                               FN_NAME, TESTDIR, DIR_MODE, errno, 
+                               strerror(errno));
+               }
+#endif
+
+       }
+               /*
+                * Change the group on this temporary directory to be that of the
+                * gid of the person running the tests and permissions to 777.
+                */
+               if ( chown(TESTDIR, -1, getgid()) == -1 )
+                       tst_brkm(TBROK, tmpdir_cleanup, 
+                               "chown(%s, -1, %d) failed; errno = %d: %s", 
+                               TESTDIR, getgid(), errno, strerror(errno));
+               if ( chmod(TESTDIR,S_IRWXU | S_IRWXG | S_IRWXO) == -1 )
+                       tst_brkm(TBROK, tmpdir_cleanup,
+                               "chmod(%s,777) failed; errno %d: %s",
+                               TESTDIR, errno, strerror(errno)); 
+
+#if UNIT_TEST
+       printf("TESTDIR = %s\n", TESTDIR);
+#endif
+
+       /*
+        * Change to the temporary directory.  If the chdir() fails, issue
+        * TBROK messages for all test cases, attempt to remove the
+        * directory (if it was created), and exit.  If the removal also
+        * fails, also issue a TWARN message.   
+        */
+       if ( chdir(TESTDIR) == -1 ) {
+               tst_brkm(TBROK, NULL, "%s: chdir(%s) failed; errno = %d: %s",
+                               FN_NAME, TESTDIR, errno, strerror(errno) );
+
+               /* Try to remove the directory */
+               if ( !no_cleanup && rmdir(TESTDIR) == -1 )
+                       tst_resm(TWARN, "%s: rmdir(%s) failed; errno = %d: %s",
+                               FN_NAME, TESTDIR, errno, strerror(errno) );
+
+               tmpdir_cleanup();
+       }
+       
+#if UNIT_TEST
+       printf("CWD is %s\n", getcwd((char *)NULL, PATH_MAX));
+#endif
+
+       /*
+        *  If we made through all this stuff, return.
+        */
+       return;
+}  /* tst_tmpdir() */
+
+
+/*
+ *
+ * tst_rmdir() - Recursively remove the temporary directory created by
+ *               tst_tmpdir().  This function is intended ONLY as a
+ *               companion to tst_tmpdir().  If the TDIRECTORY
+ *               environment variable is set, no cleanup will be
+ *               attempted.
+ */ 
+#undef   FN_NAME
+#define  FN_NAME  "tst_rmdir()"
+
+void
+tst_rmdir()
+{
+   char *errmsg;
+   char *tdirectory;
+   char current_dir[PATH_MAX];   /* current working directory */
+   char parent_dir[PATH_MAX];    /* directory above TESTDIR */
+   char *basename;               /* basename of the TESTDIR */
+
+   /*
+    * If the TDIRECTORY env variable is set, this indicates that no
+    * temp dir was created by tst_tmpdir().  Thus no cleanup will be
+    * necessary.
+    */
+   if ( (tdirectory = getenv(TDIRECTORY)) != NULL ) {
+#if UNIT_TEST
+      printf("\"TDIRECORY\" env variable is set; no cleanup was performed\n");
+#endif
+      return;
+   }
+   
+   /*
+    * Check that TESTDIR is not NULL.
+    */
+   if ( TESTDIR == NULL ) {
+      tst_resm(TWARN, "%s: TESTDIR was NULL; no removal attempted",
+               FN_NAME);
+      return;
+   }
+
+   /*
+    * Check that the value of TESTDIR is not "*" or "/".  These could
+    * have disastrous effects in a test run by root.
+    */
+   if ( strcmp(TESTDIR, "/") == 0 ) {
+      tst_resm(TWARN,
+               "%s: Recursive remove of root directory not attempted",
+               FN_NAME);
+      return;
+   }
+
+   if ( strchr(TESTDIR, '*') != NULL ) {
+      tst_resm(TWARN, "%s: Recursive remove of '*' not attempted",
+               FN_NAME);
+      return;
+   }
+
+   /*
+    * Get the directory name of TESTDIR.  If TESTDIR is a relative path,
+    * get full path.
+    */
+   if ( TESTDIR[0] != '/' ) {
+      if ( getcwd(current_dir,PATH_MAX) == NULL )
+         strcpy(parent_dir, TESTDIR);
+      else
+         sprintf(parent_dir, "%s/%s", current_dir, TESTDIR);
+   } else {
+      strcpy(parent_dir, TESTDIR);
+   }
+   if ( (basename = strrchr(parent_dir, '/')) != NULL ) {
+      *basename='\0';   /* terminate at end of parent_dir */
+   }
+
+   /*
+    * Change directory to parent_dir (The dir above TESTDIR).
+    */
+   if ( chdir(parent_dir) != 0 )
+      tst_resm(TWARN,
+               "%s: chdir(%s) failed; errno = %d: %s\nAttempting to remove temp dir anyway",
+               FN_NAME, parent_dir, errno, strerror(errno));
+   
+   /*
+    * Attempt to remove the "TESTDIR" directory, using rmobj().
+    */
+   if ( rmobj(TESTDIR, &errmsg) == -1 )
+      tst_resm(TWARN, "%s: rmobj(%s) failed: %s",
+               FN_NAME, TESTDIR, errmsg);
+
+   return;
+}  /* tst_rmdir() */
+
+
+/*
+ * tmpdir_cleanup() - This function is used when tst_tmpdir()
+ *                    encounters an error, and must cleanup and exit.
+ *                    It prints a warning message via tst_resm(), and
+ *                    then calls tst_exit().
+ */
+#undef  FN_NAME
+#define FN_NAME "tst_tmpdir()"
+
+static void
+tmpdir_cleanup()
+{
+   /*
+    * Print a warning message and call tst_exit() to exit the test.
+    */
+   tst_resm(TWARN, "%s: No user cleanup function called before exiting",
+            FN_NAME);
+   tst_exit();
+}  /* tmpdir_cleanup() */
+
+
+#ifdef UNIT_TEST
+/****************************************************************************
+ * Unit test code: Takes input from stdin and can make the following
+ *                 calls: tst_tmpdir(), tst_rmdir().
+ ****************************************************************************/
+int  TST_TOTAL = 10;
+char *TCID = "TESTTCID";
+
+main()
+{
+   int  option;
+   char *chrptr;
+
+   printf("UNIT TEST of tst_tmpdir.c.  Options to try:\n\
+   -1 : call tst_exit()\n\
+    0 : call tst_tmpdir()\n\
+    1 : call tst_rmdir()\n\n");
+
+   while ( 1 ) {
+      printf("Enter options (-1, 0, 1): ");
+      (void) scanf("%d%c", &option, &chrptr);
+
+      switch ( option ) {
+      case -1:
+         tst_exit();
+         break;
+
+      case 0:
+         tst_tmpdir();
+         break;
+
+      case 1:
+         tst_rmdir();
+         break;
+      }  /* switch() */
+   }  /* while() */
+}
+#endif  /* UNIT_TEST */
diff --git a/test/ipc/lib/usctest.h b/test/ipc/lib/usctest.h
new file mode 100644 (file)
index 0000000..0858cec
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: usctest.h,v 1.10 2006/05/26 06:06:06 vapier Exp $ */
+
+/**********************************************************
+ * 
+ *    IRIX/Linux Feature Test and Evaluation - Silicon Graphics, Inc.
+ * 
+ *    FUNCTION NAME    : usctest.h
+ * 
+ *    FUNCTION TITLE   : System Call Test Macros
+ * 
+ *    SYNOPSIS:
+ *     See DESCRIPTION below.
+ * 
+ *    AUTHOR           : William Roske
+ * 
+ *    INITIAL RELEASE  : UNICOS 7.0
+ * 
+ *    DESCRIPTION
+ *     TEST(SCALL) - calls a system call
+ *     TEST_VOID(SCALL) - same as TEST() but for syscalls with no return value.
+ *     TEST_CLEANUP - print the log of errno return counts if STD_ERRNO_LOG 
+ *                    is set.
+ *     TEST_PAUSEF(HAND) - Pause for SIGUSR1 if the pause flag is set.
+ *                   Use "hand" as the interrupt handling function
+ *     TEST_PAUSE -  Pause for SIGUSR1 if the pause flag is set.
+ *                   Use internal function to do nothing on signal and go on.
+ *     TEST_LOOPING(COUNTER) - Conditional to check if test should
+ *                   loop.  Evaluates to TRUE (1) or FALSE (0).
+ *     TEST_ERROR_LOG(eno) - log that this errno was received,
+ *                   if STD_ERRNO_LOG is set.
+ *     TEST_EXP_ENOS(array) - set the bits in TEST_VALID_ENO array at
+ *                   positions specified in integer "array"
+ *
+ *    RETURN VALUE
+ *     TEST(SCALL) - Global Variables set:
+ *                     int TEST_RETURN=return code from SCALL
+ *                     int TEST_ERRNO=value of errno at return from SCALL
+ *     TEST_VOID(SCALL) - Global Variables set:
+ *                     int TEST_ERRNO=value of errno at return from SCALL
+ *     TEST_CLEANUP - None.
+ *     TEST_PAUSEF(HAND) -  None.
+ *     TEST_PAUSE -  None.
+ *     TEST_LOOPING(COUNTER) - True if COUNTER < STD_LOOP_COUNT or
+ *                     STD_INFINITE is set.
+ *     TEST_ERROR_LOG(eno) - None
+ *     TEST_EXP_ENOS(array) - None
+ *
+ *    KNOWN BUGS
+ *      If you use the TEST_PAUSE or TEST_LOOPING macros, you must
+ *     link in parse_opts.o, which contains the code for those functions.
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+
+#ifndef  __USCTEST_H__
+#define __USCTEST_H__ 1
+
+#ifndef _SC_CLK_TCK
+#include <unistd.h>
+#endif
+
+#include <sys/param.h>
+
+/* 
+ * Ensure that PATH_MAX is defined 
+ */
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX  MAXPATHLEN
+#else
+#define PATH_MAX  1024
+#endif
+#endif
+
+#ifndef CRAY
+#ifndef BSIZE 
+#define BSIZE BBSIZE
+#endif
+#endif
+
+/***********************************************************************
+ * Define option_t structure type.
+ * Entries in this struct are used by the parse_opts routine
+ * to indicate valid options and return option arguments
+ ***********************************************************************/
+typedef struct {               
+  char *option;        /* Valid option string (one option only) like "a:" */
+  int  *flag;          /* pointer to location to set true if option given */
+  char **arg;          /* pointer to location to place argument, if needed */
+} option_t;
+
+/***********************************************************************
+ * The following globals are defined in parse_opts.c but must be 
+ * externed here because they are used in the macros defined below.
+ ***********************************************************************/
+extern int STD_FUNCTIONAL_TEST,        /* turned off by -f to not do functional test */
+           STD_TIMING_ON,      /* turned on by -t to print timing stats */
+           STD_PAUSE,          /* turned on by -p to pause before loop */
+           STD_INFINITE,       /* turned on by -i0 to loop forever */
+           STD_LOOP_COUNT,     /* changed by -in to set loop count to n */
+           STD_ERRNO_LOG,      /* turned on by -e to log errnos returned */
+           STD_ERRNO_LIST[],   /* counts of errnos returned.  indexed by errno */
+          STD_COPIES,
+          STD_argind;
+
+extern float STD_LOOP_DURATION, /* wall clock time to iterate */
+            STD_LOOP_DELAY;    /* delay time after each iteration */
+
+#define USC_MAX_ERRNO  2000
+    
+/**********************************************************************
+ * Prototype for parse_opts routine
+ **********************************************************************/
+extern char *parse_opts(int ac, char **av, option_t *user_optarr, void (*uhf)(void));
+
+
+/*
+ * define a structure 
+ */
+struct usc_errno_t {
+    int flag;
+};
+
+/***********************************************************************
+ ****
+ **** 
+ ****
+ **********************************************************************/
+#ifdef  _USC_LIB_
+
+extern long TEST_RETURN;
+extern long TEST_ERRNO;
+extern struct usc_errno_t TEST_VALID_ENO[USC_MAX_ERRNO];
+extern long btime, etime, tmptime;
+
+#else
+/***********************************************************************
+ * Global array of bit masks to indicate errnos that are expected.
+ * Bits set by TEST_EXP_ENOS() macro and used by TEST_CLEANUP() macro.
+ ***********************************************************************/
+struct usc_errno_t TEST_VALID_ENO[USC_MAX_ERRNO];
+
+/***********************************************************************
+ * Globals for returning the return code and errno from the system call
+ * test macros.
+ ***********************************************************************/
+long TEST_RETURN;
+long TEST_ERRNO;
+
+/***********************************************************************
+ * temporary variables for determining max and min times in TEST macro
+ ***********************************************************************/
+long btime, etime, tmptime;    
+
+#endif  /* _USC_LIB_ */
+
+/***********************************************************************
+ * structure for timing accumulator and counters 
+ ***********************************************************************/
+struct tblock {
+    long tb_max;
+    long tb_min;
+    long tb_total;
+    long tb_count;
+};
+
+/***********************************************************************
+ * The following globals are externed here so that they are accessable
+ * in the macros that follow.
+ ***********************************************************************/
+extern struct tblock tblock;
+extern void STD_go(int);
+extern int (*_TMP_FUNC)(void);
+extern void STD_opts_help(void);
+
+
+/***********************************************************************
+ * TEST: calls a system call 
+ * 
+ * parameters:
+ *     SCALL = system call and parameters to execute
+ *
+ ***********************************************************************/
+#define TEST(SCALL) \
+       do { \
+               errno = 0; \
+               TEST_RETURN = SCALL; \
+               TEST_ERRNO = errno; \
+       } while (0)
+
+/***********************************************************************
+ * TEST_VOID: calls a system call
+ * 
+ * parameters:
+ *     SCALL = system call and parameters to execute
+ *
+ * Note: This is IDENTICAL to the TEST() macro except that it is intended
+ * for use with syscalls returning no values (void syscall()).  The 
+ * Typecasting nothing (void) into an unsigned integer causes compilation
+ * errors.
+ *
+ ***********************************************************************/
+#define TEST_VOID(SCALL)  errno=0; SCALL; TEST_ERRNO=errno;
+
+/***********************************************************************
+ * TEST_CLEANUP: print system call timing stats and errno log entries
+ * to stdout if STD_TIMING_ON and STD_ERRNO_LOG are set, respectively.
+ * Do NOT print ANY information if no system calls logged.
+ * 
+ * parameters:
+ *     none
+ *
+ ***********************************************************************/
+#define TEST_CLEANUP   \
+if ( STD_ERRNO_LOG ) {                                         \
+       for (tmptime=0; tmptime<USC_MAX_ERRNO; tmptime++) {             \
+            if ( STD_ERRNO_LIST[tmptime] )     {                       \
+                if ( TEST_VALID_ENO[tmptime].flag )                    \
+                    tst_resm(TINFO, "ERRNO %d:\tReceived %d Times",    \
+                             tmptime, STD_ERRNO_LIST[tmptime]);        \
+                else                                                   \
+                    tst_resm(TINFO,                                    \
+                             "ERRNO %d:\tReceived %d Times ** UNEXPECTED **",  \
+                             tmptime, STD_ERRNO_LIST[tmptime]);        \
+            }                                                          \
+       }                                                               \
+}
+
+/***********************************************************************
+ * TEST_PAUSEF: Pause for SIGUSR1 if the pause flag is set.
+ *              Set the user specified function as the interrupt
+ *              handler instead of "STD_go"
+ * 
+ * parameters:
+ *     none
+ *
+ ***********************************************************************/
+#define TEST_PAUSEF(HANDLER)                                   \
+if ( STD_PAUSE ) {                                     \
+    _TMP_FUNC = (int (*)(void))signal(SIGUSR1, HANDLER);       \
+    pause();                                           \
+    signal(SIGUSR1, (void (*)(void))_TMP_FUNC);                \
+}
+
+/***********************************************************************
+ * TEST_PAUSE: Pause for SIGUSR1 if the pause flag is set.
+ *            Just continue when signal comes in.
+ * 
+ * parameters:
+ *     none
+ *
+ ***********************************************************************/
+#define TEST_PAUSE usc_global_setup_hook();
+int usc_global_setup_hook(void);
+
+/***********************************************************************
+ * TEST_LOOPING now call the usc_test_looping function.
+ * The function will return 1 if the test should continue
+ * iterating.
+ *
+ ***********************************************************************/
+#define TEST_LOOPING usc_test_looping
+int usc_test_looping(int counter);
+
+/***********************************************************************
+ * TEST_ERROR_LOG(eno): log this errno if STD_ERRNO_LOG flag set
+ * 
+ * parameters:
+ *     int eno: the errno location in STD_ERRNO_LIST to log.
+ *
+ ***********************************************************************/
+#define TEST_ERROR_LOG(eno)            \
+    if ( STD_ERRNO_LOG )               \
+        if ( eno < USC_MAX_ERRNO )             \
+            STD_ERRNO_LIST[eno]++;     \
+
+
+/***********************************************************************
+ * TEST_EXP_ENOS(array): set the bits associated with the nput errnos
+ *     in the TEST_VALID_ENO array.
+ * 
+ * parameters:
+ *     int array[]: a zero terminated array of errnos expected.
+ *
+ ***********************************************************************/
+#define TEST_EXP_ENOS(array)                           \
+    tmptime=0;                                         \
+    while (array[tmptime] != 0) {                      \
+       if (array[tmptime] < USC_MAX_ERRNO)             \
+           TEST_VALID_ENO[array[tmptime]].flag=1;      \
+       tmptime++;                                      \
+    }
+                                       
+
+#endif  /* end of __USCTEST_H__ */
diff --git a/test/ipc/msgctl/Makefile b/test/ipc/msgctl/Makefile
new file mode 100644 (file)
index 0000000..9071354
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  Copyright (c) International Business Machines  Corp., 2001
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+CFLAGS += -I../lib -I../../../../../include -Wall
+LDLIBS += -L../../../../../lib -lltp -L.. -lipc
+
+SRCS    = $(wildcard *.c)
+TARGETS = $(patsubst %.c,%,$(SRCS))
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i ; done
+
+clean:
+       rm -f $(TARGETS)
diff --git a/test/ipc/msgctl/msgctl01.c b/test/ipc/msgctl/msgctl01.c
new file mode 100644 (file)
index 0000000..eb1c302
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgctl01.c
+ *
+ * DESCRIPTION
+ *     msgctl01 - create a message queue, then issue the IPC_STAT command
+ *                and RMID commands to test the functionality
+ *
+ * ALGORITHM
+ *     create a message queue
+ *     loop if that option was specified
+ *     call msgctl() with the IPC_STAT command
+ *     check the return code
+ *       if failure, issue a FAIL message and break remaining tests
+ *     otherwise,
+ *       if doing functionality testing
+ *             if the max number of bytes on the queue is > 0,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *       else issue a PASS message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgctl01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgctl01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int msg_q_1 = -1;                      /* to hold the message queue id */
+
+struct msqid_ds qs_buf;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Get the msqid_ds structure values for the queue
+                */
+       
+               TEST(msgctl(msg_q_1, IPC_STAT, &qs_buf));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d"
+                                " : %s", TCID, TEST_ERRNO,
+                                strerror(TEST_ERRNO));
+               } else {
+                       if (STD_FUNCTIONAL_TEST) {
+                               if (qs_buf.msg_qbytes > 0) {    
+                                       tst_resm(TPASS, "qs_buf.msg_qbytes is"
+                                                " a positive value");
+                               } else {
+                                       tst_resm(TFAIL, "qs_buf.msg_qbytes did"
+                                                " not change");
+                               }
+                       } else {
+                               tst_resm(TPASS, "msgctl() call succeeded");
+                       }
+               }
+
+               /*
+                * clean up things in case we are looping
+                */
+               qs_buf.msg_qbytes = 0x0000;
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get a message key */
+       msgkey = getipckey();
+
+       /* make sure the initial # of bytes is 0 in our buffer */
+       qs_buf.msg_qbytes = 0x0000;
+
+       /* now we have a key, so let's create a message queue */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl02.c b/test/ipc/msgctl/msgctl02.c
new file mode 100644 (file)
index 0000000..32e03f8
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgctl02.c
+ *
+ * DESCRIPTION
+ *     msgctl02 - create a message queue, then issue the IPC_SET command
+ *                to lower the msg_qbytes value.
+ *
+ * ALGORITHM
+ *     create a message queue
+ *     loop if that option was specified
+ *     call msgctl() with the IPC_SET command with a new msg_qbytes value
+ *     check the return code
+ *       if failure, issue a FAIL message and break remaining tests
+ *     otherwise,
+ *       if doing functionality testing
+ *             if the msg_qbytes value is the new value
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *       else issue a PASS message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgctl02 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgctl02";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int msg_q_1 = -1;                      /* to hold the message queue id */
+
+struct msqid_ds qs_buf;
+
+unsigned short new_bytes;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Set the msqid_ds structure values for the queue
+                */
+       
+               TEST(msgctl(msg_q_1, IPC_SET, &qs_buf));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d"
+                                " : %s", TCID, TEST_ERRNO,
+                                strerror(TEST_ERRNO));
+               } else {
+                       if (STD_FUNCTIONAL_TEST) {
+
+                               /* do a stat to get current queue values */
+                               if ((msgctl(msg_q_1, IPC_STAT, &qs_buf) == -1)){
+                                       tst_resm(TBROK, "stat on queue failed");
+                                       continue;
+                               }
+
+                               if (qs_buf.msg_qbytes == new_bytes) {   
+                                       tst_resm(TPASS, "qs_buf.msg_qbytes is"
+                                                " the new value - %d",
+                                                qs_buf.msg_qbytes);
+                               } else {
+                                       tst_resm(TFAIL, "qs_buf.msg_qbytes "
+                                                "value is not expected");
+                                       tst_resm(TINFO, "expected - %d, "
+                                                "received - %d", new_bytes,
+                                                qs_buf.msg_qbytes);
+                               }
+                       } else {
+                               tst_resm(TPASS, "msgctl() call succeeded");
+                       }
+               }
+
+               /*
+                * decrement by one the msq_qbytes value
+                */
+               qs_buf.msg_qbytes -= 1;
+               new_bytes = qs_buf.msg_qbytes;
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get a message key */
+       msgkey = getipckey();
+
+       /* make sure the initial # of bytes is 0 in our buffer */
+       qs_buf.msg_qbytes = 0x3000;
+
+       /* now we have a key, so let's create a message queue */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* now stat the queue to get the default msg_qbytes value */
+       if ((msgctl(msg_q_1, IPC_STAT, &qs_buf)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't stat the message queue");
+       }
+
+       /* decrement msg_qbytes and copy its value */
+       qs_buf.msg_qbytes -= 1;
+       new_bytes = qs_buf.msg_qbytes;
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl03.c b/test/ipc/msgctl/msgctl03.c
new file mode 100644 (file)
index 0000000..3027b9c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgctl03.c
+ *
+ * DESCRIPTION
+ *     msgctl03 - create a message queue, then issue the IPC_RMID command
+ *
+ * ALGORITHM
+ *     create a message queue
+ *     loop if that option was specified
+ *     call msgctl() with the IPC_RMID command
+ *     check the return code
+ *       if failure, issue a FAIL message and break remaining tests
+ *     otherwise,
+ *       if doing functionality testing
+ *             issue an IPC_STAT on the queue that was just removed
+ *             if the call fails
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *       else issue a PASS message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgctl03 [-c n] [-f] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     This test does not support looping.
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgctl03";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int msg_q_1 = -1;                      /* to hold the message queue id */
+
+struct msqid_ds qs_buf;
+
+int main(int ac, char **av)
+{
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /*
+        * Remove the queue that was created in setup()
+        */
+
+       TEST(msgctl(msg_q_1, IPC_RMID, NULL));
+       
+       if (TEST_RETURN == -1) {
+               tst_brkm(TFAIL, cleanup, "%s call failed - errno = %d"
+                        " : %s", TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+       } else {
+               if (STD_FUNCTIONAL_TEST) {
+                       /*
+                        * if the queue is gone, then an IPC_STAT msgctl()
+                        * call should generate an EINVAL error.
+                        */
+                       if ((msgctl(msg_q_1, IPC_STAT, &qs_buf) == -1)){
+                               if (errno == EINVAL) {  
+                                       tst_resm(TPASS, "The queue is gone");
+                               } else {
+                                       tst_resm(TFAIL, "IPC_RMID succeeded ,"
+                                                " but functional test did not"
+                                                " get expected EINVAL error");
+                               }
+                       }
+               } else {
+                       tst_resm(TPASS, "msgctl() call succeeded");
+               }
+       }
+
+       msg_q_1 = -1;
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get a message key */
+       msgkey = getipckey();
+
+       /* now we have a key, so let's create a message queue */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl04.c b/test/ipc/msgctl/msgctl04.c
new file mode 100644 (file)
index 0000000..fc8866b
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgctl04.c
+ *
+ * DESCRIPTION
+ *     msgctl04 - test for EACCES, EFAULT and EINVAL errors using
+ *                a variety of incorrect calls.
+ *
+ * ALGORITHM
+ *     create two message queues
+ *     loop if that option was specified
+ *     try to access a queue with some invalid argument
+ *     check the errno value
+ *       issue a PASS message if we get EACCES, EFAULT or EINVAL
+ *       depending on the test case
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgctl04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+#include <pwd.h>
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgctl04";
+int TST_TOTAL = 6;
+extern int Tst_count;
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+int exp_enos[] = {EACCES, EFAULT, EINVAL, 0};
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+int msg_q_2 = -1;              /* Another queue id created in setup */
+int bad_q = -1;                        /* a value to use as a bad queue id */
+
+struct msqid_ds q_buf;
+
+struct test_case_t {           /* This allows testing of many negative */
+        int *queue_id;         /* test cases that can all use the same */
+        int ipc_cmd;           /* basic test setup.                    */
+        struct msqid_ds *buf;
+       int error;
+} TC[] = {
+       /* EACCES - there is no read permission for the queue */
+        {&msg_q_1, IPC_STAT, &q_buf, EACCES},
+
+       /* EFAULT - the structure address is invalid - IPC_STAT */
+        {&msg_q_2, IPC_STAT, (struct msqid_ds *)-1, EFAULT},
+
+       /* EFAULT - the structure address is invalid - IPC_SET */
+        {&msg_q_2, IPC_SET, (struct msqid_ds *)-1, EFAULT},
+
+       /* EINVAL - the command (-1) is invalid */
+        {&msg_q_2, -1, &q_buf, EINVAL},
+
+       /* EINVAL - the queue id is invalid - IPC_STAT */
+        {&bad_q, IPC_STAT, &q_buf, EINVAL},
+
+       /* EINVAL - the queue id is invalid - IPC_SET */
+        {&bad_q, IPC_SET, &q_buf, EINVAL}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       TEST(msgctl(*(TC[i].queue_id), TC[i].ipc_cmd,
+                                   TC[i].buf));
+
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "msgctl() call succeeded "
+                                        "on expected fail");
+                               continue;
+                       }
+
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - "
+                                        "errno = %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - %d : %s -",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                               tst_resm(TINFO, "expected error is - %d : %s",
+                                        TC[i].error, strerror(TC[i].error));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+        /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+        ltpuser = getpwnam(nobody_uid);
+        if (setuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("setuid");
+        }
+
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* now we have a key, so let's create a message queue */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue #1" );
+       }
+
+       /* now let's create another message queue with read & write access */
+       if ((msg_q_2 = 
+          msgget(msgkey + 1, IPC_CREAT | IPC_EXCL | MSG_RD | MSG_WR)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue #2" );
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * remove the message queues that were created.
+        */
+       rm_queue(msg_q_1);
+
+       rm_queue(msg_q_2);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl05.c b/test/ipc/msgctl/msgctl05.c
new file mode 100644 (file)
index 0000000..153a918
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgctl05.c
+ *
+ * DESCRIPTION
+ *     msgctl05 - test for EPERM error
+ *
+ * ALGORITHM
+ *     create a message queue as root
+ *     fork a child process and change its ID to nobody        
+ *     loop if that option was specified
+ *     try to remove the queue in the child process with msgctl()
+ *     check the errno value
+ *       issue a PASS message if we get EPERM
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *       break any remaining tests
+ *       call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgctl05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     The test must be run as root.
+ *     There must be a nobody ID installed on the system.
+ */
+
+#include <string.h>
+#include <pwd.h>
+#include <sys/wait.h>
+
+#include "test.h"
+#include "usctest.h"
+
+
+#include "ipcmsg.h"
+
+char *TCID = "msgctl05";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EPERM, 0};   /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+uid_t ltp_uid;                 /* The user ID for a non root user */
+char *ltp_user = "nobody";     /* A non root user */
+
+struct msqid_ds q_buf;
+
+int main(int ac, char **av)
+{
+       char *msg;                      /* message returned from parse_opts */
+       pid_t pid;
+       void do_child(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       if ((pid = FORK_OR_VFORK()) == -1) {
+               tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (pid == 0) {         /* child */
+               /* set the user ID of the child to nobody */
+               if (setuid(ltp_uid) == -1) {
+                       tst_resm(TBROK, "setuid() failed");
+                       exit(1);
+               }
+       
+               do_child();
+       } else {                /* parent */
+               if (waitpid(pid, NULL, 0) == -1) {
+                       tst_resm(TBROK, "waitpid() failed");
+                       tst_resm(TINFO, "waitpid() error = %d : %s", errno,
+                                strerror(errno));
+               }
+
+               /* if it exists, remove the message queue */
+               rm_queue(msg_q_1);
+
+               /* Remove the temporary directory */
+               tst_rmdir();
+       }
+
+       cleanup ();
+        /**NOT REACHED**/
+       return(0);
+}
+
+/*
+ * do_child - make the TEST call as the child process
+ */
+void
+do_child()
+{
+       int lc;                         /* loop counter */
+       int i;
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+
+               for (i=0; i<TST_TOTAL; i++) {
+                       TEST(msgctl(msg_q_1, IPC_RMID, NULL));
+
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "msgget() call succeeded "
+                                        "on expected fail");
+                               continue;
+                       }
+
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case EPERM:
+                               tst_resm(TPASS, "expected error = %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                               break;
+                       default:
+                               tst_resm(TFAIL, "call failed with unexpected "
+                                        "error - %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* check for root as user id of process */
+       check_root();
+
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* now we have a key, so let's create a message queue */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue #1" );
+       }
+
+       /* get the user ID for a non root user */
+       ltp_uid = getuserid(ltp_user);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl06.c b/test/ipc/msgctl/msgctl06.c
new file mode 100644 (file)
index 0000000..9e6f1f4
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+/* 11/06/2002  Port to LTP     dbarrera@us.ibm.com */
+
+/*
+ * NAME
+ *     msgctl06
+ *
+ * CALLS
+ *     msgget(2) msgctl(2)
+ *
+ * ALGORITHM
+ *     Get and manipulate a message queue.
+ *
+ * RESTRICTIONS
+ *
+ */
+
+
+
+#include <sys/types.h>         /* needed for test              */
+#include <sys/ipc.h>           /* needed for test              */
+#include <sys/msg.h>           /* needed for test              */
+#include <stdio.h>             /* needed by testhead.h         */
+#include <errno.h>             /* definitions needed for errno */
+#include "test.h"
+#include "usctest.h"
+
+void setup();
+void cleanup();
+/*
+ *  *  * These globals must be defined in the test.
+ *   *   */
+
+
+char *TCID="msgctl06";           /* Test program identifier.    */
+int TST_TOTAL=1;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+int exp_enos[]={0};     /* List must end with 0 */
+
+
+/*
+ * msgctl3_t -- union of msgctl(2)'s possible argument # 3 types.
+ */
+typedef union msgctl3_u {
+       struct msqid_ds *msq_ds;        /* pointer to msqid_ds struct */
+       struct ipc_acl  *msq_acl;       /* pointer ACL buff and size */
+} msgctl3_t;
+
+extern int local_flag;
+
+int    msqid, status;
+struct msqid_ds        buf;
+
+
+#define K 1024
+
+/*--------------------------------------------------------------*/
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+       key_t           key;
+       setup();
+
+       key = 2 * K;
+       TEST(msgget(key, IPC_CREAT));
+       msqid = TEST_RETURN;
+       if (TEST_RETURN == -1)
+       {
+                tst_resm(TFAIL, "msgget() failed errno = %d", errno);
+               tst_exit();
+       }
+       TEST(msgctl(msqid, IPC_STAT, &buf));
+       status = TEST_RETURN;
+       if (TEST_RETURN == -1)
+       {
+               (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                tst_resm(TFAIL, "msgctl(msqid, IPC_STAT, &buf) failed errno = %d", errno);
+               tst_exit();
+       }
+
+       /*
+        * Check contents of msqid_ds structure.
+        */
+
+       if (buf.msg_qnum != 0) 
+       {
+                tst_resm(TFAIL, "error: unexpected nbr of messages %d", buf.msg_qnum);
+               tst_exit();
+       }
+       if (buf.msg_perm.uid != getuid()) 
+       {
+                tst_resm(TFAIL, "error: unexpected uid %d", buf.msg_perm.uid);
+               tst_exit();
+       }
+       if (buf.msg_perm.gid != getgid())
+       {
+                tst_resm(TFAIL, "error: unexpected gid %d", buf.msg_perm.gid);
+               tst_exit();
+       }
+       if (buf.msg_perm.cuid != getuid())
+       {
+                tst_resm(TFAIL, "error: unexpected cuid %d", buf.msg_perm.cuid);
+               tst_exit();
+       }
+       if (buf.msg_perm.cgid != getgid())
+       {
+                tst_resm(TFAIL, "error: unexpected cgid %d", buf.msg_perm.cgid);
+               tst_exit();
+       }
+
+
+       tst_resm(TPASS,"msgctl06 ran successfully!");
+    /***************************************************************
+     * cleanup and exit
+     ***************************************************************/
+       cleanup();
+
+       return 0;
+}       /* End main */    
+
+
+/***************************************************************
+ *  * setup() - performs all ONE TIME setup for this test.
+ *   ****************************************************************/
+void
+setup()
+{
+       /* You will want to enable some signal handling so you can capture
+        * unexpected signals like SIGSEGV.
+        */
+        tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+        /* Pause if that option was specified */
+        /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
+        * fork the test with the -c option.  You want to make sure you do this
+        * before you create your temporary directory.
+        */
+       TEST_PAUSE;
+}
+
+
+/***************************************************************
+ *  *  * cleanup() - performs all ONE TIME cleanup for this test at
+ *   *   *              completion or premature exit.
+ *    *    ***************************************************************/
+void
+cleanup()
+{
+       int status;
+               /*
+        * print timing stats if that option was specified.
+         * print errno log if that option was specified.
+         */
+        TEST_CLEANUP;
+
+        /*
+         * Remove the message queue from the system
+         */
+#ifdef DEBUG
+       tst_resm(TINFO,"Remove the message queue");
+#endif
+       fflush (stdout);
+       (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+       if ((status = msgctl(msqid, IPC_STAT, &buf)) != -1)
+       {
+               (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                tst_resm(TFAIL, "msgctl(msqid, IPC_RMID) failed");
+               tst_exit();
+               
+       }
+
+       fflush (stdout);
+        /* exit with return code appropriate for results */
+        tst_exit();
+}
diff --git a/test/ipc/msgctl/msgctl07.c b/test/ipc/msgctl/msgctl07.c
new file mode 100644 (file)
index 0000000..826bc50
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+/* 11/06/2002   Port to LTP     dbarrera@us.ibm.com */
+
+
+/*
+ * NAME
+ *     msgctl07
+ *
+ * CALLS
+ *     msgget(2) msgctl(2) msgop(2)
+ *
+ * ALGORITHM
+ *     Get and manipulate a message queue.
+ *
+ * RESTRICTIONS
+ *
+ */
+
+
+#include <sys/types.h>         /* needed for test              */
+#include <sys/ipc.h>           /* needed for test              */
+#include <sys/msg.h>           /* needed for test              */
+#include <signal.h>            /* needed for test              */
+#include <wait.h>              /* needed for test              */
+#include <stdio.h>             /* needed by testhead.h         */
+#include "test.h"
+#include "usctest.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+typedef void (*sighandler_t)(int);
+volatile int ready;
+
+#define K 1024
+#define BYTES 100
+#define SECS 10
+
+void setup();
+void cleanup();
+void do_child_1();
+void do_child_2();
+
+/*
+ *  *  *  * These globals must be defined in the test.
+ *   *   *   */
+
+char *TCID="msgctl07";           /* Test program identifier.    */
+int TST_TOTAL=1;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+/* Used by main() and do_child_1(): */
+static int msqid;
+struct my_msgbuf {
+       long type;
+       char text[BYTES];
+} p1_msgp, p2_msgp, p3_msgp, c1_msgp, c2_msgp, c3_msgp;
+
+
+/*--------------------------------------------------------------*/
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+       key_t key;
+       int pid, status;
+       int i, j, k;
+       sighandler_t alrm();
+
+#ifdef UCLINUX
+       char *msg;
+
+        /* parse standard options */
+        if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
+                                                       (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+        }
+
+       maybe_run_child(&do_child_1, "ndd", 1, &msqid, &c1_msgp.type);
+       maybe_run_child(&do_child_2, "ndddd", 2, &msqid, &c1_msgp.type,
+                       &c2_msgp.type, &c3_msgp.type);
+#endif
+
+       key = 2 * K;
+       if ((msqid = msgget(key, IPC_CREAT)) == -1) 
+        {
+                tst_resm(TFAIL, "msgget() failed errno = %d", errno);
+                tst_exit();
+
+       }
+
+       pid = FORK_OR_VFORK();
+       if (pid < 0) {
+               (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
+                tst_exit();
+       }
+       else if (pid == 0) {
+#ifdef UCLINUX
+               if (self_exec(argv[0], "ndd", 1, msqid, c1_msgp.type) < 0) {
+                       tst_resm(TFAIL, "\tself_exec failed");
+                       tst_exit();
+               }
+#else
+               do_child_1();
+#endif
+       }
+       else {
+               struct sigaction act;
+
+               memset(&act, 0, sizeof(act));
+               act.sa_handler = (sighandler_t) alrm;
+               sigemptyset(&act.sa_mask);
+               sigaddset(&act.sa_mask, SIGALRM);
+               if ((sigaction(SIGALRM, &act, NULL)) < 0) {
+                       kill(pid, SIGKILL);
+                       (void)msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                       tst_resm(TFAIL, "signal failed. errno = %d", errno);
+                       tst_exit();
+               }
+               ready = 0;
+               alarm(SECS);
+               while (!ready)          /* make the child wait */
+                       ;
+               for (i=0; i<BYTES; i++) 
+                       p1_msgp.text[i] = 'i';
+               p1_msgp.type = 1;
+               if (msgsnd(msqid, &p1_msgp, BYTES, 0) == -1) {
+                       kill(pid, SIGKILL);
+                       (void)msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                       tst_resm(TFAIL, "msgsnd() failed. errno = %d", errno);
+                       tst_exit();
+               }
+               wait(&status);
+       }
+       if ((status >> 8) == 1)
+       {
+                       tst_resm(TFAIL, "test failed. status = %d", (status >> 8));
+                       tst_exit();
+       }
+       
+       pid = FORK_OR_VFORK();
+       if (pid < 0) {
+               (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
+               tst_exit();
+       }
+       else if (pid == 0) {
+#ifdef UCLINUX
+               if (self_exec(argv[0], "ndddd", 1, msqid, c1_msgp.type,
+                             c2_msgp.type, c3_msgp.type) < 0) {
+                       tst_resm(TFAIL, "\tself_exec failed");
+                       tst_exit();
+               }
+#else
+               do_child_2();
+#endif
+       }
+       else {
+               struct sigaction act;
+
+               memset(&act, 0, sizeof(act));
+               act.sa_handler = (sighandler_t) alrm;
+               sigemptyset(&act.sa_mask);
+               sigaddset(&act.sa_mask, SIGALRM);
+               if ((sigaction(SIGALRM, &act, NULL)) < 0) {
+                       kill(pid, SIGKILL);
+                       (void)msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                       tst_resm(TFAIL, "signal failed. errno = %d", errno);
+                       tst_exit();
+               }
+               ready = 0;
+               alarm(SECS);
+               while (!ready)          /* make the child wait */
+                       ;
+               for (i=0; i<BYTES; i++) 
+                       p1_msgp.text[i] = 'i';
+               p1_msgp.type = 1;
+               if (msgsnd(msqid, &p1_msgp, BYTES, 0) == -1) {
+                       kill(pid, SIGKILL);
+                       (void)msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                       tst_resm(TFAIL, "msgsnd() failed. errno = %d", errno);
+                       tst_exit();
+               }
+               for (j=0; j<BYTES; j++) 
+                       p2_msgp.text[j] = 'j';
+               p2_msgp.type = 2;
+               if (msgsnd(msqid, &p2_msgp, BYTES, 0) == -1) {
+                       kill(pid, SIGKILL);
+                       (void)msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                       tst_resm(TFAIL, "msgsnd() failed. errno = %d", errno);
+                       tst_exit();
+               }
+               for (k=0; k<BYTES; k++) 
+                       p3_msgp.text[k] = 'k';
+               p3_msgp.type = 3;
+               if (msgsnd(msqid, &p3_msgp, BYTES, 0) == -1) {
+                       kill(pid, SIGKILL);
+                       (void)msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                       tst_resm(TFAIL, "msgsnd() failed. errno = %d", errno);
+                       tst_exit();
+               }
+               wait(&status);
+       }
+       if ((status >> 8) == 1)
+       {
+                       tst_resm(TFAIL, "test failed. status = %d", (status >> 8));
+                       tst_exit();
+       }
+        /*
+        * Remove the message queue from the system
+        */
+#ifdef DEBUG
+        tst_resm(TINFO,"Removing the message queue");
+#endif
+        fflush (stdout);
+        (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+        if ((status = msgctl(msqid, IPC_STAT, (struct msqid_ds *)NULL)) != -1)
+        {
+                (void) msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
+                tst_resm(TFAIL, "msgctl(msqid, IPC_RMID) failed");
+                tst_exit();
+
+        }
+
+        fflush (stdout);
+        tst_resm(TPASS,"msgctl07 ran successfully!");
+        return (0);
+
+}
+/*--------------------------------------------------------------*/
+
+sighandler_t alrm(sig)
+int sig;
+{
+       ready++;
+       return(0);
+}
+/*--------------------------------------------------------------*/
+
+void
+do_child_1()
+{      
+       int i;
+       int size;
+
+       if ((size = msgrcv(msqid, &c1_msgp, BYTES, 0, 0)) == -1)
+       {
+               tst_resm(TFAIL, "msgrcv() failed errno = %d", errno);
+               tst_exit();
+       }
+       if (size != BYTES) 
+       {
+               tst_resm(TFAIL, "error: received %d bytes expected %d", size, BYTES);
+               tst_exit();
+       }
+       for (i=0; i<BYTES; i++) 
+               if (c1_msgp.text[i] != 'i') 
+               {
+                       tst_resm(TFAIL, "error: corrup message");
+                       tst_exit();
+               }
+       exit(0);
+}
+
+void
+do_child_2()
+{
+       int i, j, k;
+       int size;
+
+       if ((size = msgrcv(msqid, &c3_msgp, BYTES, 3, 0)) == -1) {
+               tst_resm(TFAIL, "msgrcv() failed errno = %d", errno);
+               tst_exit();
+       }
+       if (size != BYTES) {
+               tst_resm(TFAIL, "error: received %d bytes expected %d", size, BYTES);
+               tst_exit();
+       }
+       for (k=0; k<BYTES; k++) 
+               if (c3_msgp.text[k] != 'k') {
+                       tst_resm(TFAIL, "error: corrupt message");
+                       tst_exit();
+               }
+       if ((size = msgrcv(msqid, &c2_msgp, BYTES, 2, 0)) == -1) {
+               tst_resm(TFAIL, "msgrcv() failed errno = %d", errno);
+               tst_exit();
+       }
+       if (size != BYTES) {
+               tst_resm(TFAIL, "error: received %d bytes expected %d", size, BYTES);
+               tst_exit();
+       }
+       for (j=0; j<BYTES; j++) 
+               if (c2_msgp.text[j] != 'j') {
+                       tst_resm(TFAIL, "error: corrupt message");
+                       tst_exit();
+               }
+       if ((size = msgrcv(msqid, &c1_msgp, BYTES, 1, 0)) == -1) {
+               tst_resm(TFAIL, "msgrcv() failed errno = %d", errno);
+               tst_exit();
+       }
+       if (size != BYTES) {
+               tst_resm(TFAIL, "error: received %d bytes expected %d", size, BYTES);
+               tst_exit();
+       }
+       for (i=0; i<BYTES; i++) 
+               if (c1_msgp.text[i] != 'i') {
+                       tst_resm(TFAIL, "error: corrupt message");
+                       tst_exit();
+               }
+       
+       exit(0);
+}
+
+/***************************************************************
+ * setup() - performs all ONE TIME setup for this test.
+ ****************************************************************/
+void
+setup()
+{
+        /* You will want to enable some signal handling so you can capture
+        * unexpected signals like SIGSEGV.
+         */
+        tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
+        * fork the test with the -c option.  You want to make sure you do this
+         * before you create your temporary directory.
+         */
+       TEST_PAUSE;
+}
+
+
+/***************************************************************
+ *  * cleanup() - performs all ONE TIME cleanup for this test at
+ *   *              completion or premature exit.
+ *    ***************************************************************/
+void
+cleanup()
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl08.c b/test/ipc/msgctl/msgctl08.c
new file mode 100644 (file)
index 0000000..609ac50
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+/* 11/06/2002   Port to LTP     dbarrera@us.ibm.com */
+
+/*
+ * NAME
+ *     msgctl08
+ *
+ * CALLS
+ *     msgget(2) msgctl(2) 
+ *
+ * ALGORITHM
+ *     Get and manipulate a message queue.
+ *
+ * RESTRICTIONS
+ *
+ */
+
+#define _XOPEN_SOURCE 500
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <values.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include "test.h"
+#include "usctest.h"
+
+void setup();
+void cleanup();
+/*
+ *  *  *  * These globals must be defined in the test.
+ *   *   *   */
+
+
+char *TCID="msgctl08";           /* Test program identifier.    */
+int TST_TOTAL=1;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+int exp_enos[]={0};     /* List must end with 0 */
+
+#ifndef CONFIG_COLDFIRE
+#define MAXNPROCS      1000000  /* This value is set to an arbitrary high limit. */
+#else
+#define MAXNPROCS       100000   /* Coldfire can't deal with 1000000 */
+#endif
+#define MAXNREPS       100000
+#define FAIL           1
+#define PASS           0
+
+key_t  keyarray[MAXNPROCS];    
+
+struct {
+       long    type;
+       struct {
+               char    len;
+               char    pbytes[99];
+               } data;
+       } buffer;
+
+int    pidarray[MAXNPROCS];
+int tid;
+int MSGMNI,nprocs, nreps;
+int procstat;
+int dotest(key_t key, int child_process);
+int doreader(int id, long key, int child);
+int dowriter(int id,long key, int child);
+int fill_buffer(register char *buf, char val, register int size);
+int verify(register char *buf,char val, register int size,int child);
+void sig_handler();             /* signal catching function */
+int mykid;
+#ifdef UCLINUX
+static char *argv0;
+
+void do_child_1_uclinux();
+static key_t key_uclinux;
+static int i_uclinux;
+
+void do_child_2_uclinux();
+static int id_uclinux;
+static int child_process_uclinux;
+#endif
+
+/*-----------------------------------------------------------------*/
+int main(argc, argv)
+int    argc;
+char   *argv[];
+{
+       register int i, j, ok, pid;
+       int count, status;
+       struct sigaction act;
+
+#ifdef UCLINUX
+       char *msg;                      /* message returned from parse_opts */
+
+       argv0 = argv[0];
+
+       /* parse standard options */
+       if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL)
+       {
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+       
+       maybe_run_child(&do_child_1_uclinux, "ndd", 1, &key_uclinux, &i_uclinux);
+       maybe_run_child(&do_child_2_uclinux, "nddd", 2, &id_uclinux, &key_uclinux,
+                       &child_process_uclinux);
+#endif
+
+       setup();
+       
+       if (argc == 1 )
+       {
+               /* Set default parameters */
+               nreps = MAXNREPS;
+               nprocs = MSGMNI;
+       }
+       else if (argc == 3 )
+       {
+               if ( atoi(argv[1]) > MAXNREPS )
+               {
+                       tst_resm(TCONF,"Requested number of iterations too large, setting to Max. of %d", MAXNREPS);
+                       nreps = MAXNREPS;
+               }
+               else
+               {
+                       nreps = atoi(argv[1]);
+               }
+               if (atoi(argv[2]) > MSGMNI )
+               {
+                       tst_resm(TCONF,"Requested number of processes too large, setting to Max. of %d", MSGMNI);
+                       nprocs = MSGMNI;
+               }
+               else
+               {
+                       nprocs = atoi(argv[2]);
+               }
+       }
+       else
+       {
+               tst_resm(TCONF," Usage: %s [ number of iterations  number of processes ]", argv[0]);
+               tst_exit();
+       }
+
+       srand(getpid());
+       tid = -1;
+
+       /* Setup signal handleing routine */
+       memset(&act, 0, sizeof(act));
+       act.sa_handler = sig_handler;
+       sigemptyset(&act.sa_mask);
+       sigaddset(&act.sa_mask, SIGTERM);
+       if (sigaction(SIGTERM, &act, NULL) < 0) 
+       {
+                tst_resm(TFAIL, "Sigset SIGTERM failed");
+                tst_exit();
+       }
+       /* Set up array of unique keys for use in allocating message
+        * queues
+        */
+       for (i = 0; i < nprocs; i++) 
+       {
+               ok = 1;
+               do 
+               {
+                       /* Get random key */
+                       keyarray[i] = (key_t)rand();
+                       /* Make sure key is unique and not private */
+                       if (keyarray[i] == IPC_PRIVATE) 
+                       {
+                               ok = 0;
+                               continue;
+                       }
+                       for (j = 0; j < i; j++) 
+                       {
+                               if (keyarray[j] == keyarray[i]) 
+                               {
+                                       ok = 0;
+                                       break;
+                               }
+                               ok = 1;
+                       }
+               } while (ok == 0);
+       }
+        
+       /* Fork a number of processes, each of which will
+        * create a message queue with one reader/writer
+        * pair which will read and write a number (iterations)
+        * of random length messages with specific values.
+        */
+
+       for (i = 0; i <  nprocs; i++) 
+       {
+               fflush(stdout);
+               if ((pid = FORK_OR_VFORK()) < 0) 
+               {
+                       tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
+                       tst_exit();
+               }
+               /* Child does this */
+               if (pid == 0) 
+               {
+#ifdef UCLINUX
+                       if (self_exec(argv[0], "ndd", 1, keyarray[i], i) < 0)
+                       {
+                               tst_resm(TFAIL, "\tself_exec failed");
+                               tst_exit();
+                       }
+#else
+                       procstat = 1;
+                       exit( dotest(keyarray[i], i) );
+#endif
+               }
+               pidarray[i] = pid;
+       }
+
+       count = 0;
+       while(1)
+       {
+               if (( wait(&status)) > 0)
+               {
+                       if (status>>8 != 0 )
+                       {
+                               tst_resm(TFAIL, "Child exit status = %d", status>>8);
+                               tst_exit();
+                       }
+                       count++;
+               }       
+               else
+               {
+                       if (errno != EINTR)
+                       {       
+                               break;
+                       }
+#ifdef DEBUG
+                       tst_resm(TINFO,"Signal detected during wait");
+#endif
+               }
+       }
+       /* Make sure proper number of children exited */
+       if (count != nprocs)
+       {
+                tst_resm(TFAIL, "Wrong number of children exited, Saw %d, Expected %d", count, nprocs);
+                       tst_exit();
+       }
+
+        tst_resm(TPASS,"msgctl08 ran successfully!");
+        
+       cleanup();
+        return (0);
+                                                               
+}
+/*--------------------------------------------------------------------*/
+
+#ifdef UCLINUX
+void
+do_child_1_uclinux()
+{
+       procstat = 1;
+       exit(dotest(key_uclinux, i_uclinux));
+}
+
+void
+do_child_2_uclinux()
+{
+       exit(doreader(id_uclinux, key_uclinux % 255, child_process_uclinux));
+}
+#endif
+
+int dotest(key, child_process)
+key_t  key;
+int    child_process;
+{
+       int id, pid;
+
+       sighold(SIGTERM);
+                TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR));
+       if (TEST_RETURN < 0)
+       {
+                tst_resm(TFAIL, "Msgget error in child %d, errno = %d", child_process, TEST_ERRNO);
+                       tst_exit();
+       }
+       tid = id = TEST_RETURN;
+       sigrelse(SIGTERM);
+
+       fflush(stdout);
+       if ((pid = FORK_OR_VFORK()) < 0) 
+       {
+                tst_resm(TWARN, "\tFork failed (may be OK if under stress)");
+               TEST(msgctl(tid, IPC_RMID, 0));
+               if (TEST_RETURN < 0)
+               {
+                       tst_resm(TFAIL, "Msgctl error in cleanup, errno = %d", errno);
+               }
+                       tst_exit();
+       }
+       /* Child does this */
+       if (pid == 0) 
+       {
+#ifdef UCLINUX
+               if (self_exec(argv0, "nddd", 2, id, key, child_process) < 0) {
+                       tst_resm(TWARN, "self_exec failed");
+                       TEST(msgctl(tid, IPC_RMID, 0));
+                       if (TEST_RETURN < 0)
+                       {
+                               tst_resm(TFAIL, "\tMsgctl error in cleanup, "
+                                        "errno = %d\n", errno);
+                       }
+                       tst_exit();
+               }
+#else
+               exit( doreader(id, key % 255, child_process) );
+#endif
+       }
+       /* Parent does this */
+       mykid = pid;
+       procstat = 2;
+       dowriter(id, key % 255, child_process);
+       wait(0);
+       TEST(msgctl(id, IPC_RMID, 0));
+       if (TEST_RETURN < 0)
+       {
+                tst_resm(TFAIL, "msgctl errno %d", TEST_ERRNO);
+                       tst_exit();
+       }
+       exit(PASS);
+}
+
+int doreader(id, key, child)
+int id, child;
+long key;
+{
+       int i, size;
+
+       for (i = 0; i < nreps; i++) 
+       {
+               if ((size = msgrcv(id, &buffer, 100, 0, 0)) < 0) 
+               {
+                       tst_brkm(TBROK, cleanup, "Msgrcv error in child %d, read # = %d, errno = %d", (i + 1), child, errno);
+                       tst_exit();
+               }
+               if (buffer.data.len + 1 != size)  
+               {
+                       tst_resm(TFAIL, "Size mismatch in child %d, read # = %d", child, (i + 1));
+                       tst_resm(TFAIL, "for message size got  %d expected  %d %s",size ,buffer.data.len);
+                       tst_exit();
+               }
+               if ( verify(buffer.data.pbytes, key, size - 1, child) ) 
+               {
+                       tst_resm(TFAIL, "in read # = %d,key =  %x", (i + 1), child, key);
+                       tst_exit();
+               }
+               key++;
+       }
+       return (0);
+}
+
+int dowriter(id, key, child)
+int id,child;
+long key;
+{
+       int i, size;
+
+       for (i = 0; i < nreps; i++) 
+       {
+               do 
+               {
+                       size = (rand() % 99);
+               } while (size == 0);
+               fill_buffer(buffer.data.pbytes, key, size);
+               buffer.data.len = size;
+               buffer.type = 1;
+               TEST(msgsnd(id, &buffer, size + 1, 0));
+               if (TEST_RETURN < 0)
+               {
+                       tst_brkm(TBROK, cleanup, "Msgsnd error in child %d, key =   %x errno  = %d", child, key, TEST_ERRNO);
+               }
+               key++;
+       }
+       return (0);
+}      
+
+int fill_buffer(buf, val, size)
+register char *buf;
+char   val;
+register int size;
+{
+       register int i;
+
+       for(i = 0; i < size; i++)
+       {
+               buf[i] = val;
+       }
+
+       return (0);
+}
+
+
+/*
+ * verify()
+ *     Check a buffer for correct values.
+ */
+
+int verify(buf, val, size, child)
+       register char *buf;
+       char    val;
+       register int size;
+       int     child;
+{
+       while(size-- > 0)
+       {
+               if (*buf++ != val)
+               {
+                       tst_resm(TWARN, "Verify error in child %d, *buf = %x, val = %x, size = %d", child, *buf, val, size);
+                       return(FAIL);
+               }
+       }
+       return(PASS);
+}
+
+/*
+ *  * void
+ *  * sig_handler() - signal catching function for 'SIGUSR1' signal.
+ *  *
+ *  *   This is a null function and used only to catch the above signal
+ *  *   generated in parent process.
+ *  */
+void
+sig_handler()
+{
+}
+
+#define BUFSIZE 512
+
+/** Get the number of message queues already in use */
+static int get_used_msgqueues()
+{
+        FILE *f;
+        int used_queues;
+        char buff[BUFSIZE];
+
+        f = popen("ipcs -q", "r");
+        if (!f) {
+                tst_resm(TBROK,"Could not run 'ipcs' to calculate used message queues");
+                tst_exit();
+        }
+        /* FIXME: Start at -4 because ipcs prints four lines of header */
+        for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++)
+                ;
+        pclose(f);
+        if (used_queues < 0) {
+                tst_resm(TBROK,"Could not read output of 'ipcs' to calculate used message queues");
+                tst_exit();
+        }
+        return used_queues;
+}
+
+/** Get the max number of message queues allowed on system */
+static int get_max_msgqueues()
+{
+        FILE *f;
+        char buff[BUFSIZE];
+
+        /* Get the max number of message queues allowed on system */
+        f = fopen("/proc/sys/kernel/msgmni", "r");
+        if (!f){
+                tst_resm(TBROK,"Could not open /proc/sys/kernel/msgmni");
+                tst_exit();
+        }
+        if (!fgets(buff, BUFSIZE, f)) {
+                tst_resm(TBROK,"Could not read /proc/sys/kernel/msgmni");
+                tst_exit();
+        }
+        fclose(f);
+        return atoi(buff);
+}
+
+/***************************************************************
+ * setup() - performs all ONE TIME setup for this test.
+ *****************************************************************/
+void
+setup()
+{
+       tst_tmpdir();
+        /* You will want to enable some signal handling so you can capture
+        * unexpected signals like SIGSEGV.
+        */
+        tst_sig(FORK, DEF_HANDLER, cleanup);
+
+        /* Pause if that option was specified */
+        /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
+        * fork the test with the -c option.  You want to make sure you do this
+        * before you create your temporary directory.
+        */
+        TEST_PAUSE;
+
+        MSGMNI = get_max_msgqueues() - get_used_msgqueues();
+       if (MSGMNI <= 0){
+               tst_resm(TBROK,"Max number of message queues already used, cannot create more.");
+               cleanup(); 
+       }       
+}
+
+
+/***************************************************************
+ * cleanup() - performs all ONE TIME cleanup for this test at
+ *             completion or premature exit.
+ ****************************************************************/
+void
+cleanup()
+{
+       int status;
+        /*
+        *  Remove the message queue from the system
+        */
+#ifdef DEBUG
+        tst_resm(TINFO,"Removing the message queue");
+#endif
+        fflush (stdout);
+        (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL);
+        if ((status = msgctl(tid, IPC_STAT, (struct msqid_ds *)NULL)) != -1)
+        {
+                (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL);
+                tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
+                tst_exit();
+        }
+
+        fflush (stdout);
+        /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+        TEST_CLEANUP;
+       tst_rmdir();
+        /* exit with return code appropriate for results */
+        tst_exit();
+}
+
diff --git a/test/ipc/msgctl/msgctl09.c b/test/ipc/msgctl/msgctl09.c
new file mode 100644 (file)
index 0000000..ec36e8a
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+/* 11/11/2002   Port to LTP     dbarrera@us.ibm.com */
+
+
+/*
+ * NAME
+ *     msgctl09
+ *
+ * CALLS
+ *     msgget(2) msgctl(2) msgop(2)
+ *
+ * ALGORITHM
+ *     Get and manipulate a message queue.
+ *
+ * RESTRICTIONS
+ *
+ */
+
+#define _XOPEN_SOURCE 500
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "test.h"
+#include "usctest.h"
+
+#define MAXNREPS       1000
+#ifndef CONFIG_COLDFIRE
+#define MAXNPROCS       1000000  /* This value is set to an arbitrary high limit. */
+#else
+#define MAXNPROCS       100000   /* Coldfire can't deal with 1000000 */
+#endif
+#define MAXNKIDS       10
+#define FAIL           1
+#define PASS           0
+
+int dotest(key_t,int);
+int doreader(long,int,int);
+int dowriter(long,int,int);
+int fill_buffer(char*,char,int);
+int verify(char*,char,int,int);
+void setup();
+void cleanup();
+
+/*
+ * These globals must be defined in the test.
+ * */
+
+
+char *TCID="msgctl09";           /* Test program identifier.    */
+int TST_TOTAL=1;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+int exp_enos[]={0};     /* List must end with 0 */
+
+
+key_t  keyarray[MAXNPROCS];
+
+struct {
+       long    type;
+       struct {
+               char    len;
+               char    pbytes[99];
+               } data;
+       } buffer;
+
+int    pidarray[MAXNPROCS];
+int    rkidarray[MAXNKIDS];
+int    wkidarray[MAXNKIDS];
+int    tid;
+int    nprocs, nreps, nkids, MSGMNI;
+int    procstat;
+void   term(int);
+#ifdef UCLINUX
+static char *argv0;
+
+void do_child_1_uclinux();
+static key_t key_uclinux;
+static int i_uclinux;
+
+void do_child_2_uclinux();
+static int pid_uclinux;
+static int child_process_uclinux;
+
+void do_child_3_uclinux();
+static int rkid_uclinux;
+#endif
+void cleanup_msgqueue(int i, int tid);
+
+/*-----------------------------------------------------------------*/
+int main(argc, argv)
+int    argc;
+char   *argv[];
+{
+       register int i, j, ok, pid;
+       int count, status;
+
+#ifdef UCLINUX
+       char *msg;                      /* message returned from parse_opts */
+
+       argv0 = argv[0];
+
+       /* parse standard options */
+       if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL)
+       {
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+       
+       maybe_run_child(&do_child_1_uclinux, "ndd", 1, &key_uclinux, &i_uclinux);
+       maybe_run_child(&do_child_2_uclinux, "nddd", 2, &key_uclinux,
+                       &pid_uclinux, &child_process_uclinux);
+       maybe_run_child(&do_child_3_uclinux, "nddd", 3, &key_uclinux,
+                       &rkid_uclinux, &child_process_uclinux);
+#endif
+
+       setup();
+
+       if (argc == 1 )
+       {
+               /* Set default parameters */
+               nreps = MAXNREPS;
+               nprocs = MSGMNI;
+               nkids = MAXNKIDS;
+       }
+       else if (argc == 4 )
+       {
+               if ( atoi(argv[1]) > MAXNREPS )
+               {
+                        tst_resm(TCONF,"Requested number of iterations too large, setting to Max. of %d", MAXNREPS);
+                       nreps = MAXNREPS;
+               }
+               else
+               {
+                       nreps = atoi(argv[1]);
+               }
+               if (atoi(argv[2]) > MSGMNI )
+               {
+                        tst_resm(TCONF,"Requested number of processes too large, setting to Max. of %d", MSGMNI);
+                       nprocs = MSGMNI;
+               }
+               else
+               {
+                       nprocs = atoi(argv[2]);
+               }
+               if (atoi(argv[3]) > MAXNKIDS )
+               {
+                        tst_resm(TCONF,"Requested number of read/write pairs too large; setting to Max. of %d", MAXNKIDS);
+                       nkids = MAXNKIDS;
+               }
+               else
+               {
+                       nkids = atoi(argv[3]);
+               }
+       }
+       else
+       {
+                tst_resm(TCONF," Usage: %s [ number of iterations  number of processes number of read/write pairs ]", argv[0]);
+               tst_exit();
+       }
+
+       procstat = 0;
+       srand48((unsigned)getpid() + (unsigned)(getppid() << 16));
+       tid = -1;
+
+       /* Setup signal handleing routine */
+       if (sigset(SIGTERM, term) == SIG_ERR) 
+       {
+                tst_resm(TFAIL, "Sigset SIGTERM failed");
+                tst_exit();
+       }
+       /* Set up array of unique keys for use in allocating message
+        * queues
+        */
+       for (i = 0; i < nprocs; i++) 
+       {
+               ok = 1;
+               do 
+               {
+                       /* Get random key */
+                       keyarray[i] = (key_t)lrand48();
+                       /* Make sure key is unique and not private */
+                       if (keyarray[i] == IPC_PRIVATE) 
+                       {
+                               ok = 0;
+                               continue;
+                       }
+                       for (j = 0; j < i; j++) 
+                       {
+                               if (keyarray[j] == keyarray[i]) 
+                               {
+                                       ok = 0;
+                                       break;
+                               }
+                               ok = 1;
+                       }
+               } while (ok == 0);
+       }
+/*-----------------------------------------------------------------*/
+       /* Fork a number of processes (nprocs), each of which will
+        * create a message queue with several (nkids) reader/writer
+        * pairs which will read and write a number (iterations)
+        * of random length messages with specific values (keys).
+        */
+
+       for (i = 0; i <  nprocs; i++) 
+       {
+               fflush(stdout);
+               if ((pid = FORK_OR_VFORK()) < 0) 
+               {
+                       tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
+                       tst_exit();
+               }
+               /* Child does this */
+               if (pid == 0) 
+               {
+#ifdef UCLINUX
+                       if (self_exec(argv[0], "ndd", 1, keyarray[i], i) < 0)
+                       {
+                               tst_resm(TFAIL, "\tself_exec failed");
+                               tst_exit();
+                       }
+#else
+                       procstat = 1;
+                       exit( dotest(keyarray[i], i) );
+#endif
+               }
+               pidarray[i] = pid;
+       }
+
+       count = 0;
+       while(1)
+       {
+               if (( wait(&status)) > 0)
+               {
+                       if (status>>8 != PASS )
+                       {
+                                tst_resm(TFAIL, "Child exit status = %d", status>>8);
+                                tst_exit();
+                       }
+                       count++;
+               }       
+               else
+               {
+                       if (errno != EINTR)
+                       {       
+                               break;
+                       }
+#ifdef DEBUG
+                        tst_resm(TINFO,"Signal detected during wait");
+#endif
+               }
+       }
+       /* Make sure proper number of children exited */
+       if (count != nprocs)
+       {
+                tst_resm(TFAIL, "Wrong number of children exited, Saw %d, Expected %d", count, nprocs);
+                tst_exit();
+       }
+
+        tst_resm(TPASS,"msgctl09 ran successfully!");
+
+       cleanup();
+       
+        return (0);
+
+
+
+}
+/*--------------------------------------------------------------------*/
+
+#ifdef UCLINUX
+void
+do_child_1_uclinux()
+{
+       procstat = 1;
+       exit(dotest(key_uclinux, i_uclinux));
+}
+
+void
+do_child_2_uclinux()
+{
+       procstat = 2;
+       exit(doreader(key_uclinux, pid_uclinux, child_process_uclinux));
+}
+
+void
+do_child_3_uclinux()
+{
+       procstat = 2;
+       exit(dowriter(key_uclinux, rkid_uclinux, child_process_uclinux));
+}
+#endif
+
+void
+cleanup_msgqueue(int i, int tid)
+{
+       /*
+        * Decrease the value of i by 1 because it
+        * is getting incremented even if the fork
+        * is failing.
+        */
+
+       i--;
+       /*
+        * Kill all children & free message queue.
+        */
+       for (; i >= 0; i--) {
+               (void)kill(rkidarray[i], SIGKILL);
+               (void)kill(wkidarray[i], SIGKILL);
+       }
+
+       if (msgctl(tid, IPC_RMID, 0) < 0) {
+               tst_resm(TFAIL, "Msgctl error in cleanup, errno = %d", errno);
+               tst_exit();
+       }
+}
+
+int dotest(key, child_process)
+key_t  key;
+int    child_process;
+{
+       int id, pid;
+       int i, count, status, exit_status;
+
+       sighold(SIGTERM);
+                if ((id = msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR )) < 0)
+       {
+                tst_resm(TFAIL, "Msgget error in child %d, errno = %d", child_process, errno);
+                tst_exit();
+       }
+       tid = id;
+       sigrelse(SIGTERM);
+
+       exit_status = PASS;
+
+       for (i=0; i < nkids; i++)
+       {
+               fflush(stdout);
+               if ((pid = FORK_OR_VFORK()) < 0) 
+               {
+                       tst_resm(TWARN, "Fork failure in first child of child group %d", child_process);
+                       cleanup_msgqueue(i, tid);
+                       tst_exit();
+               }
+               /* First child does this */
+               if (pid == 0) 
+               {
+#ifdef UCLINUX
+                       if (self_exec(argv0, "nddd", 2, key, getpid(),
+                                     child_process) < 0) {
+                               tst_resm(TWARN, "self_exec failed");
+                               cleanup_msgqueue(i, tid);
+                               tst_exit();
+                       }
+#else
+                       procstat = 2;
+                       exit( doreader( key, getpid(), child_process) );
+#endif
+               }
+               rkidarray[i] = pid;
+               fflush(stdout);
+               if ((pid = FORK_OR_VFORK()) < 0) 
+               {
+                       tst_resm(TWARN, "Fork failure in first child of child group %d", child_process);
+                       /*
+                        * Kill the reader child process
+                        */
+                       (void)kill(rkidarray[i], SIGKILL);
+
+                       cleanup_msgqueue(i, tid);
+                               tst_exit();
+               }
+               /* Second child does this */
+               if (pid == 0) 
+               {
+#ifdef UCLINUX
+                       if (self_exec(argv0, "nddd", 3, key, rkidarray[i],
+                                     child_process) < 0) {
+                               tst_resm(TWARN, "\tFork failure in first child "
+                                        "of child group %d \n", child_process);
+                               /*
+                                * Kill the reader child process
+                                */
+                               (void)kill(rkidarray[i], SIGKILL);
+
+                               cleanup_msgqueue(i, tid);
+                               tst_exit();
+                       }
+#else
+                       procstat = 2;
+                       exit( dowriter( key, rkidarray[i], child_process) );
+#endif
+               }
+               wkidarray[i] = pid;
+       }
+       /* Parent does this */
+       count = 0;
+       while(1)
+       {
+               if (( wait(&status)) > 0)
+               {
+                       if (status>>8 != PASS )
+                       {
+                                tst_resm(TFAIL, "Child exit status = %d from child group %d", status>>8, child_process);
+                               for (i = 0; i < nkids; i++) 
+                               {
+                                       kill(rkidarray[i], SIGTERM);
+                                       kill(wkidarray[i], SIGTERM);
+                               }
+                                                                if (msgctl(tid, IPC_RMID, 0) < 0) {
+                                                                                tst_resm(TFAIL, "Msgctl error, errno = %d", errno);
+                                                                }
+                                tst_exit();
+                       }
+                       count++;
+               }       
+               else
+               {
+                       if (errno != EINTR)
+                       {       
+                               break;
+                       }
+               }
+       }
+       /* Make sure proper number of children exited */
+       if (count != (nkids * 2))
+       {
+               tst_resm(TFAIL, "Wrong number of children exited in child group %d, Saw %d Expected %d", child_process, count, (nkids * 2));
+                                if (msgctl(tid, IPC_RMID, 0) < 0) {
+                                                tst_resm(TFAIL, "Msgctl error, errno = %d", errno);
+                                }
+                tst_exit();
+       }
+       if (msgctl(id, IPC_RMID, 0) < 0)
+       {
+               tst_resm(TFAIL, "Msgctl failure in child group %d, errno %d", child_process, errno);
+                tst_exit();
+       }
+       exit(exit_status);
+}
+
+int doreader( key, type, child)
+int type, child;
+long key;
+{
+       int i, size;
+       int id;
+
+       if ((id = msgget(key, 0)) < 0)
+       {
+               tst_resm(TFAIL, "Msgget error in reader of child group %d, errno = %d", child, errno);
+                tst_exit();
+       }
+       if (id != tid)
+       {
+               tst_resm(TFAIL, "Message queue mismatch in reader of child group %d for message queue id %d", child, id);
+               tst_exit();
+       }
+       for (i = 0; i < nreps; i++) 
+       {
+               if ((size = msgrcv(id, &buffer, 100, type, 0)) < 0) 
+               {
+                       tst_resm(TFAIL, "Msgrcv error in child %d, read # = %d, errno = %d", (i + 1), child, errno);
+                       tst_exit();
+               }
+               if (buffer.type != type)
+               {
+                        tst_resm(TFAIL, "Size mismatch in child %d, read # = %d", child, (i + 1));
+                        tst_resm(TFAIL, "\tfor message size got  %d expected  %d %s",size ,buffer.data.len);
+                        tst_exit();
+               }
+               if (buffer.data.len + 1 != size)  
+               {
+                       tst_resm(TFAIL, "Size mismatch in child %d, read # = %d, size = %d, expected = %d", child, (i + 1), buffer.data.len, size);
+                       tst_exit();
+               }
+               if ( verify(buffer.data.pbytes, (key % 255), size - 1, child) ) 
+               {
+                        tst_resm(TFAIL, "in read # = %d,key =  %x", (i + 1), child, key);
+                        tst_exit();
+               }
+               key++;
+       }
+       exit(PASS);
+}
+
+int dowriter( key, type, child)
+int type,child;
+long key;
+{
+       int i, size;
+       int id;
+
+                if ((id = msgget(key, 0)) < 0)
+       {
+                tst_resm(TFAIL, "Msgget error in writer of child group %d, errno = %d", child, errno);
+                tst_exit();
+       }
+       if (id != tid)
+       {
+               tst_resm(TFAIL, "Message queue mismatch in writer of child group %d", child);
+               tst_resm(TFAIL, "\tfor message queue id %d expected  %d",id, tid);
+                tst_exit();
+       }
+
+       for (i = 0; i < nreps; i++) 
+       {
+               do 
+               {
+                       size = (lrand48() % 99);
+               } while (size == 0);
+               fill_buffer(buffer.data.pbytes, (key % 255), size);
+               buffer.data.len = size;
+               buffer.type = type;
+               if (msgsnd(id, &buffer, size + 1, 0) < 0)
+               {
+                        tst_resm(TFAIL, "Msgsnd error in child %d, key =   %x errno  = %d", child, key, errno);
+                       tst_exit();
+               }
+               key++;
+       }
+       exit(PASS);
+}      
+
+int fill_buffer(buf, val, size)
+register char *buf;
+char   val;
+register int size;
+{
+       register int i;
+
+       for(i = 0; i < size; i++)
+               buf[i] = val;
+       return(0);
+}
+
+
+/*
+ * verify()
+ *     Check a buffer for correct values.
+ */
+
+int verify(buf, val, size, child)
+       register char *buf;
+       char    val;
+       register int size;
+       int     child;
+{
+       while(size-- > 0)
+               if (*buf++ != val)
+               {
+                        tst_resm(TWARN, "Verify error in child %d, *buf = %x, val = %x, size = %d", child, *buf, val, size);
+                        return(FAIL);
+               }
+       return(PASS);
+}
+
+/* ARGSUSED */
+void
+term(int sig)
+{
+       int i;
+
+       if (procstat == 0) 
+       {
+#ifdef DEBUG
+               tst_resm(TINFO,"SIGTERM signal received, test killing kids");
+#endif
+               for (i = 0; i < nprocs; i++) 
+               {
+                       if ( pidarray[i] > 0){
+                               if ( kill(pidarray[i], SIGTERM) < 0)
+                               {
+                                       tst_resm(TBROK,"Kill failed to kill child %d", i);
+                                       exit(FAIL);
+                               }
+                       }
+               }
+               return;
+       }
+
+       if (procstat == 2) 
+       {
+               fflush(stdout);
+               exit(PASS);
+       }
+
+       if (tid == -1) 
+       {
+               exit(FAIL);
+       }
+       for (i = 0; i < nkids; i++) 
+       {
+               if (rkidarray[i] > 0)
+                       kill(rkidarray[i], SIGTERM);
+               if (wkidarray[i] > 0)
+                       kill(wkidarray[i], SIGTERM);
+       }
+}
+
+#define BUFSIZE 512
+
+/** Get the number of message queues already in use */
+static int get_used_msgqueues()
+{
+        FILE *f;
+        int used_queues;
+        char buff[BUFSIZE];
+
+        f = popen("ipcs -q", "r");
+        if (!f) {
+                tst_resm(TBROK,"Could not run 'ipcs' to calculate used message queues");
+                tst_exit();
+        }
+        /* FIXME: Start at -4 because ipcs prints four lines of header */
+        for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++)
+                ;
+        pclose(f);
+        if (used_queues < 0) {
+                tst_resm(TBROK,"Could not read output of 'ipcs' to calculate used message queues");
+                tst_exit();
+        }
+        return used_queues;
+}
+
+/** Get the max number of message queues allowed on system */
+static int get_max_msgqueues()
+{
+        FILE *f;
+        char buff[BUFSIZE];
+
+        /* Get the max number of message queues allowed on system */
+        f = fopen("/proc/sys/kernel/msgmni", "r");
+        if (!f){
+                tst_resm(TBROK,"Could not open /proc/sys/kernel/msgmni");
+                tst_exit();
+        }
+        if (!fgets(buff, BUFSIZE, f)) {
+                tst_resm(TBROK,"Could not read /proc/sys/kernel/msgmni");
+                tst_exit();
+        }
+        fclose(f);
+        return atoi(buff);
+}
+
+/***************************************************************
+ * setup() - performs all ONE TIME setup for this test.
+ *****************************************************************/
+void
+setup()
+{
+       tst_tmpdir();
+        /* You will want to enable some signal handling so you can capture
+         * unexpected signals like SIGSEGV.
+         */
+        tst_sig(FORK, DEF_HANDLER, cleanup);
+
+
+        /* Pause if that option was specified */
+        /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
+         * fork the test with the -c option.  You want to make sure you do this
+         * before you create your temporary directory.
+         */
+        TEST_PAUSE;
+
+        MSGMNI = get_max_msgqueues() - get_used_msgqueues();
+        if (MSGMNI <= 0){
+                tst_resm(TBROK,"Max number of message queues already used, cannot create more.");
+                cleanup();
+        }
+
+}
+
+
+/***************************************************************
+ * cleanup() - performs all ONE TIME cleanup for this test at
+ * completion or premature exit.
+ ****************************************************************/
+void
+cleanup()
+{
+       int status;
+        /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+        TEST_CLEANUP;
+
+        /*
+        * Remove the message queue from the system
+        */
+#ifdef DEBUG
+        tst_resm(TINFO,"Removing the message queue");
+#endif
+        fflush (stdout);
+        (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL);
+       if ((status = msgctl(tid, IPC_STAT, (struct msqid_ds *)NULL)) != -1)
+               {
+                               (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL);
+                                       tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
+                                               tst_exit();
+                                               }
+
+        fflush (stdout);
+       tst_rmdir();
+        /* exit with return code appropriate for results */
+        tst_exit();
+}
+
diff --git a/test/ipc/msgget/Makefile b/test/ipc/msgget/Makefile
new file mode 100644 (file)
index 0000000..9071354
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  Copyright (c) International Business Machines  Corp., 2001
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+CFLAGS += -I../lib -I../../../../../include -Wall
+LDLIBS += -L../../../../../lib -lltp -L.. -lipc
+
+SRCS    = $(wildcard *.c)
+TARGETS = $(patsubst %.c,%,$(SRCS))
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i ; done
+
+clean:
+       rm -f $(TARGETS)
diff --git a/test/ipc/msgget/msgget01.c b/test/ipc/msgget/msgget01.c
new file mode 100644 (file)
index 0000000..e8ca995
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgget01.c
+ *
+ * DESCRIPTION
+ *     msgget01 - create a message queue, write a message to it and
+ *                read it back.
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     create a message queue
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing by writting a message to the queue,
+ *       reading it back and comparing the two.
+ *             if the messages are the same,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgget01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcmsg.h"
+
+#include <string.h>
+
+char *TCID = "msgget01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int msg_q_1 = -1;              /* to hold the message queue ID */
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       void check_functionality(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Use TEST macro to make the call to create the message queue
+                */
+       
+               TEST(msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RD | MSG_WR));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d : %s",
+                                TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+               } else {
+                       msg_q_1 = TEST_RETURN;
+                       if (STD_FUNCTIONAL_TEST) {
+                               /*
+                                * write a message to the queue.
+                                * read back the message.
+                                * PASS the test if they are the same.
+                                */
+                               check_functionality();
+                       } else {
+                               tst_resm(TPASS, "message queue was created");
+                       }
+               }
+
+               /*
+                * remove the message queue that was created and mark the ID
+                * as invalid.
+                */
+               if (msg_q_1 != -1) {
+                       rm_queue(msg_q_1);
+                       msg_q_1 = -1;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * check_functionality() - check the functionality of the tested system call.
+ */
+void
+check_functionality()
+{
+       int i=0;
+       MSGBUF snd_buf, rcv_buf;
+
+       /* EAGLE: Houston, Tranquility Base here. The Eagle has landed! */
+       char *queue_msg =
+                "Qston, check_functionality here.  The message has queued!";
+
+       /*
+        * copy our message into the buffer and then set the type.
+        */
+       do {
+               snd_buf.mtext[i++] = *queue_msg;
+       } while(*queue_msg++ != (char)NULL);
+
+       snd_buf.mtype = MSGTYPE;
+
+       /* send the message */
+       if(msgsnd(msg_q_1, &snd_buf, MSGSIZE, 0) == -1) {
+               tst_brkm(TBROK, cleanup, "Could not send a message in the "
+                        "check_functionality() routine.");
+       }
+
+       /* receive the message */
+       if(msgrcv(msg_q_1, &rcv_buf, MSGSIZE, MSGTYPE, IPC_NOWAIT) == -1) {
+               tst_brkm(TBROK, cleanup, "Could not read a messages in the "
+                        "check_functionality() routine.");
+       }
+
+       if(strcmp(snd_buf.mtext, rcv_buf.mtext) == 0) {
+               tst_resm(TPASS, "message received = message sent");
+       } else {
+               tst_resm(TFAIL, "message received != message sent");
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgget/msgget02.c b/test/ipc/msgget/msgget02.c
new file mode 100644 (file)
index 0000000..a7040f6
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgget02.c
+ *
+ * DESCRIPTION
+ *     msgget02 - test for EEXIST and ENOENT errors
+ *
+ * ALGORITHM
+ *     create a message queue
+ *     loop if that option was specified
+ *     try to recreate the same queue - test #1
+ *     try to access a queue that doesn't exist - tests #2 & #3
+ *     check the errno value
+ *       issue a PASS message if we get EEXIST or ENOENT depening on test
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *       break any remaining tests
+ *       call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgget02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgget02";
+int TST_TOTAL = 3;
+extern int Tst_count;
+
+struct test_case_t {
+        int error;      
+        int msg_incr;
+        int flags;
+} TC[] = {
+        {EEXIST, 0, IPC_CREAT | IPC_EXCL},
+        {ENOENT, 1, IPC_PRIVATE},
+        {ENOENT, 1, IPC_EXCL}
+};
+
+int exp_enos[] = {EEXIST, ENOENT, 0};
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       TEST(msgget(msgkey + TC[i].msg_incr, TC[i].flags));
+
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "msgget() call succeeded "
+                                        "on expected fail");
+                               continue;
+                       }
+
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case ENOENT:
+                               /*FALLTHROUGH*/
+                       case EEXIST:
+                               if (TEST_ERRNO == TC[i].error) {
+                                       tst_resm(TPASS, "expected failure - "
+                                                "errno = %d : %s", TEST_ERRNO,
+                                                strerror(TEST_ERRNO));
+                                       break;
+                               }
+                               /*FALLTHROUGH*/
+                       default:
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* now we have a key, so let's create a message queue */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue" );
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created. */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgget/msgget03.c b/test/ipc/msgget/msgget03.c
new file mode 100644 (file)
index 0000000..d7bc315
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgget03.c
+ *
+ * DESCRIPTION
+ *     msgget03 - test for an ENOSPC error by using up all available
+ *                message queues.
+ *
+ * ALGORITHM
+ *     Get all the message queues that can be allocated
+ *     loop if that option was specified
+ *     Try to get one more message queue
+ *     check the errno value
+ *       issue a PASS message if we get ENOSPC
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *       break any remaining tests
+ *       call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgget03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgget03";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int maxmsgs = 0;
+
+int exp_enos[] = {ENOSPC, 0};  /* 0 terminated list of expected errnos */
+
+int *msg_q_arr = NULL;         /* hold the id's that we create */
+int num_queue = 0;             /* count the queues created */
+
+static int get_max_msgqueues();
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Try to create another message queue.  This should
+                * give us an ENOSPC error.
+                */
+
+               TEST(msgget(msgkey + num_queue + 1, IPC_CREAT|IPC_EXCL));
+       
+               if (TEST_RETURN != -1) {
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case ENOSPC:
+                       tst_resm(TPASS, "expected failure - errno = %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "call failed with an "
+                                "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;          
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/** Get the max number of message queues allowed on system */
+int get_max_msgqueues()
+{
+        FILE *f;
+        char buff[512];
+
+        /* Get the max number of message queues allowed on system */
+        f = fopen("/proc/sys/kernel/msgmni", "r");
+        if (!f){
+                tst_brkm(TBROK, cleanup, "Could not open /proc/sys/kernel/msgmni");
+        }
+        if (!fgets(buff, 512, f)) {
+                tst_brkm(TBROK, cleanup, "Could not read /proc/sys/kernel/msgmni");
+        }
+        fclose(f);
+        return atoi(buff);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       int msg_q;
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       maxmsgs = get_max_msgqueues();
+
+       msg_q_arr = (int *)calloc(maxmsgs, sizeof (int));
+       if (msg_q_arr == NULL) {
+               tst_brkm(TBROK, cleanup, "Couldn't allocate memory "
+                               "for msg_q_arr: calloc() failed");
+       }
+
+       /*
+        * Use a while loop to create the maximum number of queues.
+        * When we get an error, check for ENOSPC.
+        */
+       while((msg_q = msgget(msgkey + num_queue, IPC_CREAT|IPC_EXCL)) != -1) {
+               msg_q_arr[num_queue] = msg_q;
+               if (num_queue == maxmsgs) {
+                       tst_resm(TINFO, "The maximum number of message"
+                                " queues (%d) has been reached", maxmsgs);
+                       break;
+               }
+               num_queue++;
+       }
+
+       /*
+        * if we have something other than ENOSPC, then something else is
+        * wrong.
+        */
+
+       if (errno != ENOSPC) {
+               tst_brkm(TBROK, cleanup, "Didn't get ENOSPC in test setup"
+                        " - errno = %d : %s", errno, strerror(errno));
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       int i;
+
+       /*
+        * remove the message queues if they were created
+        */
+
+       if (msg_q_arr != NULL) {
+               for (i=0; i<num_queue; i++) {
+                       rm_queue(msg_q_arr[i]);
+               }
+               (void) free(msg_q_arr);
+       }
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgget/msgget04.c b/test/ipc/msgget/msgget04.c
new file mode 100644 (file)
index 0000000..b3d6b4a
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgget04.c
+ *
+ * DESCRIPTION
+ *     msgget04 - test for an EACCES error by creating a message queue
+ *                with no read or write permission and then attempting
+ *                to access it with various permissions.
+ *
+ * ALGORITHM
+ *     Create a message queue with no read or write permission
+ *     loop if that option was specified
+ *     Try to access the message queue with various permissions
+ *     check the errno value
+ *       issue a PASS message if we get EACCES
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *       break any remaining tests
+ *       call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgget04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+#include <pwd.h>
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+char *TCID = "msgget04";
+int TST_TOTAL = 3;
+extern int Tst_count;
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+
+int exp_enos[] = {EACCES, 0};  /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* to hold the message queue id */
+
+int test_flags[] = {MSG_RD, MSG_WR, MSG_RD | MSG_WR};
+
+int main(int ac, char **av)
+{
+       int lc;                 /* loop counter */
+       char *msg;              /* message returned from parse_opts */
+       int i;                  /* a counter */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+
+               for (i=0; i<TST_TOTAL; i++) {
+                       /*
+                        * Try to access the message queue with specified
+                        * permissions.
+                        */
+
+                       TEST(msgget(msgkey, test_flags[i]));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded "
+                                        "when EACCES error expected");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case EACCES:
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       default:
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+        /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+        ltpuser = getpwnam(nobody_uid);
+        if (setuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("setuid");
+        }
+
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /*
+        * Create the message queue without specifying permissions.
+        */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT|IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Could not create message queue"
+                        " - errno = %d : %s", errno, strerror(errno));
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgrcv/Makefile b/test/ipc/msgrcv/Makefile
new file mode 100644 (file)
index 0000000..9071354
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  Copyright (c) International Business Machines  Corp., 2001
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+CFLAGS += -I../lib -I../../../../../include -Wall
+LDLIBS += -L../../../../../lib -lltp -L.. -lipc
+
+SRCS    = $(wildcard *.c)
+TARGETS = $(patsubst %.c,%,$(SRCS))
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i ; done
+
+clean:
+       rm -f $(TARGETS)
diff --git a/test/ipc/msgrcv/msgrcv01.c b/test/ipc/msgrcv/msgrcv01.c
new file mode 100644 (file)
index 0000000..66c92d0
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgrcv01.c
+ *
+ * DESCRIPTION
+ *     msgrcv01 - test that msgrcv() receives the expected message
+ *
+ * ALGORITHM
+ *     create a message queue
+ *     initialize a message buffer with a known message and type
+ *     loop if that option was specified
+ *     fork a child to receive the message
+ *     parent enqueues the message then exits
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             build a new message and compare it to the one received
+ *             if they are the same,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgrcv01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include <string.h>
+#include <sys/wait.h>
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+void do_child(void);
+
+char *TCID = "msgrcv01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int msg_q_1;
+MSGBUF snd_buf, rcv_buf, cmp_buf;
+
+pid_t c_pid;
+
+int main(int ac, char **av)
+{
+    int lc;                    /* loop counter */
+    char *msg;                 /* message returned from parse_opts */
+    void check_functionality(void);
+    int status, e_code;
+
+    /* parse standard options */
+    if ((msg =
+        parse_opts(ac, av, (option_t *) NULL, NULL)) != (char *) NULL) {
+       tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+    }
+
+#ifdef UCLINUX
+    maybe_run_child(&do_child, "d", &msg_q_1);
+#endif
+
+    setup();                   /* global setup */
+
+    /* The following loop checks looping state if -i option given */
+
+    for (lc = 0; TEST_LOOPING(lc); lc++) {
+       /* reset Tst_count in case we are looping */
+       Tst_count = 0;
+
+       /*
+        * fork a child to read from the queue while the parent
+        * enqueues the message to be read.
+        */
+       if ((c_pid = FORK_OR_VFORK()) == -1) {
+           tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (c_pid == 0) {       /* child */
+#ifdef UCLINUX
+           if (self_exec(av[0], "d", msg_q_1) < 0) {
+               tst_brkm(TBROK, cleanup, "could not self_exec");
+           }
+#else
+           do_child();
+#endif
+       } else {                /* parent */
+           /* put the message on the queue */
+           if (msgsnd(msg_q_1, &snd_buf, MSGSIZE, 0) == -1) {
+               tst_brkm(TBROK, cleanup, "Couldn't enqueue" " message");
+           }
+           /* wait for the child to finish */
+           wait(&status);
+           /* make sure the child returned a good exit status */
+           e_code = status >> 8;
+           if (e_code != 0) {
+               tst_resm(TFAIL, "Failures reported above");
+           }
+
+       }
+    }
+
+    cleanup();
+
+    /** NOT REACHED **/
+    return(0);
+
+}
+
+/*
+ * do_child()
+ */
+void
+do_child()
+{
+    int retval = 0;
+
+    TEST(msgrcv(msg_q_1, &rcv_buf, MSGSIZE, 1, 0));
+    
+    if (TEST_RETURN == -1) {
+       retval = 1;
+       tst_resm(TFAIL, "%s call failed - errno = %d : %s",
+                TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+    } else {
+       if (STD_FUNCTIONAL_TEST) {
+           /*
+            * Build a new message and compare it
+            * with the one received.
+            */
+           init_buf(&cmp_buf, MSGTYPE, MSGSIZE);
+           
+           if (strcmp(rcv_buf.mtext, cmp_buf.mtext) == 0) {
+               tst_resm(TPASS,
+                        "message received = " "message sent");
+           } else {
+               retval = 1;
+               tst_resm(TFAIL,
+                        "message received != " "message sent");
+           }
+       } else {
+           tst_resm(TPASS, "call succeeded");
+       }
+    }
+    exit(retval);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void setup(void)
+{
+    /* capture signals */
+    tst_sig(FORK, DEF_HANDLER, cleanup);
+
+    /* Pause if that option was specified */
+    TEST_PAUSE;
+
+    /*
+     * Create a temporary directory and cd into it.
+     * This helps to ensure that a unique msgkey is created.
+     * See ../lib/libipc.c for more information.
+     */
+    tst_tmpdir();
+
+    msgkey = getipckey();
+
+    /* create a message queue with read/write permission */
+    if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+       tst_brkm(TBROK, cleanup, "Can't create message queue");
+    }
+
+    /* initialize the message buffer */
+    init_buf(&snd_buf, MSGTYPE, MSGSIZE);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void cleanup(void)
+{
+    /* if it exists, remove the message queue that was created */
+    rm_queue(msg_q_1);
+
+    /* Remove the temporary directory */
+    tst_rmdir();
+
+    /*
+     * print timing stats if that option was specified.
+     * print errno log if that option was specified.
+     */
+    TEST_CLEANUP;
+
+    /* exit with return code appropriate for results */
+    tst_exit();
+}
diff --git a/test/ipc/msgrcv/msgrcv02.c b/test/ipc/msgrcv/msgrcv02.c
new file mode 100644 (file)
index 0000000..c5cbdc3
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgrcv02.c
+ *
+ * DESCRIPTION
+ *     msgrcv02 - test for EACCES and EFAULT errors
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     initialize a message buffer with a known message and type
+ *     enqueue the message
+ *     create another message queue without read/write permissions
+ *     loop if that option was specified
+ *     call msgrcv() using two different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EACCES or EFAULT
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgrcv02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include <pwd.h>
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgrcv02";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+int exp_enos[] = {EACCES, EFAULT, 0};
+
+int msg_q_1 = -1;              /* The message queue ID created in setup */
+int msg_q_2 = -1;              /* Another message queue ID created in setup */
+MSGBUF snd_buf, rcv_buf;
+
+struct test_case_t {
+       int *queue_id;
+       MSGBUF *mbuf;
+       int error;
+} TC[] = {
+       /* EACCES - the queue has no read access */
+       {&msg_q_2, &rcv_buf, EACCES},
+
+       /* EFAULT - the message buffer address is invalid */
+       {&msg_q_1, (MSGBUF *)-1, EFAULT}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /*
+                        * Use the TEST macro to make the call
+                        */
+       
+                       TEST(msgrcv(*(TC[i].queue_id), TC[i].mbuf, MSGSIZE,
+                            1, IPC_NOWAIT));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }                       
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+        /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+        ltpuser = getpwnam(nobody_uid);
+        if (setuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("setuid");
+        }
+
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue #1");
+       }
+
+       /* initialize a message buffer */
+       init_buf(&snd_buf, MSGTYPE, MSGSIZE);
+
+       /* put it on msq_q_1 */
+       if (msgsnd(msg_q_1, &snd_buf, MSGSIZE, IPC_NOWAIT) == -1) {
+               tst_brkm(TBROK, cleanup, "Couldn't put message on queue");
+       }
+
+       /* create a message queue without read/write permission */
+       if ((msg_q_2 = msgget(msgkey + 1, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue #2");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue #1 */
+       rm_queue(msg_q_1);
+
+       /* if it exists, remove the message queue #2 */
+       rm_queue(msg_q_2);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgrcv/msgrcv03.c b/test/ipc/msgrcv/msgrcv03.c
new file mode 100644 (file)
index 0000000..b069b27
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgrcv03.c
+ *
+ * DESCRIPTION
+ *     msgrcv03 - test for EINVAL error
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     loop if that option was specified
+ *     call msgrcv() using two different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EINVAL
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgrcv03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgrcv03";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+int exp_enos[] = {EINVAL, 0};  /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+int bad_q = -1;                        /* a value to use as a bad queue ID */
+MSGBUF rcv_buf;
+
+struct test_case_t {
+       int *queue_id;
+       int msize;
+       int error;
+} TC[] = {
+       /* EINVAL - the queue ID is invalid */
+       {&bad_q, MSGSIZE, EINVAL},
+
+       /* EINVAL - the message size is less than 0 */
+       {&msg_q_1, -1, EINVAL}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /*
+                        * Use the TEST macro to make the call
+                        */
+       
+                       TEST(msgrcv(*(TC[i].queue_id), &rcv_buf, TC[i].msize,
+                            1, 0));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }                       
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgrcv/msgrcv04.c b/test/ipc/msgrcv/msgrcv04.c
new file mode 100644 (file)
index 0000000..ce71e5f
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgrcv04.c
+ *
+ * DESCRIPTION
+ *     msgrcv04 - test for E2BIG and ENOMSG errors
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     initialize a message buffer with a known message and type
+ *     enqueue the message
+ *     loop if that option was specified
+ *     call msgrcv() using two different invalid cases 
+ *     check the errno value
+ *       issue a PASS message if we get E2BIG or ENOMSG
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgrcv04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgrcv04";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+int exp_enos[] = {E2BIG, ENOMSG, 0};
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+
+#define SMSIZE 512
+
+MSGBUF snd_buf, rcv_buf;
+
+struct test_case_t {
+       int size;
+       int type;
+       int flags;
+       int error;
+} TC[] = {
+       /*
+        * E2BIG - The receive buffer is too small for the message and
+        *         MSG_NOERROR isn't asserted in the flags.
+        */
+       {SMSIZE, 1, 0, E2BIG},
+
+       /*
+        * ENOMSG - There is no message with the requested type and
+        *          IPC_NOWAIT is asserted in the flags.
+        */
+       {MSGSIZE, 2, IPC_NOWAIT, ENOMSG}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /*
+                        * Use the TEST macro to make the call
+                        */
+       
+                       TEST(msgrcv(msg_q_1, &rcv_buf, TC[i].size, TC[i].type,
+                            TC[i].flags));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }                       
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize a buffer */
+       init_buf(&snd_buf, MSGTYPE, MSGSIZE);
+
+       /* put the message on the queue */
+       if (msgsnd(msg_q_1, &snd_buf, MSGSIZE, 0) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't enqueue message");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgrcv/msgrcv05.c b/test/ipc/msgrcv/msgrcv05.c
new file mode 100644 (file)
index 0000000..ad15397
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgrcv05.c
+ *
+ * DESCRIPTION
+ *     msgrcv05 - test for EINTR error
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     loop if that option was specified
+ *     fork a child who attempts to read a non-existent message with msgrcv()
+ *     parent sends a SIGHUP to the child, then waits for the child to complete
+ *     check the errno value
+ *       issue a PASS message if we get EINTR
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     child exits, parent calls cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgrcv05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void do_child(void);
+void cleanup(void);
+void setup(void);
+void sighandler(int);
+#ifdef UCLINUX
+void do_child_uclinux(void);
+#endif
+
+char *TCID = "msgrcv05";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EINTR, 0};   /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+
+MSGBUF rcv_buf;
+pid_t c_pid;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+#ifdef UCLINUX
+       maybe_run_child(&do_child_uclinux, "d", &msg_q_1);
+#endif
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * fork a child that will attempt to read a non-existent
+                * message from the queue
+                */
+               if ((c_pid = FORK_OR_VFORK()) == -1) {
+                       tst_brkm(TBROK, cleanup, "could not fork");
+               }
+
+               if (c_pid == 0) {               /* child */
+                       /*
+                        * Attempt to read a message without IPC_NOWAIT.
+                        * With no message to read, the child sleeps.
+                        */
+#ifdef UCLINUX
+                       if (self_exec(av[0], "d", msg_q_1) < 0) {
+                               tst_brkm(TBROK, cleanup, "could not self_exec");
+                       }
+#else
+                       do_child();
+#endif
+               } else {                        /* parent */
+                       usleep(250000);
+
+                       /* send a signal that must be caught to the child */
+                       if (kill(c_pid, SIGHUP) == -1) {
+                               tst_brkm(TBROK, cleanup, "kill failed");
+                       }
+
+                       waitpid(c_pid, NULL, 0);
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * do_child()
+ */
+void
+do_child()
+{
+       TEST(msgrcv(msg_q_1, &rcv_buf, MSGSIZE, 1, 0));
+
+       if (TEST_RETURN != -1) {
+               tst_resm(TFAIL, "call succeeded when error expected");
+               exit(-1);
+       }
+       
+       TEST_ERROR_LOG(TEST_ERRNO);
+       
+       switch(TEST_ERRNO) {
+       case EINTR:
+               tst_resm(TPASS, "expected failure - errno = %d : %s", TEST_ERRNO,
+                        strerror(TEST_ERRNO));
+               break;
+       default:
+               tst_resm(TFAIL, "call failed with an unexpected error - %d : %s",
+                        TEST_ERRNO, strerror(TEST_ERRNO));
+               break;
+       }                       
+
+       exit(0);
+}
+
+#ifdef UCLINUX
+/*
+ * do_child_uclinux() - capture signals again, then run do_child()
+ */
+void
+do_child_uclinux()
+{
+       tst_sig(FORK, sighandler, cleanup);
+
+       do_child();
+}
+#endif
+
+/*
+ * sighandler() - handle signals
+ */
+void
+sighandler(int sig)
+{
+       /* we don't need to do anything here */
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(FORK, sighandler, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
diff --git a/test/ipc/msgrcv/msgrcv06.c b/test/ipc/msgrcv/msgrcv06.c
new file mode 100644 (file)
index 0000000..e5a1f62
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgrcv06.c
+ *
+ * DESCRIPTION
+ *     msgrcv06 - test for EIDRM error
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     create a message queue with read/write permissions
+ *     fork a child who sleeps on an attempted read with msgrcv()
+ *     parent removes the queue then waits for child to complete
+ *     check the errno value
+ *       issue a PASS message if we get EIDRM
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *      child removes message queue if required
+ *     parent callc cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgrcv06 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void do_child(void);
+void cleanup(void);
+void setup(void);
+void sighandler(int);
+#ifdef UCLINUX
+void do_child_uclinux(void);
+#endif
+
+char *TCID = "msgrcv06";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EIDRM, 0};   /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+
+MSGBUF rcv_buf;
+pid_t c_pid;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+#ifdef UCLINUX
+       maybe_run_child(&do_child_uclinux, "d", &msg_q_1);
+#endif
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * set up the queue here so that multiple test iterations
+                * will work.
+                */
+               msgkey = getipckey();
+
+               /* create a message queue with read/write permission */
+               if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW))
+                    == -1) {
+                       tst_brkm(TBROK, cleanup, "Can't create message queue");
+               }
+
+               /*
+                * fork a child that will attempt to read a non-existent
+                * message from the queue
+                */
+               if ((c_pid = FORK_OR_VFORK()) == -1) {
+                       tst_brkm(TBROK, cleanup, "could not fork");
+               }
+
+               if (c_pid == 0) {               /* child */
+                       /*
+                        * Attempt to read a message without IPC_NOWAIT.
+                        * With no message to read, the child sleeps.
+                        */
+#ifdef UCLINUX
+                       if (self_exec(av[0], "d", msg_q_1) < 0) {
+                               tst_brkm(TBROK, cleanup, "could not self_exec");
+                       }
+#else
+                       do_child();
+#endif
+               } else {                        /* parent */
+                       usleep(250000);
+
+                       /* remove the queue */
+                       rm_queue(msg_q_1);
+
+                       waitpid(c_pid, NULL, 0);
+               }
+       }
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * do_child()
+ */
+void
+do_child()
+{
+       TEST(msgrcv(msg_q_1, &rcv_buf, MSGSIZE, 1, 0));
+
+       if (TEST_RETURN != -1) {
+               tst_resm(TFAIL, "call succeeded when error expected");
+               exit(-1);
+       }
+       
+       TEST_ERROR_LOG(TEST_ERRNO);
+       
+       switch(TEST_ERRNO) {
+       case EIDRM:
+               tst_resm(TPASS, "expected failure - errno = %d : %s", TEST_ERRNO,
+                        strerror(TEST_ERRNO));
+               
+               /* mark the queue as invalid as it was removed */
+               msg_q_1 = -1;
+               break;
+       default:
+               tst_resm(TFAIL, "call failed with an unexpected error - %d : %s",
+                        TEST_ERRNO, strerror(TEST_ERRNO));
+               break;
+       }                       
+       
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       exit(0);
+}
+
+#ifdef UCLINUX
+/*
+ * do_child_uclinux() - capture signals again, then run do_child()
+ */
+void
+do_child_uclinux()
+{
+       tst_sig(FORK, sighandler, cleanup);
+
+       do_child();
+}
+#endif
+
+/*
+ * sighandler() - handle signals
+ */
+void
+sighandler(int sig)
+{
+       /* we don't need to do anything here */
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(FORK, sighandler, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
diff --git a/test/ipc/msgsnd/Makefile b/test/ipc/msgsnd/Makefile
new file mode 100644 (file)
index 0000000..9071354
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  Copyright (c) International Business Machines  Corp., 2001
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+CFLAGS += -I../lib -I../../../../../include -Wall
+LDLIBS += -L../../../../../lib -lltp -L.. -lipc
+
+SRCS    = $(wildcard *.c)
+TARGETS = $(patsubst %.c,%,$(SRCS))
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i ; done
+
+clean:
+       rm -f $(TARGETS)
diff --git a/test/ipc/msgsnd/msgsnd01.c b/test/ipc/msgsnd/msgsnd01.c
new file mode 100644 (file)
index 0000000..368ea37
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgsnd01.c
+ *
+ * DESCRIPTION
+ *     msgsnd01 - test that msgsnd() enqueues a message correctly
+ *
+ * ALGORITHM
+ *     create a message queue
+ *     initialize a message buffer with a known message and type
+ *     loop if that option was specified
+ *     enqueue the message
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             stat the message queue
+ *             check for # of bytes = MSGSIZE and # of messages = 1
+ *             if correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgsnd01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     None
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgsnd01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int msg_q_1;
+MSGBUF msg_buf, rd_buf;
+
+struct msqid_ds qs_buf;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Use TEST macro to make the call
+                */
+       
+               TEST(msgsnd(msg_q_1, &msg_buf, MSGSIZE, 0));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d : %s",
+                                TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+                       continue;
+               }
+
+               if (STD_FUNCTIONAL_TEST) {
+
+                       /* get the queue status */
+                       if (msgctl(msg_q_1, IPC_STAT, &qs_buf) == -1) {
+                               tst_brkm(TBROK, cleanup, "Could not "
+                                        "get queue status");
+                       }
+
+                       if (qs_buf.msg_cbytes != MSGSIZE) {
+                               tst_resm(TFAIL, "queue bytes != MSGSIZE");
+                       }
+
+                       if (qs_buf.msg_qnum != 1) {
+                               tst_resm(TFAIL, "queue message != 1");
+                       }
+
+                       tst_resm(TPASS, "queue bytes = MSGSIZE and "
+                                "queue messages = 1"); 
+               } else {
+                       tst_resm(TPASS, "call succeeded");
+               }
+
+               /*
+                * remove the message by reading from the queue
+                */
+               if (msgrcv(msg_q_1, &rd_buf, MSGSIZE, 1, 0) == -1) {
+                       tst_brkm(TBROK, cleanup, "Could not read from queue");
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permissions */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize the message buffer */
+       init_buf(&msg_buf, MSGTYPE, MSGSIZE);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue if it exists */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgsnd/msgsnd02.c b/test/ipc/msgsnd/msgsnd02.c
new file mode 100644 (file)
index 0000000..24af375
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgsnd02.c
+ *
+ * DESCRIPTION
+ *     msgsnd02 - test for EACCES and EFAULT errors
+ *
+ * ALGORITHM
+ *     create a message queue without write permission
+ *     create a trivial message buffer
+ *     loop if that option was specified
+ *     call msgsnd() using two different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EACCES or EFAULT
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgsnd02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+#include <pwd.h>
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgsnd02";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+int exp_enos[] = {EACCES, EFAULT, 0};
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+MSGBUF msg_buf;                        /* a buffer for the message to queue */
+int bad_q = -1;                        /* a value to use as a bad queue ID */
+
+struct test_case_t {
+       int *queue_id;
+       MSGBUF *buffer;
+       int error;
+} TC[] = {
+       /* EACCES - there is no write permission for the queue */
+       {&msg_q_1, &msg_buf, EACCES},
+
+       /* EFAULT - the message buffer address is invalid */
+       {&msg_q_1, NULL, EFAULT},
+};
+       
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * loop through the test cases
+                */
+       
+               for (i=0; i<TST_TOTAL; i++) {
+                       TEST(msgsnd(*(TC[i].queue_id), TC[i].buffer, 1, 0));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - "
+                                        "errno = %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+        /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+        ltpuser = getpwnam(nobody_uid);
+        if (setuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("setuid");
+        }
+
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue without write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RD)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize the message buffer with something trivial */
+       msg_buf.mtype = MSGTYPE;
+       msg_buf.mtext[0] = 'a';
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgsnd/msgsnd03.c b/test/ipc/msgsnd/msgsnd03.c
new file mode 100644 (file)
index 0000000..821492c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgsnd03.c
+ *
+ * DESCRIPTION
+ *     msgsnd03 - test for EINVAL error
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     create a trivial message buffer
+ *     loop if that option was specified
+ *     call msgsnd() using four different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EINVAL
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgsnd03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgsnd03";
+int TST_TOTAL = 4;
+extern int Tst_count;
+
+
+int exp_enos[] = {EINVAL, 0};  /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+MSGBUF msg_buf;                        /* a buffer for the message to queue */
+int bad_q = -1;                        /* a value to use as a bad queue ID */
+
+struct test_case_t {
+       int *queue_id;
+       MSGBUF *buffer;
+       long mtype;
+       int msg_size;
+       int error;
+} TC[] = {
+       /* EINVAL - the queue ID is invalid */
+       {&bad_q, &msg_buf, 1, 1, EINVAL},
+
+       /* EINVAL - the message type is not positive (0) */
+       {&msg_q_1, &msg_buf, 0, 1, EINVAL},
+
+       /* EINVAL - the message type is not positive (>0) */
+       {&msg_q_1, &msg_buf, -1, 1, EINVAL},
+
+       /* EINVAL - the message size is less than zero */
+       {&msg_q_1, &msg_buf, 1, -1, EINVAL}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * loop through the test cases
+                */
+       
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /* set the message type */
+                       msg_buf.mtype = TC[i].mtype;
+
+                       /* make the call with the TEST macro */
+                       TEST(msgsnd(*(TC[i].queue_id), TC[i].buffer,
+                            TC[i].msg_size, 0));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - "
+                                        "errno = %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize the message buffer with something trivial */
+       msg_buf.mtype = MSGTYPE;
+       msg_buf.mtext[0] = 'a';
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgsnd/msgsnd04.c b/test/ipc/msgsnd/msgsnd04.c
new file mode 100644 (file)
index 0000000..5c2d3b9
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgsnd04.c
+ *
+ * DESCRIPTION
+ *     msgsnd04 - test for EAGAIN error
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     initialize a message buffer with a known message and type
+ *     enqueue the message in a loop until the queue is full
+ *     loop if that option was specified
+ *     attempt to enqueue another message - msgsnd()
+ *     check the errno value
+ *       issue a PASS message if we get EAGAIN
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgsnd04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+
+char *TCID = "msgsnd04";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EAGAIN, 0};  /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+MSGBUF msg_buf;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Attempt to write another message to the full queue.
+                */
+       
+               TEST(msgsnd(msg_q_1, &msg_buf, MSGSIZE, IPC_NOWAIT));
+       
+               if (TEST_RETURN != -1) {
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case EAGAIN:
+                       tst_resm(TPASS, "expected failure - errno = %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "call failed with an "
+                                "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize the message buffer */
+       init_buf(&msg_buf, MSGTYPE, MSGSIZE);
+
+       /* write messages to the queue until it is full */
+       while (msgsnd(msg_q_1, &msg_buf, MSGSIZE, IPC_NOWAIT) != -1) {
+               msg_buf.mtype += 1;
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgsnd/msgsnd05.c b/test/ipc/msgsnd/msgsnd05.c
new file mode 100644 (file)
index 0000000..eb0bb71
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgsnd05.c
+ *
+ * DESCRIPTION
+ *     msgsnd05 - test for EINTR error
+ *
+ * ALGORITHM
+ *     create a message queue with read/write permissions
+ *     initialize a message buffer with a known message and type
+ *     enqueue the message in a loop until the queue is full
+ *     loop if that option was specified
+ *     fork a child process
+ *     child attempts to enqueue a message to the full queue and sleeps
+ *     parent sends a SIGHUP to the child then waits for the child to complete
+ *     child get a return from msgsnd()
+ *     check the errno value
+ *       issue a PASS message if we get EINTR
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     child exits, parent calls cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgsnd05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void do_child(void);
+void cleanup(void);
+void setup(void);
+void sighandler(int);
+#ifdef UCLINUX
+void do_child_uclinux(void);
+#endif
+
+char *TCID = "msgsnd05";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EINTR, 0};   /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+MSGBUF msg_buf;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       pid_t c_pid;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+#ifdef UCLINUX
+       maybe_run_child(&do_child_uclinux, "d", &msg_q_1);
+#endif
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * fork a child that will attempt to write a message
+                * to the queue without IPC_NOWAIT
+                */
+               if ((c_pid = FORK_OR_VFORK()) == -1) {
+                       tst_brkm(TBROK, cleanup, "could not fork");
+               }
+
+               if (c_pid == 0) {               /* child */
+                       /*
+                        * Attempt to write another message to the full queue.
+                        * Without the IPC_NOWAIT flag, the child sleeps
+                        */
+#ifdef UCLINUX
+                       if (self_exec(av[0], "d", msg_q_1) < 0) {
+                               tst_brkm(TBROK, cleanup, "could not self_exec");
+                       }
+#else
+                       do_child();
+#endif
+               } else {                /* parent */
+                       usleep(250000);
+
+                       /* send a signal that must be caught to the child */
+                       if (kill(c_pid, SIGHUP) == -1) {
+                               tst_brkm(TBROK, cleanup, "kill failed");
+                       }
+
+                       waitpid(c_pid, NULL, 0);
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * do_child()
+ */
+void
+do_child()
+{
+       TEST(msgsnd(msg_q_1, &msg_buf, MSGSIZE, 0));
+
+       if (TEST_RETURN != -1) {
+               tst_resm(TFAIL, "call succeeded when error expected");
+               exit(-1);
+       }
+       
+       TEST_ERROR_LOG(TEST_ERRNO);
+       
+       switch(TEST_ERRNO) {
+       case EINTR:
+               tst_resm(TPASS, "expected failure - errno = %d : %s",
+                        TEST_ERRNO, strerror(TEST_ERRNO));
+               break;
+       default:
+               tst_resm(TFAIL, "call failed with an unexpected error - %d : %s",
+                        TEST_ERRNO, strerror(TEST_ERRNO));
+               break;
+       }
+
+       exit(0);
+}
+
+#ifdef UCLINUX
+/*
+ * do_child_uclinux() - capture signals, initialize buffer, then run do_child()
+ */
+void
+do_child_uclinux()
+{
+       /* initialize the message buffer */
+       init_buf(&msg_buf, MSGTYPE, MSGSIZE);
+
+       tst_sig(FORK, sighandler, cleanup);
+
+       do_child();
+}
+#endif
+
+/*
+ * sighandler() - handle signals
+ */
+void
+sighandler(int sig)
+{
+       /* we don't need to do anything here */
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals in our own handler */
+       tst_sig(FORK, sighandler, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize the message buffer */
+       init_buf(&msg_buf, MSGTYPE, MSGSIZE);
+
+       /* write messages to the queue until it is full */
+       while (msgsnd(msg_q_1, &msg_buf, MSGSIZE, IPC_NOWAIT) != -1) {
+               msg_buf.mtype += 1;
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the message queue that was created */
+       rm_queue(msg_q_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/msgsnd/msgsnd06.c b/test/ipc/msgsnd/msgsnd06.c
new file mode 100644 (file)
index 0000000..b7ed964
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     msgsnd06.c
+ *
+ * DESCRIPTION
+ *     msgsnd06 - test for EIDRM error
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     create a message queue with read/write permissions
+ *     initialize a message buffer with a known message and type
+ *     enqueue messages in a loop until the queue is full
+ *     fork a child process
+ *     child attempts to enqueue a message to the full queue and sleeps        
+ *     parent removes the queue and then exits
+ *     child get a return from msgsnd()
+ *     check the errno value
+ *       issue a PASS message if we get EIDRM
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  msgsnd06 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include <sys/wait.h> 
+#include "test.h"
+#include "usctest.h"
+
+#include "ipcmsg.h"
+
+void cleanup(void);
+void setup(void);
+void do_child(void);
+
+char *TCID = "msgsnd06";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = { EIDRM, 0 }; /* 0 terminated list of expected errnos */
+
+int msg_q_1 = -1;              /* The message queue id created in setup */
+MSGBUF msg_buf;
+
+int main(int ac, char **av)
+{
+    int lc;                    /* loop counter */
+    char *msg;                 /* message returned from parse_opts */
+    pid_t c_pid;
+    int status, e_code;
+
+    /* parse standard options */
+    if ((msg =
+        parse_opts(ac, av, (option_t *) NULL, NULL)) != (char *) NULL) {
+       tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+    }
+
+#ifdef UCLINUX
+    maybe_run_child(&do_child, "d", &msg_q_1);
+#endif
+
+    setup();                   /* global setup */
+
+    /* The following loop checks looping state if -i option given */
+
+    for (lc = 0; TEST_LOOPING(lc); lc++) {
+       /* reset Tst_count in case we are looping */
+       Tst_count = 0;
+
+       msgkey = getipckey();
+
+       /* create a message queue with read/write permission */
+       if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW))
+           == -1) {
+           tst_brkm(TBROK, cleanup, "Can't create message queue");
+       }
+
+       /* initialize the message buffer */
+       init_buf(&msg_buf, MSGTYPE, MSGSIZE);
+
+       /* write messages to the queue until it is full */
+       while (msgsnd(msg_q_1, &msg_buf, MSGSIZE, IPC_NOWAIT) != -1) {
+           msg_buf.mtype += 1;
+       }
+
+       /*
+        * fork a child that will attempt to write a message
+        * to the queue without IPC_NOWAIT
+        */
+       if ((c_pid = FORK_OR_VFORK()) == -1) {
+           tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (c_pid == 0) {       /* child */
+#ifdef UCLINUX
+           if (self_exec(av[0], "d", msg_q_1) < 0) {
+               tst_brkm(TBROK, cleanup, "could not self_exec");
+           }
+#else
+           do_child();
+#endif
+       } else {                /* parent */
+           sleep(1);
+           /* remove the queue */
+           rm_queue(msg_q_1);
+
+           /* wait for the child to finish */
+           wait(&status);
+           /* make sure the child returned a good exit status */
+           e_code = status >> 8;
+           if (e_code != 0) {
+               tst_resm(TFAIL, "Failures reported above");
+           }
+       }
+    }
+
+    cleanup();
+
+ /*NOTREACHED*/
+ return(0);
+}
+
+/*
+ * do_child()
+ */
+void
+do_child()
+{
+    int retval = 0;
+
+#ifdef UCLINUX
+    /* initialize the message buffer */
+    init_buf(&msg_buf, MSGTYPE, MSGSIZE);
+#endif
+
+    /*
+     * Attempt to write another message to the full queue.
+     * Without the IPC_NOWAIT flag, the child sleeps
+     */
+    TEST(msgsnd(msg_q_1, &msg_buf, MSGSIZE, 0));
+
+    if (TEST_RETURN != -1) {
+       retval = 1;
+       tst_resm(TFAIL, "call succeeded when error expected");
+       exit(retval);
+    }
+
+    TEST_ERROR_LOG(TEST_ERRNO);
+
+    switch (TEST_ERRNO) {
+    case EIDRM:
+       tst_resm(TPASS, "expected failure - errno = %d : %s",
+                TEST_ERRNO, strerror(TEST_ERRNO));
+
+       /* mark the queue as invalid as it was removed */
+       msg_q_1 = -1;
+       break;
+    default:
+       retval = 1;
+       tst_resm(TFAIL, "call failed with an unexpected error - %d : %s",
+                TEST_ERRNO, strerror(TEST_ERRNO));
+       break;
+    }
+    exit(retval);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void setup(void)
+{
+    /* capture signals */
+    tst_sig(FORK, DEF_HANDLER, cleanup);
+
+    /* Set up the expected error numbers for -e option */
+    TEST_EXP_ENOS(exp_enos);
+
+    /* Pause if that option was specified */
+    TEST_PAUSE;
+
+    /*
+     * Create a temporary directory and cd into it.
+     * This helps to ensure that a unique msgkey is created.
+     * See ../lib/libipc.c for more information.
+     */
+    tst_tmpdir();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void cleanup(void)
+{
+
+    /* Remove the temporary directory */
+    tst_rmdir();
+
+    /*
+     * print timing stats if that option was specified.
+     * print errno log if that option was specified.
+     */
+    TEST_CLEANUP;
+
+    /* exit with return code appropriate for results */
+    tst_exit();
+}
diff --git a/test/ipc/semctl/Makefile b/test/ipc/semctl/Makefile
new file mode 100644 (file)
index 0000000..6fdccf7
--- /dev/null
@@ -0,0 +1,44 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = semctl01 semctl02 semctl03 semctl04 semctl05 semctl06 semctl07
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+semctl01: semctl01.c
+semctl02: semctl02.c
+semctl03: semctl03.c
+semctl04: semctl04.c
+semctl05: semctl05.c
+semctl06: semctl06.c
+semctl07: semctl07.c
+
diff --git a/test/ipc/semctl/semctl01.c b/test/ipc/semctl/semctl01.c
new file mode 100644 (file)
index 0000000..111ea45
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semctl01.c
+ *
+ * DESCRIPTION
+ *     semctl01 - test the 10 possible semctl() commands
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     loop if that option was specified
+ *       loop through the test cases
+ *         do any setup required for the test case
+ *         make the semctl() call using the TEST() macro
+ *         check the return code
+ *           if failure, issue a FAIL message.
+ *         otherwise,
+ *           if doing functionality testing
+ *             call the appropriate test function
+ *             if correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semctl01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+
+char *TCID = "semctl01";
+int TST_TOTAL = 10;
+extern int Tst_count;
+
+int sem_id_1 = -1;     /* a semaphore set with read and alter permissions */
+
+/*
+ * These are the various setup and check functions for the 10 different
+ * commands that are available for the semctl() call.
+ */
+void func_stat(int);
+void set_setup(int), func_set(int);
+void func_gall(int);
+void cnt_setup(int), func_cnt(int);
+void pid_setup(int), func_pid(int);
+void gval_setup(int), func_gval(int);
+void sall_setup(int), func_sall(int);
+void func_sval(int);
+void func_rmid(int);
+void child_cnt(void);
+void child_pid(void);
+
+struct semid_ds buf;
+unsigned short array[PSEMS];
+struct sembuf sops;
+
+#define INCVAL 2       /* a semaphore increment value */
+#define NEWMODE        066
+#define NCHILD 5
+#define SEM2   2       /* semaphore to use for GETPID and GETVAL */
+#define SEM4   4       /* semaphore to use for GETNCNT and GETZCNT */
+#define ONE    1
+
+#define SEMUN_CAST (union semun)
+
+int pid_arr[NCHILD];
+
+#ifdef UCLINUX
+static char *argv0;
+#endif
+
+struct test_case_t {
+       int semnum;             /* the primitive semaphore to use */
+       int cmd;                /* the command to test */
+       void (*func_test)(int); /* the test function */
+       union semun arg;
+       void (*func_setup)(int);        /* the setup function if necessary */
+} TC[10];
+
+void setup_test_cases(void)
+{
+       int i;
+
+       i = -1;
+
+       /* {0, IPC_STAT, func_stat, &buf, NULL}, */
+       i++;
+       TC[i].semnum = 0;
+       TC[i].cmd = IPC_STAT;
+       TC[i].func_test = func_stat;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = NULL;
+
+       /* {0, IPC_SET, func_set, &buf, set_setup}, */
+       i++;
+       TC[i].semnum = 0;
+       TC[i].cmd = IPC_SET;
+       TC[i].func_test = func_set;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = set_setup;
+
+       /* {0, GETALL, func_gall, array, NULL}, */
+       i++;
+       TC[i].semnum = 0;
+       TC[i].cmd = GETALL;
+       TC[i].func_test = func_gall;
+       TC[i].arg.array = array;
+       TC[i].func_setup = NULL;
+
+       /* {SEM4, GETNCNT, func_cnt, SEMUN_CAST &buf, cnt_setup}, */
+       i++;
+       TC[i].semnum = SEM4;
+       TC[i].cmd = GETNCNT;
+       TC[i].func_test = func_cnt;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = cnt_setup;
+
+       /* {SEM2, GETPID, func_pid, SEMUN_CAST &buf, pid_setup}, */
+       i++;
+       TC[i].semnum = SEM2;
+       TC[i].cmd = GETPID;
+       TC[i].func_test = func_pid;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = pid_setup;
+
+       /* {SEM2, GETVAL, func_gval, SEMUN_CAST &buf, NULL}, */
+       i++;
+       TC[i].semnum = SEM2;
+       TC[i].cmd = GETVAL;
+       TC[i].func_test = func_gval;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = NULL;
+
+       /* {SEM4, GETZCNT, func_cnt, SEMUN_CAST &buf, cnt_setup}, */
+       i++;
+       TC[i].semnum = SEM4;
+       TC[i].cmd = GETZCNT;
+       TC[i].func_test = func_cnt;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = cnt_setup;
+
+       /* {0, SETALL, func_sall, SEMUN_CAST array, sall_setup}, */
+       i++;
+       TC[i].semnum = 0;
+       TC[i].cmd = SETALL;
+       TC[i].func_test = func_sall;
+       TC[i].arg.array = array;
+       TC[i].func_setup = sall_setup;
+
+       /* {SEM4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL}, */
+       i++;
+       TC[i].semnum = SEM4;
+       TC[i].cmd = SETVAL;
+       TC[i].func_test = func_sval;
+       TC[i].arg.val = INCVAL;
+       TC[i].func_setup = NULL;
+
+       /* {0, IPC_RMID, func_rmid, SEMUN_CAST &buf, NULL} */
+       i++;
+       TC[i].semnum = 0;
+       TC[i].cmd = IPC_RMID;
+       TC[i].func_test = func_rmid;
+       TC[i].arg.buf = &buf;
+       TC[i].func_setup = NULL;
+}
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i, j;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+#ifdef UCLINUX
+       argv0 = av[0];
+       maybe_run_child(&child_pid, "nd", 1, &sem_id_1);
+       maybe_run_child(&child_cnt, "ndd", 2, &sem_id_1, &sops.sem_op);
+#endif
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /*
+                        * Set up any conditions if needed
+                        */
+
+                       if (TC[i].func_setup != NULL) {
+                               /* call the setup function */
+                               switch (TC[i].cmd) {
+                               case GETNCNT:
+                                       (*TC[i].func_setup)(-ONE);
+                                       break;
+                               case GETZCNT:
+                                       (*TC[i].func_setup)(0);
+                                       break;
+                               default:
+                                       (*TC[i].func_setup)(ONE);
+                                       break;
+                               }
+                       }
+
+                       /*
+                        * Use TEST macro to make the call
+                        */
+
+                       TEST(semctl(sem_id_1, TC[i].semnum, TC[i].cmd,
+                                   TC[i].arg));
+       
+                       if (TEST_RETURN == -1) {
+                               tst_resm(TFAIL, "%s call failed - errno = %d "
+                                        ": %s", TCID, TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               if (STD_FUNCTIONAL_TEST) {
+                                       /*
+                                        * call the appropriate test function
+                                        * and pass the return value where it
+                                        * is needed to perform certain tests.
+                                        */
+                                       switch (TC[i].cmd) {
+                                       case GETNCNT:
+                                               /*FALLTHROUGH*/
+                                       case GETZCNT:
+                                               /*FALLTHROUGH*/
+                                       case GETPID:
+                                               /*FALLTHROUGH*/
+                                       case GETVAL:
+                                               (*TC[i].func_test)(TEST_RETURN);
+                                               break;
+                                       default:
+                                               (*TC[i].func_test)(0);
+                                               break;
+                                       }
+                               } else {
+                                       tst_resm(TPASS, "call succeeded");
+                               }
+                       }
+
+                       /*
+                        * If testing GETNCNT or GETZCNT, clean up the children.
+                        */
+                       switch (TC[i].cmd) {
+                       case GETNCNT:
+                               /*FALLTHROUGH*/
+                       case GETZCNT:
+                               for (j=0; j<NCHILD; j++) {
+                                       if (kill(pid_arr[j], SIGKILL) == -1) {
+                                               tst_brkm(TBROK, cleanup,
+                                                       "child kill failed");
+                                       }
+                               }
+                               break;
+                       }
+               }
+               /*
+                * recreate the semaphore resource if looping
+                */
+               if (TEST_LOOPING(lc)) {
+                       if ((sem_id_1 = semget(semkey, PSEMS,
+                           IPC_CREAT | IPC_EXCL | SEM_RA)) == -1 ) {
+                               tst_brkm(TBROK, cleanup, "couldn't recreate "
+                                        "semaphore");
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+        return(0);
+
+}
+
+/*
+ * func_stat() - check the functionality of the IPC_STAT command with semctl()
+ */
+void
+func_stat(int n)
+{
+       /* check the number of semaphores and the ipc_perm.mode value */
+       if (buf.sem_nsems == PSEMS && buf.sem_perm.mode == (SEM_RA)) {
+               tst_resm(TPASS, "buf.sem_nsems and buf.sem_perm.mode"
+                               " are correct");
+       } else {
+               tst_resm(TFAIL, "semaphore STAT info is incorrect");
+       }
+}
+
+/*
+ * set_setup() - set up for the IPC_SET command with semctl()
+ */
+void
+set_setup(int n)
+{
+       /* set up a new mode for the semaphore set */
+       buf.sem_perm.mode = SEM_RA | NEWMODE;
+}
+
+/*
+ * func_set() - check the functionality of the IPC_SET command with semctl()
+ */
+void
+func_set(int n)
+{
+       /* first stat the semaphore to get the new data */
+    union semun arg;
+
+    arg.buf = &buf;
+       if (semctl(sem_id_1, 0, IPC_STAT, arg) == -1) {
+               tst_resm(TBROK, "stat failed in func_set()");
+               return;
+       }
+
+       /* check that the new mode is what we set */
+       if (buf.sem_perm.mode == (SEM_RA | NEWMODE)) {
+               tst_resm(TPASS, "buf.sem_perm.mode is correct");
+       } else {
+               tst_resm(TFAIL, "semaphore mode info is incorrect");
+       }
+}
+
+/*
+ * func_gall() - check the functionality of the GETALL command with semctl()
+ */
+void
+func_gall(int n)
+{
+       int i;
+
+       /* the initial value of the primitive semaphores should be zero */
+       for (i=0 ; i<PSEMS; i++) {
+               if (array[i] != 0) {
+                       tst_resm(TFAIL, "semaphore %d has unexpected value", i);
+                       return;
+               }
+       }
+       tst_resm(TPASS, "semaphores have expected values");
+}
+
+/*
+ * cnt_setup() - set up for the GETNCNT and GETZCNT commands with semctl()
+ */
+void
+cnt_setup(int opval)
+{
+       int pid, i;
+
+       sops.sem_num = SEM4;
+       sops.sem_flg = 0;
+
+       /*
+        * if seting up for GETZCNT, the semaphore value needs to be positive
+        */
+       if (opval == 0) {
+               /* initialize the semaphore value to ONE */
+               sops.sem_op = ONE;
+               if (semop(sem_id_1, &sops, 1) == -1) {
+                       tst_brkm(TBROK, cleanup, "semop #1 failed - cnt_setup");
+               }
+       }
+
+       sops.sem_op = opval;    /* set the correct operation */
+
+       for (i=0; i<NCHILD; i++) {
+               /* fork five children to wait */
+               if ((pid = FORK_OR_VFORK()) == -1) {
+                       tst_brkm(TBROK, cleanup, "fork failed in cnt_setup");
+               }
+       
+               if (pid == 0) {         /* child */
+#ifdef UCLINUX
+                       if (self_exec(argv0, "ndd", 2, sem_id_1,
+                                     sops.sem_op) < 0) {
+                               tst_brkm(TBROK, cleanup, "self_exec failed "
+                                        "in cnt_setup");
+                       }
+#else
+                       child_cnt();
+#endif
+               } else {                /* parent */
+                       /* take a quick nap so that commands execute orderly */
+                       usleep(50000);
+
+                       /* save the pid so we can kill it later */
+                       pid_arr[i] = pid;
+               }
+       }
+}
+
+void
+child_cnt(void)
+{
+       sops.sem_num = SEM4;
+       sops.sem_flg = 0;
+
+       /*
+        * Do a semop that will cause the child to sleep.
+        * The child process will be killed in the func_ncnt
+        * routine which should cause an error to be return
+        * by the semop() call.
+        */
+       if (semop(sem_id_1, &sops, 1) != -1) {
+               tst_resm(TBROK, "semop succeeded - cnt_setup");
+       }
+       exit(0);
+}
+
+/*
+ * func_cnt() - check the functionality of the GETNCNT and GETZCNT commands
+ *             with semctl()
+ */
+void
+func_cnt(int rval)
+{
+
+       if (rval == NCHILD) {
+               tst_resm(TPASS, "number of sleeping processes is correct");
+       } else {
+               tst_resm(TFAIL, "number of sleeping processes is not correct");
+       }
+}
+
+/*
+ * pid_setup() - set up for the GETPID command with semctl()
+ */
+void
+pid_setup(int n)
+{
+       int pid;
+
+       /*
+        * Fork a child to do a semop that will pass. 
+        */
+       if ((pid = FORK_OR_VFORK()) == -1) {
+               tst_brkm(TBROK, cleanup, "fork failed in pid_setup()");
+       }
+
+       if (pid == 0) {         /* child */
+#ifdef UCLINUX
+               if (self_exec(argv0, "nd", 1, sem_id_1) < 0) {
+                       tst_brkm(TBROK, cleanup, "self_exec failed "
+                                "in pid_setup()");
+               }
+#else
+               child_pid();
+#endif
+       } else {                /* parent */
+               /* take a quick nap so that commands execute orderly */
+               usleep(50000);
+
+               pid_arr[SEM2] = pid;
+       }
+}
+
+void
+child_pid(void)
+{
+       sops.sem_num = SEM2;    /* semaphore to change */
+       sops.sem_op = ONE;      /* operation is to increment semaphore */
+       sops.sem_flg = 0;
+
+       /*
+        * Do a semop that will increment the semaphore.
+        */
+       if (semop(sem_id_1, &sops, 1) == -1) {
+               tst_resm(TBROK, "semop failed - pid_setup");
+       }
+       exit(0);
+}
+
+/*
+ * func_pid() - check the functionality of the GETPID command with semctl()
+ */
+void
+func_pid(int rval)
+{
+       /* compare the rval (pid) to the saved pid from the setup */
+       if (rval == pid_arr[SEM2]) {
+               tst_resm(TPASS, "last pid value is correct");
+       } else {
+               tst_resm(TFAIL, "last pid value is not correct");
+       }
+}
+
+/*
+ * func_gval() - check the functionality of the GETVAL command with semctl()
+ */
+void
+func_gval(int rval)
+{
+       /*
+        * This is a simple test.  The semaphore value should be equal
+        * to ONE as it was set in the last test (GETPID).
+        */
+       if (rval == 1) {
+               tst_resm(TPASS, "semaphore value is correct");
+       } else {
+               tst_resm(TFAIL, "semaphore value is not correct");
+       }
+
+}
+
+/*
+ * all_setup() - set up for the SETALL command with semctl()
+ */
+void
+sall_setup(int n)
+{
+       int i;
+
+       for (i=0; i<PSEMS; i++) {
+               /* initialize the array values to 3 */
+               array[i] = 3;
+       }
+}
+
+/*
+ * func_sall() - check the functionality of the SETALL command with semctl()
+ */
+void
+func_sall(int n)
+{
+       int i;
+       unsigned short rarray[PSEMS];
+    union semun arg;
+
+       /*
+        * do a GETALL and compare the values to those set above
+        */
+
+    arg.array = rarray;
+       if (semctl(sem_id_1, 0, GETALL, arg) == -1) {
+               tst_brkm(TBROK, cleanup, "semctl failed in func_sall");
+       }
+
+       for (i=0; i<PSEMS; i++) {
+               if (array[i] != rarray[i]) {
+                       tst_resm(TFAIL, "semaphore values are not correct");
+                       return;
+               }
+       }
+
+       tst_resm(TPASS, "semaphore values are correct");
+}
+
+/*
+ * func_sval() - check the functionality of the SETVAL command with semctl()
+ */
+void
+func_sval(int n)
+{
+       int semv;
+       union semun arr;
+
+       /*
+        * do a GETVAL and compare it to the value set above
+        */
+
+       if ((semv = semctl(sem_id_1, SEM4, GETVAL, arr)) == -1) {
+               tst_brkm(TBROK, cleanup, "semctl failed in func_sval");
+       }
+
+       if (semv != INCVAL) {
+               tst_resm(TFAIL, "semaphore value is not what was set");
+       } else {
+               tst_resm(TPASS, "semaphore value is correct");
+       }
+}
+
+/*
+ * func_rmid() - check the functionality of the IPC_RMID command with semctl()
+ */
+void
+func_rmid(int n)
+{
+
+       /*
+        * do a semop() - we should get EINVAL
+        */
+       if (semop(sem_id_1, &sops, 1) != -1) {
+               tst_resm(TFAIL, "semop succeeded on expected fail");
+       }
+
+       if (errno != EINVAL) {
+               tst_resm(TFAIL, "returned errno - %d - is not expected", errno);
+       } else {
+               tst_resm(TPASS, "semaphore appears to be removed");
+       }
+
+       sem_id_1 = -1;
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       setup_test_cases();
+
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1 ) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
diff --git a/test/ipc/semctl/semctl02.c b/test/ipc/semctl/semctl02.c
new file mode 100644 (file)
index 0000000..857c242
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semctl02.c
+ *
+ * DESCRIPTION
+ *     semctl02 - test for EACCES error
+ *
+ * ALGORITHM
+ *     create a semaphore set without read/alter permissions
+ *     loop if that option was specified
+ *     call semctl() attempting an IPC_STAT command
+ *     check the errno value
+ *       issue a PASS message if we get EACCES
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semctl02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+#include <pwd.h>
+
+char *TCID = "semctl02";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EACCES, 0};  /* 0 terminated list of expected errnos */
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+int sem_id_1 = -1;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       struct semid_ds sem_ds;
+       union semun un_arg;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+       
+               un_arg.buf = &sem_ds; 
+
+               /*
+                * use the TEST macro to make the call
+                */
+
+               TEST(semctl(sem_id_1, 0, IPC_STAT, un_arg));
+       
+               if (TEST_RETURN != -1) {
+printf("result: %d\n", TEST_RETURN);
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case EACCES:
+                       tst_resm(TPASS, "expected failure - errno = %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+        return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+        /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+        ltpuser = getpwnam(nobody_uid);
+        if (seteuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("setuid");
+        }
+
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set without read or alter permissions */
+       if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       if (seteuid(0) == -1) {
+               tst_resm(TINFO, "setuid back to root error!\n");
+       }
+
+       /* if it exists, remove the semaphore resouce */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semctl/semctl03.c b/test/ipc/semctl/semctl03.c
new file mode 100644 (file)
index 0000000..0e52254
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semctl03.c
+ *
+ * DESCRIPTION
+ *     semctl03 - test for EINVAL and EFAULT errors
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     loop if that option was specified
+ *     call semctl() using four different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EINVAL or EFAULT
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semctl03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+
+#ifdef _XLC_COMPILER
+#define SEMUN_CAST
+#else
+#define SEMUN_CAST (union semun)
+#endif
+
+char *TCID = "semctl03";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+#ifdef _XLC_COMPILER
+#define SEMUN_CAST 
+#else
+#define SEMUN_CAST (union semun)
+#endif
+
+int exp_enos[] = {EINVAL, EFAULT, 0};
+
+int sem_id_1 = -1;
+int bad_id = -1;
+
+struct semid_ds sem_ds;
+
+struct test_case_t {
+       int *sem_id;
+       int ipc_cmd;
+       union semun arg;
+       int error;
+} TC[4];
+
+void setup_test_case(void)
+{
+       /* EINVAL - the IPC command is not valid */
+       /* {&sem_id_1, -1, SEMUN_CAST &sem_ds, EINVAL}, */
+    TC[0].sem_id = &sem_id_1;
+    TC[0].ipc_cmd = -1;
+    TC[0].arg.buf = &sem_ds;
+    TC[0].error = EINVAL;
+
+       /* EINVAL - the semaphore ID is not valid */
+       /* {&bad_id, IPC_STAT, SEMUN_CAST &sem_ds, EINVAL}, */
+    TC[1].sem_id = &bad_id;
+    TC[1].ipc_cmd = IPC_STAT;
+    TC[1].arg.buf = &sem_ds;
+    TC[1].error = EINVAL;
+
+#if 0
+/* EFAULT address can't be detected well in Minix. */
+       /* EFAULT - the union arg is invalid when expecting "ushort *array" */
+       /* {&sem_id_1, GETALL, SEMUN_CAST -1, EFAULT}, */
+    TC[2].sem_id = &sem_id_1;
+    TC[2].ipc_cmd = GETALL;
+    TC[2].arg.val = -1;
+    TC[2].error = EFAULT;
+
+       /* EFAULT - the union arg is invalid when expecting */
+       /* "struct semid_ds *buf */
+       /* {&sem_id_1, IPC_SET, SEMUN_CAST -1, EFAULT} */
+    TC[3].sem_id = &sem_id_1;
+    TC[3].ipc_cmd = IPC_SET;
+    TC[3].arg.val = -1;
+    TC[3].error = EFAULT;
+#endif
+}
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       TEST(semctl(*(TC[i].sem_id), 0, TC[i].ipc_cmd,
+                            TC[i].arg));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = %d"
+                                        " : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+    setup_test_case();
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resouce */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semctl/semctl04.c b/test/ipc/semctl/semctl04.c
new file mode 100644 (file)
index 0000000..871f6c4
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semctl04.c
+ *
+ * DESCRIPTION
+ *     semctl04 - test for EPERM error
+ *
+ * ALGORITHM
+ *     create a semaphore set without read or alter permissions
+ *     get the user id for "nobody"
+ *     fork a child process
+ *     if child
+ *       set the ID of the child process to that of "nobody"
+ *       loop if that option was specified
+ *         call semctl() with two different invalid cases      
+ *         check the errno value
+ *           issue a PASS message if we get EPERM
+ *         otherwise, the tests fails
+ *           issue a FAIL message
+ *       call cleanup
+ *     if parent
+ *       wait for child to exit
+ *       remove the semaphore set
+ *
+ * USAGE:  <for command-line>
+ *  semctl04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     test must be run as root
+ */
+
+#include "ipcsem.h"
+
+#include <pwd.h>
+#include <sys/wait.h>
+
+char *TCID = "semctl04";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+int exp_enos[] = {EPERM, 0};   /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+uid_t ltp_uid;
+char *ltp_user = "nobody";
+
+int TC[] = {IPC_SET, IPC_RMID};
+
+int main(int ac, char **av)
+{
+       char *msg;                      /* message returned from parse_opts */
+       pid_t pid;
+       void do_child(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       if ((pid = FORK_OR_VFORK()) == -1) {
+               tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (pid == 0) {         /* child */
+               /* set the user ID of the child to the non root user */
+               if (setuid(ltp_uid) == -1) {
+                       tst_resm(TBROK, "setuid() failed");
+                       exit(1);
+               }
+
+               do_child();
+
+       } else {
+               if (waitpid(pid, NULL, 0) == -1) {
+                       tst_resm(TBROK, "waitpid() failed");
+                       tst_resm(TINFO, "waitpid() error = %d : %s", errno,
+                                strerror(errno));
+               }
+
+               /* if it exists, remove the semaphore resouce */
+               rm_sema(sem_id_1);
+
+               /* Remove the temporary directory */
+               tst_rmdir();
+       }
+       cleanup();
+
+       return(0);
+}
+
+/*
+ * do_child() - make the TEST call as the child process
+ */
+void
+do_child(void)
+{
+       int lc;                         /* loop counter */
+       int i;
+       union semun arg;
+       struct semid_ds perm; 
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       if (TC[i] == IPC_SET)  {
+                               arg.buf =  &perm;
+                               memset(&perm, 0, sizeof perm); 
+                               perm.sem_perm.uid = getuid() + 1;
+                               perm.sem_perm.gid = getgid() + 1; 
+                               perm.sem_perm.mode = 0666; 
+                       }
+
+
+                       TEST(semctl(sem_id_1, 0, TC[i], arg));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case EPERM:
+                               tst_resm(TPASS, "expected failure - errno ="
+                                        " %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       default:
+                               tst_resm(TFAIL, "unexpected error "
+                                        "- %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* check for root as user id of process */
+       check_root();
+
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set without read or alter permissions */
+       if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+
+       /* get the userid for a non root user */
+       ltp_uid = getuserid(ltp_user);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semctl/semctl05.c b/test/ipc/semctl/semctl05.c
new file mode 100644 (file)
index 0000000..7418d3d
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semctl05.c
+ *
+ * DESCRIPTION
+ *     semctl05 - test for ERANGE error
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     loop if that option was specified
+ *     call semctl() with three different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get ERANGE
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semctl05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+
+char *TCID = "semctl05";
+int TST_TOTAL = 3;
+extern int Tst_count;
+
+#ifdef _XLC_COMPILER
+#define SEMUN_CAST 
+#else
+#define SEMUN_CAST (union semun)
+#endif
+
+int exp_enos[] = {ERANGE, 0};  /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+#define BIGV   65535           /* a number ((2^16)-1) that should be larger */
+                               /* than the maximum for a semaphore value    */ 
+
+#ifdef _XLC_COMPILER
+#define SEMUN_CAST
+#else
+#define SEMUN_CAST (union semun)
+#endif
+
+
+unsigned short big_arr[] = {BIGV, BIGV, BIGV, BIGV, BIGV, BIGV, BIGV, BIGV,
+                           BIGV, BIGV};
+
+struct test_case_t {
+       int count;
+       int cmd;
+       union semun t_arg;
+} TC[3];
+
+void setup_test_case(void)
+{
+       /* ERANGE - the value to set is less than zero - SETVAL */
+       /* {5, SETVAL, SEMUN_CAST -1}, */
+    TC[0].count = 5;
+    TC[0].cmd = SETVAL;
+    TC[0].t_arg.val = -1;
+       
+       /* ERANGE - the values to set are too large, > semaphore max value */
+       /* {0, SETALL, SEMUN_CAST big_arr}, */
+    TC[1].count = 0;
+    TC[1].cmd = SETALL;
+    TC[1].t_arg.array = big_arr;
+
+       /* ERANGE - the value to set is too large, > semaphore max value */
+       /* {5, SETVAL, SEMUN_CAST BIGV} */
+    TC[2].count = 5;
+    TC[2].cmd = SETVAL;
+    TC[2].t_arg.val = BIGV;
+}
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       TEST(semctl(sem_id_1, TC[i].count,
+                                   TC[i].cmd, TC[i].t_arg));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case ERANGE:
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       default:
+                               tst_resm(TFAIL, "unexpected error "
+                                        "- %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+    setup_test_case();
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resouce */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semctl/semctl06.c b/test/ipc/semctl/semctl06.c
new file mode 100644 (file)
index 0000000..c3957be
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+/* 10/30/2002  Port to LTP     dbarrera@us.ibm.com */
+
+
+/*
+ * NAME
+ *     semctl06
+ *
+ * CALLS
+ *     semctl(2) semget(2) semop(2)
+ *
+ * ALGORITHM
+ *     Get and manipulate a set of semaphores.
+ *
+ * RESTRICTIONS
+ *
+ * WARNING
+ *     If this test fail, it may be necessary to use the ipcs and ipcrm
+ *     commands to remove any semaphores left in the system due to a
+ *     premature exit of this test.
+ */
+
+#define DEBUG 0
+
+#ifdef UCLINUX
+#define _GNU_SOURCE /* for asprintf */
+#include <stdio.h>
+#endif
+
+#include <sys/types.h>         /* needed for test              */
+#include <sys/ipc.h>           /* needed for test              */
+#include <sys/sem.h>           /* needed for test              */
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "test.h"
+#include "usctest.h"
+#include <sys/wait.h>
+#include "ipcsem.h"
+
+int local_flag=1;
+
+
+#define NREPS  10
+#define NPROCS 3
+#define NKIDS  5
+#define NSEMS  5
+#define HVAL   1000
+#define LVAL   100
+#define FAILED 0
+
+void setup (void);
+void cleanup(void);
+
+static key_t           keyarray[NPROCS];
+static struct sembuf   semops[NSEMS];
+static short           maxsemvals[NSEMS];
+static int             pidarray[NPROCS];
+static int             kidarray[NKIDS];
+static int             tid;
+static int             procstat;
+static char           *prog;
+static unsigned short          semvals[NSEMS];
+
+/*
+ *  * These globals must be defined in the test.
+ *   * */
+
+
+char *TCID="semctl06";           /* Test program identifier.    */
+int TST_TOTAL=1;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+int exp_enos[]={0};     /* List must end with 0 */
+
+
+static void term(int sig);
+static void dosemas(int id);
+static void dotest(key_t key);
+
+#ifdef UCLINUX
+static char *argv0;
+
+void do_child();
+static int id_uclinux;
+static char *maxsemstring;
+#endif
+
+/*--------------------------------------------------------------*/
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+       register int i, j, ok, pid;
+       int count, child, status, nwait;
+
+#ifdef UCLINUX
+       char *msg;
+       if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       argv0 = argv[0];
+       maybe_run_child(&do_child, "dS", &id_uclinux, &maxsemstring);
+#endif
+
+       prog = argv[0];
+       nwait = 0;
+       setup();                
+/*--------------------------------------------------------------*/
+       srand(getpid());
+
+       tid = -1;
+
+       for (i = 0; i < NPROCS; i++) {
+               do {
+                       keyarray[i] = (key_t)rand();
+                       if (keyarray[i] == IPC_PRIVATE) {
+                               ok = 0;
+                               continue;
+                       }
+                       ok = 1;
+                       for (j = 0; j < i; j++) {
+                               if (keyarray[j] == keyarray[i]) {
+                                       ok = 0;
+                                       break;
+                               }
+                       }
+               } while (ok == 0);
+       }
+
+       if ((signal(SIGTERM, term)) == SIG_ERR) {
+                tst_resm(TFAIL, "\tsignal failed. errno = %d", errno);
+               tst_exit();
+       }
+
+       for (i = 0; i <  NPROCS; i++) {
+               if ((pid = FORK_OR_VFORK()) < 0) {
+                        tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
+                        tst_exit();
+               }
+               if (pid == 0) {
+                       procstat = 1;
+                       dotest(keyarray[i]);
+                       exit(0);
+               }
+               pidarray[i] = pid;
+               nwait++;
+       }
+
+       /*
+        * Wait for children to finish.
+        */
+
+       count = 0;
+       while((child = wait(&status)) > 0) {
+               if (status) {
+                       tst_resm(TFAIL, "%s[%d] Test failed.  exit=0x%x", prog, child, status);
+                       local_flag = FAILED;
+               }
+               ++count;
+       }
+
+       /*
+        * Should have collected all children.
+        */
+
+       if (count != nwait) {
+                tst_resm(TFAIL, "\tWrong # children waited on, count = %d", count);
+               local_flag = FAILED;
+       }
+
+       if (local_flag != FAILED)
+               tst_resm(TPASS, "semctl06 ran successfully!");
+       else tst_resm(TFAIL, "semctl06 failed");
+       
+/*--------------------------------------------------------------*/
+/* Clean up any files created by test before call to anyfail.  */
+
+       cleanup ();
+
+       return (0); /* shut lint up */
+}
+/*--------------------------------------------------------------*/
+
+
+static void
+dotest(key_t key)
+{
+       int id, pid, status;
+       int count, child, nwait;
+       short i;
+                union semun get_arr;
+
+       nwait = 0;
+       srand(getpid());
+       if ((id = semget(key, NSEMS, IPC_CREAT)) < 0) {
+               tst_resm(TFAIL, "\tsemget() failed errno %d", errno);
+               exit(1);
+       }
+       tid = id;
+       for (i = 0; i < NSEMS; i++) {
+               do {
+                       maxsemvals[i] = /*CASTOK*/(short)(rand() % HVAL);
+               } while (maxsemvals[i] < LVAL);
+               semops[i].sem_num = i;
+               semops[i].sem_op = maxsemvals[i];
+               semops[i].sem_flg = SEM_UNDO;
+       }
+       if (semop(id, semops, NSEMS) < 0) {
+               tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno);
+               exit(1);
+       }
+                       
+       for (i = 0; i < NKIDS; i++) {
+               if ((pid = FORK_OR_VFORK()) < 0) {
+                       tst_resm(TFAIL, "\tfork failed");
+               }
+               if (pid == 0) {
+#ifdef UCLINUX
+                       int j;
+                       maxsemstring = "";
+                       for (j = 0; j < NSEMS; j++) {
+                               if (asprintf(&maxsemstring, "%s%s%d",
+                                            maxsemstring, (j ? ":" : ""),
+                                            maxsemvals[j]) < 0) {
+                                       tst_resm(TBROK, "Could not serialize "
+                                                "maxsemvals");
+                                       tst_exit();
+                               }
+                       }
+                       if (self_exec(argv0, "dS", id, maxsemstring) < 0) {
+                               tst_resm(TFAIL, "\tself_exec failed");
+                       }
+#else
+                       dosemas(id);
+#endif
+               }
+               if (pid > 0) {
+                       kidarray[i] = pid;
+                       nwait++;
+               }
+       }
+                       
+
+       procstat = 2;
+       /*
+        * Wait for children to finish.
+        */
+
+       count = 0;
+       while((child = wait(&status)) > 0) {
+               if (status) {
+                       tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x", prog, child, status);
+                       local_flag = FAILED;
+               }
+               ++count;
+       }
+
+       /*
+        * Should have collected all children.
+        */
+
+       if (count != nwait) {
+                tst_resm(TFAIL, "\tWrong # children waited on, count = %d", count);
+               local_flag = FAILED;
+       }
+
+                get_arr.array = semvals;
+                if (semctl(id, 0, GETALL, get_arr) < 0) {
+                tst_resm(TFAIL, "\terror on GETALL");
+               tst_resm(TFAIL, "\tsemctl() failed errno %d", errno);
+       }
+
+       if (DEBUG)
+               tst_resm(TINFO, "\tchecking maxvals");
+       for (i = 0; i < NSEMS; i++) {
+               if (semvals[i] !=  maxsemvals[i]) {
+                       tst_resm(TFAIL, "\terror on i %d orig %d final %d", i, semvals[i],
+                                       maxsemvals[i]);
+                       local_flag = FAILED;
+               }
+       }
+       if (DEBUG)
+               tst_resm(TINFO, "\tmaxvals checked");
+
+       /* 4th arg must either be missing, or must be of type 'union semun'.
+        * CANNOT just be an int, else it crashes on ppc.
+        */
+       get_arr.val = 0;
+       if (semctl(id, 0, IPC_RMID, get_arr) < 0) {
+               tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno);
+               local_flag = FAILED;
+       }
+       if (local_flag == FAILED)
+               exit(1);
+}
+
+#ifdef UCLINUX
+void
+do_child()
+{
+       int i;
+       char *tok;
+       char *endptr;
+
+       tok = strtok(maxsemstring, ":");
+       for (i = 0; i < NSEMS; i++) {
+               if (strlen(tok) == 0) {
+                       tst_resm(TBROK, "Invalid argument to -C option");
+                       tst_exit();
+               }
+
+               maxsemvals[i] = strtol(tok, &endptr, 10);
+               if (*endptr != '\0') {
+                       tst_resm(TBROK, "Invalid argument to -C option");
+                       tst_exit();
+                }
+               tok = strtok(NULL, ":");
+       }
+
+       dosemas(id_uclinux);
+}
+#endif
+
+static void
+dosemas(int id)
+{
+       int i, j;
+
+       srand(getpid());
+       for (i = 0; i < NREPS; i++) {
+               for (j = 0; j < NSEMS; j++) {
+                       semops[j].sem_num = j;
+                       semops[j].sem_flg = SEM_UNDO;
+
+                       do {
+                               semops[j].sem_op = 
+                                       ( - /*CASTOK*/(short)(rand() % (maxsemvals[j]/2)));
+                       } while (semops[j].sem_op == 0);
+               }
+               if (semop(id, semops, NSEMS) < 0) {
+                       tst_resm(TFAIL, "\tsemop1 failed errno %d", errno);
+                       exit(1); 
+               }
+               for (j = 0; j < NSEMS; j++) {
+                       semops[j].sem_op = ( - semops[j].sem_op);
+               }
+               if (semop(id, semops, NSEMS) < 0) {
+                       tst_resm(TFAIL, "\tsemop2 failed errno %d", errno);
+                       exit(1); 
+               }
+       }
+       exit(0);
+}
+
+
+/*ARGSUSED*/
+static void
+term(int sig)
+{
+       int i;
+
+       if ((signal(SIGTERM, term)) == SIG_ERR) {
+               tst_resm(TFAIL, "\tsignal failed. errno %d", errno);
+               exit(1);
+       }
+       if (procstat == 0) {
+               if (DEBUG)
+                       tst_resm(TINFO, "\ttest killing kids");
+               for (i = 0; i < NPROCS; i++) {
+                       if (kill(pidarray[i], SIGTERM) != 0) {
+                               tst_resm(TFAIL, "Kill error pid = %d :",pidarray[1]);
+                       }
+               }
+               if (DEBUG)
+                       tst_resm(TINFO, "\ttest kids killed");
+               return;
+       }
+
+       if (procstat == 1) {
+               /* 4th arg must either be missing, or must be of type 'union semun'.
+                * CANNOT just be an int, else it crashes on ppc.
+                */
+               union semun arg;
+               arg.val = 0;
+               (void)semctl(tid, 0, IPC_RMID, arg);
+               exit(1);
+       }
+
+       if (tid == -1) {
+               exit(1);
+       }
+       for (i = 0; i < NKIDS; i++) {
+               if (kill(kidarray[i], SIGTERM) != 0) {
+                       tst_resm(TFAIL, "Kill error kid id = %d :",kidarray[1]);
+               }
+       }
+}
+
+/***************************************************************
+ * setup() - performs all ONE TIME setup for this test.
+ *****************************************************************/
+void
+setup()
+{
+        /* You will want to enable some signal handling so you can capture
+        * unexpected signals like SIGSEGV.
+        *                   */
+        tst_sig(FORK, DEF_HANDLER, cleanup);
+
+
+        /* Pause if that option was specified */
+        /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
+        * fork the test with the -c option.  You want to make sure you do this
+        * before you create your temporary directory.
+        */
+        TEST_PAUSE;
+}
+
+
+/***************************************************************
+ * cleanup() - performs all ONE TIME cleanup for this test at
+ * completion or premature exit.
+ ****************************************************************/
+void
+cleanup()
+{
+        /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+        TEST_CLEANUP;
+
+        /* exit with return code appropriate for results */
+        tst_exit();
+}
+
diff --git a/test/ipc/semctl/semctl07.c b/test/ipc/semctl/semctl07.c
new file mode 100644 (file)
index 0000000..b93bf92
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+/* 10/30/2002  Port to LTP     dbarrera@us.ibm.com */
+
+/*
+ * NAME
+ *     semctl07
+ *
+ * CALLS
+ *     semctl(2) semget(2)
+ *
+ * ALGORITHM
+ *     Get and manipulate a set of semaphores.
+ *
+ * RESTRICTIONS
+ *
+ */
+
+
+#include <sys/types.h>         /* needed for test              */
+#include <sys/ipc.h>           /* needed for test              */
+#include <sys/sem.h>           /* needed for test              */
+#include <signal.h>            /* needed for test              */
+#include <errno.h>             /* needed for test              */
+#include <stdio.h>             /* needed by testhead.h         */
+#include <sys/wait.h>          /* needed by testhead.h         */
+#include "ipcsem.h"
+#include "test.h"
+#include "usctest.h"
+
+
+void setup(void);
+void cleanup(void);
+
+
+/*
+ *These globals must be defined in the test.
+ */
+
+
+char *TCID="semctl07";           /* Test program identifier.    */
+int TST_TOTAL=1;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+int exp_enos[]={0};     /* List must end with 0 */
+
+
+
+/*--------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+       key_t key;
+       int semid, nsems, status;
+       struct semid_ds buf_ds;
+
+       union semun {
+               int val;
+               struct semid_ds *buf;
+               short *array;
+       };
+
+       union semun arg;
+
+       setup();                /* temp file is now open        */
+/*--------------------------------------------------------------*/
+       key = nsems = 1;
+       if ((semid = semget(key, nsems, SEM_RA|IPC_CREAT)) == -1) {
+               tst_resm(TFAIL, "semget() failed errno = %d", errno);
+               tst_exit();
+       }
+       arg.buf = &buf_ds;
+       if ((status = semctl(semid, 0, IPC_STAT, arg)) == -1) {
+               tst_resm(TFAIL, "semctl() failed errno = %d", errno);
+               semctl(semid, 1, IPC_RMID, arg);
+               tst_exit();
+       }
+
+       /*
+        * Check contents of semid_ds structure.
+        */
+
+       if (arg.buf->sem_nsems != nsems) {
+               tst_resm(TFAIL, "error: unexpected number of sems %d", arg.buf->sem_nsems);
+               tst_exit();
+       }
+       if (arg.buf->sem_perm.uid != getuid()) {
+               tst_resm(TFAIL, "error: unexpected uid %d", arg.buf->sem_perm.uid);
+               tst_exit();
+       }
+       if (arg.buf->sem_perm.gid != getgid()) {
+               tst_resm(TFAIL, "error: unexpected gid %d", arg.buf->sem_perm.gid);
+               tst_exit();
+       }
+       if (arg.buf->sem_perm.cuid != getuid()) {
+               tst_resm(TFAIL, "error: unexpected cuid %d", arg.buf->sem_perm.cuid);
+               tst_exit();
+       }
+       if (arg.buf->sem_perm.cgid != getgid()) {
+               tst_resm(TFAIL, "error: unexpected cgid %d", arg.buf->sem_perm.cgid);
+               tst_exit();
+       }
+       if ((status = semctl(semid, 0, GETVAL, arg)) == -1) {
+               tst_resm(TFAIL, "semctl(GETVAL) failed errno = %d", errno);
+               tst_exit();
+       }
+       arg.val = 1;
+       if ((status = semctl(semid, 0, SETVAL, arg)) == -1) {
+               tst_resm(TFAIL, "SEMCTL(SETVAL) failed errno = %d", errno);
+               tst_exit();
+       }
+       if ((status = semctl(semid, 0, GETVAL, arg)) == -1) {
+               tst_resm(TFAIL, "semctl(GETVAL) failed errno = %d", errno);
+               tst_exit();
+       }
+       if (status != arg.val) {
+               tst_resm(TFAIL, "error: unexpected value %d", status);
+               tst_exit();
+       }
+       if ((status = semctl(semid, 0, GETPID, arg)) == -1) {
+               tst_resm(TFAIL, "semctl(GETPID) failed errno = %d", errno);
+               tst_exit();
+       }
+       status = getpid();
+       if (status == 0) 
+       {
+               tst_resm(TFAIL, "error: unexpected pid %d", status);
+               tst_exit();
+       }
+       if ((status = semctl(semid, 0, GETNCNT, arg)) == -1) {
+               tst_resm(TFAIL, "semctl(GETNCNT) failed errno = %d", errno);
+               tst_exit();
+       }
+       if (status != 0) {
+               tst_resm(TFAIL, "error: unexpected semncnt %d", status);
+               tst_exit();
+       }
+       if ((status = semctl(semid, 0, GETZCNT, arg)) == -1) {
+               tst_resm(TFAIL, "semctl(GETZCNT) failed errno = %d", errno);
+               tst_exit();
+       }
+       if (status != 0) {
+               tst_resm(TFAIL, "error: unexpected semzcnt %d", status);
+               tst_exit();
+       }
+               
+       semctl(semid, 0, IPC_RMID, arg);
+       if ((status = semctl(semid, 0, GETPID, arg)) != -1) {
+               tst_resm(TFAIL, "semctl(IPC_RMID) failed");
+               tst_exit();
+       }
+
+       tst_resm(TPASS, "semctl07 ran successfully!");
+/*--------------------------------------------------------------*/
+/* Clean up any files created by test before exit.             */
+/*--------------------------------------------------------------*/
+
+       cleanup();
+       return (0);
+}
+/*--------------------------------------------------------------*/
+
+/***************************************************************
+ * setup() - performs all ONE TIME setup for this test.
+ *****************************************************************/
+void
+setup()
+{
+        /* You will want to enable some signal handling so you can capture
+        * unexpected signals like SIGSEGV.
+        *                   */
+        tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+
+        /* Pause if that option was specified */
+        /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
+        * fork the test with the -c option.  You want to make sure you do this
+        * before you create your temporary directory.
+        */
+        TEST_PAUSE;
+}
+
+
+/***************************************************************
+ * cleanup() - performs all ONE TIME cleanup for this test at
+ * completion or premature exit.
+ ****************************************************************/
+void
+cleanup()
+{
+        /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+        TEST_CLEANUP;
+
+        /* exit with return code appropriate for results */
+        tst_exit();
+}
+
diff --git a/test/ipc/semctl/test.sh b/test/ipc/semctl/test.sh
new file mode 100644 (file)
index 0000000..baf468b
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+./semctl01
+./semctl02
+./semctl03
+./semctl04
+./semctl05
+./semctl06
+./semctl07
diff --git a/test/ipc/semget/Makefile b/test/ipc/semget/Makefile
new file mode 100644 (file)
index 0000000..c1aa8f1
--- /dev/null
@@ -0,0 +1,41 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = semget01 semget02 semget03 semget05 semget06
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+semget01: semget01.c
+semget02: semget02.c
+semget03: semget03.c
+semget05: semget05.c
+semget06: semget06.c
diff --git a/test/ipc/semget/semget01.c b/test/ipc/semget/semget01.c
new file mode 100644 (file)
index 0000000..e23928c
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semget01.c
+ *
+ * DESCRIPTION
+ *     semget01 - test that semget() correclty creates a semaphore set
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     call semget() to create the semaphore set
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             stat the semaphore set
+ *             if the number of primitive semaphores is correct and
+ *                the semaphore uid == the process uid
+ *             then,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semget01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+#include "usctest.h"
+
+
+char *TCID = "semget01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int sem_id_1 = -1;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       void check_functionality(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Use TEST macro to make the call
+                */
+
+               TEST(semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d : %s",
+                                TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+               } else {
+                       /* get the semaphore ID */
+                       sem_id_1 = TEST_RETURN;
+
+                       if (STD_FUNCTIONAL_TEST) {
+                               check_functionality();  
+                       } else {
+                               tst_resm(TPASS, "semaphore was created");
+                       }
+               }
+
+               /*
+                * remove the semaphore that was created and mark the ID
+                * as invalid.
+                */
+               if (sem_id_1 != -1) {
+                       rm_sema(sem_id_1);
+                       sem_id_1 = -1;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * check_functionality() - check the functionality of the tested system call.
+ */
+void
+check_functionality(void)
+{
+       struct semid_ds semary;
+       union semun un_arg;             /* union defined in ipcsem.h */
+
+       /* STAT the semaphore */
+       un_arg.buf = &semary;
+       if (semctl(sem_id_1, 0, IPC_STAT, un_arg) == -1) {
+               tst_brkm(TBROK, cleanup, "Could not stat the semaphore");
+               return;
+       }
+
+       if (un_arg.buf->sem_nsems != PSEMS) {
+               tst_resm(TFAIL, "# of semaphores in set != # given to create");
+               return;
+       }
+
+       if (un_arg.buf->sem_perm.cuid != geteuid()) {
+               tst_resm(TFAIL, "semaphore uid != process uid");
+               return;
+       }
+
+       tst_resm(TPASS, "basic semaphore values are okay");
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resouce */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semget/semget02.c b/test/ipc/semget/semget02.c
new file mode 100644 (file)
index 0000000..8efd18c
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semget02.c
+ *
+ * DESCRIPTION
+ *     semget02 - test for EACCES and EEXIST errors
+ *
+ * ALGORITHM
+ *     create a semaphore set without read or alter permissions
+ *     loop if that option was specified
+ *     call semget() using two different invalid cases 
+ *     check the errno value
+ *       issue a PASS message if we get EACCES or EEXIST
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semget02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+#include <pwd.h>
+
+#include "../lib/ipcsem.h"
+
+char *TCID = "semget02";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+int exp_enos[] = {EACCES, EEXIST, 0};
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+
+int sem_id_1 = -1;
+
+struct test_case_t {
+       int flags;
+       int error;
+} TC [] = {
+       /* EACCES - the semaphore has no read or alter permissions */
+       {SEM_RA, EACCES},
+
+       /* EEXIST - the semaphore id exists and semget() was called with  */
+       /* IPC_CREAT and IPC_EXCL                                         */
+       {IPC_CREAT | IPC_EXCL, EEXIST}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+                       /* use the TEST macro to make the call */
+       
+                       TEST(semget(semkey, PSEMS, TC[i].flags));
+
+                       if (TEST_RETURN != -1) {
+                               sem_id_1 = TEST_RETURN;
+                               tst_resm(TFAIL, "call succeeded");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno "
+                                        "= %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* Switch to nobody user for correct error code collection */
+       if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+       
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+        ltpuser = getpwnam(nobody_uid);
+         if (seteuid(ltpuser->pw_uid) == -1) {
+               tst_resm(TINFO, "setreuid failed to "
+                        "to set the effective uid to %d",
+                        ltpuser->pw_uid);
+               perror("setreuid");
+        }
+                       
+       
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set without read or alter permissions */
+       if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semget/semget03.c b/test/ipc/semget/semget03.c
new file mode 100644 (file)
index 0000000..1b5c780
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semget03.c
+ *
+ * DESCRIPTION
+ *     semget03 - test for ENOENT error
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     call semget() with a valid key but with no associated semaphore set
+ *        and IPC_CREAT is not asserted
+ *     check the errno value
+ *       issue a PASS message if we get ENOENT
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semget03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "../lib/ipcsem.h"
+
+char *TCID = "semget03";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {ENOENT, 0};  /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* use the TEST macro to make the call */
+       
+               TEST(semget(semkey, PSEMS, SEM_RA));
+
+               if (TEST_RETURN != -1) {
+                       sem_id_1 = TEST_RETURN;
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case ENOENT:
+                       tst_resm(TPASS, "expected failure - errno "
+                                "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semget/semget05.c b/test/ipc/semget/semget05.c
new file mode 100644 (file)
index 0000000..1c6b610
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semget05.c
+ *
+ * DESCRIPTION
+ *     semget05 - test for ENOSPC error
+ *
+ * ALGORITHM
+ *     create semaphore sets in a loop until the system limit is reached
+ *     loop if that option was specified
+ *     attempt to create yet another semaphore set
+ *     check the errno value
+ *       issue a PASS message if we get ENOSPC
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semget05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *      07/2006 - Changes By Michael Reed
+ *                - Changed the value of MAXIDS for the specific machine by reading 
+ *                  the system limit for SEMMNI - The maximum number of sempahore sets    
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "../lib/ipcsem.h"
+
+char *TCID = "semget05";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+/*
+ * The MAXIDS value is somewhat arbitrary and may need to be increased
+ * depending on the system being tested.  
+ */
+
+int MAXIDS=2048;
+
+int exp_enos[] = {ENOSPC, 0};  /* 0 terminated list of expected errnos */
+int *sem_id_arr;
+int num_sems = 0;              /* count the semaphores created */
+
+int main(int ac, char **av)
+{
+       int lc,getmaxid;                                /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       FILE *fp;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       /* Set the MAXIDS for the specific machine by reading the system limit
+           for SEMMNI - The maximum number of sempahore sets                  */
+       if((fp = fopen("/proc/sys/kernel/sem", "r")) != NULL) 
+         {
+           for(lc= 0; lc < 4; lc++)
+             {
+               if(lc == 3)
+                 {
+                   if(getmaxid > MAXIDS)
+                     MAXIDS=getmaxid;
+                 }
+             }
+
+         }
+       fclose(fp);
+
+       sem_id_arr = (int*)malloc(sizeof(int)*MAXIDS);
+
+       setup();                        /* global setup */      
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* use the TEST macro to make the call */
+       
+               TEST(semget(semkey + num_sems, PSEMS,
+                           IPC_CREAT | IPC_EXCL | SEM_RA));
+               /*      printf("rc = %ld \n",   TEST_RETURN); */
+               if (TEST_RETURN != -1) {
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case ENOSPC:
+                       tst_resm(TPASS, "expected failure - errno "
+                                "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       int sem_q;
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /*
+        * Use a while loop to create the maximum number of semaphore sets.
+        * If the loop exceeds MAXIDS, then break the test and cleanup.
+        */
+       while((sem_q =
+                semget(semkey + num_sems, PSEMS, IPC_CREAT|IPC_EXCL)) != -1) {
+               sem_id_arr[num_sems++] = sem_q;
+               if (num_sems == MAXIDS) {
+                       tst_brkm(TBROK, cleanup, "The maximum number of "
+                                "semaphore ID's has been\n\t reached.  Please "
+                                "increase the MAXIDS value in the test.");
+               }
+       }
+
+       /*
+        * If the errno is other than ENOSPC, then something else is wrong.
+        */
+
+       if (errno != ENOSPC) {
+               tst_brkm(TBROK, cleanup, "Didn't get ENOSPC in test setup"
+                        " - errno = %d : %s", errno, strerror(errno));
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       int i;
+
+       /* remove the semaphore resources that were created */
+       for (i=0; i<num_sems; i++) {
+               rm_sema(sem_id_arr[i]);
+       }
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semget/semget06.c b/test/ipc/semget/semget06.c
new file mode 100644 (file)
index 0000000..fed4b01
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semget06.c
+ *
+ * DESCRIPTION
+ *     semget06 - test for EINVAL error
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     call semget() using two different invalid cases - too many and too
+ *        few primitive semaphores
+ *     check the errno value
+ *       issue a PASS message if we get EINVAL
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semget06 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "../lib/ipcsem.h"
+
+char *TCID = "semget06";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+#define LARGENUM       1024 * 32
+#define SMALLNUM       -1
+
+int exp_enos[] = {EINVAL, 0};  /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+int num_sems[] = {LARGENUM, SMALLNUM};
+
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+       
+               for (i=0; i<TST_TOTAL; i++) {
+                       TEST(semget(semkey, num_sems[i],
+                                   IPC_CREAT | IPC_EXCL | SEM_RA));
+
+                       if (TEST_RETURN != -1) {
+                               sem_id_1 = TEST_RETURN;
+                               tst_resm(TFAIL, "call succeeded");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case EINVAL:
+                               tst_resm(TPASS, "expected failure - errno "
+                                        "= %d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       default:
+                               tst_resm(TFAIL, "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semget/test.sh b/test/ipc/semget/test.sh
new file mode 100644 (file)
index 0000000..3919705
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+./semget01
+./semget02
+./semget03
+./semget05
+./semget06
+
diff --git a/test/ipc/semop/Makefile b/test/ipc/semop/Makefile
new file mode 100644 (file)
index 0000000..8089c50
--- /dev/null
@@ -0,0 +1,42 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = semop01 semop02 semop03 semop04 semop05
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+semop01: semop01.c
+semop02: semop02.c
+semop03: semop03.c
+semop04: semop04.c
+semop05: semop05.c
+
diff --git a/test/ipc/semop/semop01.c b/test/ipc/semop/semop01.c
new file mode 100644 (file)
index 0000000..1574e14
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semop01.c
+ *
+ * DESCRIPTION
+ *     semop01 - test that semop() basic functionality is correct
+ *
+ * ALGORITHM
+ *     create a semaphore set and initialize some values
+ *     loop if that option was specified
+ *     call semop() to set values for the primitive semaphores
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             get the semaphore values and compare with expected values
+ *             if correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *       else issue a PASS message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semop01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001  - Written by Wayne Boyer
+ *     17/01/02 - Modified. Manoj Iyer, IBM Austin. TX. manjo@austin.ibm.com
+ *                4th argument to semctl() system call was modified according
+ *                to man pages. 
+ *                In my opinion The test should not even have compiled but
+ *                it was working due to some mysterious reason.
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+
+#define NSEMS  4       /* the number of primitive semaphores to test */
+
+char *TCID = "semop01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int sem_id_1 = -1;     /* a semaphore set with read & alter permissions */
+
+
+struct sembuf sops[PSEMS];     /* an array of sembuf structures */
+
+
+int main(int ac, char **av)
+{
+        union semun get_arr;
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+       int fail = 0;
+
+        get_arr.array = malloc(sizeof(unsigned short int) * PSEMS);
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Use TEST macro to make the call
+                */
+
+               TEST(semop(sem_id_1, sops, NSEMS));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d "
+                                ": %s", TCID, TEST_ERRNO,
+                                strerror(TEST_ERRNO));
+               } else {
+                       if (STD_FUNCTIONAL_TEST) {
+
+                               /* get the values and make sure they */
+                               /* are the same as what was set      */
+                               if (semctl(sem_id_1, 0, GETALL, get_arr) ==
+                                   -1) {
+                                       tst_brkm(TBROK, cleanup, "semctl() "
+                                                "failed in functional test");
+                               }
+
+                               for (i=0; i<NSEMS; i++) {
+                                       if (get_arr.array[i] != i*i) {
+                                               fail = 1;
+                                       }
+                               }
+                               if (fail) {
+                                       tst_resm(TFAIL, "semaphore values"
+                                                " are not expected");
+                               } else {
+                                       tst_resm(TPASS, "semaphore values"
+                                                " are correct");
+                               }
+               
+                       } else {
+                               tst_resm(TPASS, "call succeeded");
+                       }
+               }
+
+
+               /*
+                * clean up things in case we are looping
+                */
+               get_arr.val = 0;
+               for (i=0; i<NSEMS; i++) {
+                       if(semctl(sem_id_1, i, SETVAL, get_arr) == -1) {
+                               tst_brkm(TBROK, cleanup, "semctl failed");
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       int i;
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+       
+       /* set up some values for the first four primitive semaphores */
+       for (i=0; i<NSEMS; i++){
+               sops[i].sem_num = i;
+               sops[i].sem_op = i*i;   /* 0, 1, 4, 9, */
+               sops[i].sem_flg = SEM_UNDO;
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resouce */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semop/semop02.c b/test/ipc/semop/semop02.c
new file mode 100644 (file)
index 0000000..448de6e
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semop02.c
+ *
+ * DESCRIPTION
+ *     semop02 - test for E2BIG, EACCES, EFAULT and EINVAL errors
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     create a semaphore set without read and alter permissions
+ *     loop if that option was specified
+ *     call semop with five different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get E2BIG, EACCES, EFAULT or EINVAL
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semop02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+#include <pwd.h>
+
+#include "ipcsem.h"
+
+char *TCID = "semop02";
+int TST_TOTAL = 4;
+extern int Tst_count;
+
+int exp_enos[] = {E2BIG, EACCES, EFAULT, EINVAL, 0};
+
+int sem_id_1 = -1;     /* a semaphore set with read & alter permissions */
+int sem_id_2 = -1;     /* a semaphore set without read & alter permissions */
+int bad_id = -1;
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+struct sembuf s_buf[PSEMS];
+
+int badbuf = -1;
+
+#define NSOPS  5               /* a resonable number of operations */
+#define        BIGOPS  1024            /* a value that is too large for the number */
+                               /* of semop operations that are permitted   */
+
+struct test_case_t {
+       int *semid;             /* the semaphore id */
+       struct sembuf *t_sbuf;  /* the first in an array of sembuf structures */
+       unsigned t_ops;         /* the number of elements in the above array */
+       int error;              /* the expected error number */
+} TC[] = {
+       /* E2BIG - the number of operations is too big */
+       {&sem_id_1, (struct sembuf *)&s_buf, BIGOPS, E2BIG},
+
+       /* EACCES - the semaphore set has no access permission */
+       {&sem_id_2, (struct sembuf *)&s_buf, NSOPS, EACCES},
+
+       /* EINVAL - the number of elments (t_ops) is 0 */
+       {&sem_id_1, (struct sembuf *)&s_buf, 0, EINVAL},
+
+       /* EINVAL - the semaphore set doesn't exist */
+       {&bad_id, (struct sembuf *)&s_buf, NSOPS, EINVAL}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+                       /*
+                        * use the TEST macro to make the call
+                        */
+       
+                       TEST(semop(*(TC[i].semid), TC[i].t_sbuf, TC[i].t_ops));
+
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       ltpuser = getpwnam(nobody_uid);
+       if (seteuid(ltpuser->pw_uid) == -1) {
+               tst_resm(TINFO, "setreuid failed to "
+                               "to set the effective uid to %d",
+                               ltpuser->pw_uid);
+               perror("setreuid");
+       }
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+
+       /* increment the semkey */
+       semkey += 1;
+       
+       /* create a semaphore set without read and alter permissions */
+       if ((sem_id_2 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if they exist, remove the semaphore resources */
+       rm_sema(sem_id_1);
+       rm_sema(sem_id_2);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semop/semop03.c b/test/ipc/semop/semop03.c
new file mode 100644 (file)
index 0000000..47a9845
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semop03.c
+ *
+ * DESCRIPTION
+ *     semop03 - test for EFBIG error
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     loop if that option was specified
+ *     call semop() using two different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EFBIG
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semop03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+
+char *TCID = "semop03";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+int exp_enos[] = {EFBIG, 0};   /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+struct sembuf s_buf;
+
+int TC[] = {-1, PSEMS + 1};    /* negative and too many "primitive" semas */
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) !=(char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* initialize two fields in the sembuf structure here */
+       s_buf.sem_op = 1;       /* add this value to struct sem.semval */
+       s_buf.sem_flg = SEM_UNDO;       /* undo when process exits */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /* initialize the last field in the sembuf */
+                       /* structure to the test dependent value   */
+                       s_buf.sem_num = TC[i];
+
+                       /*
+                        * use the TEST macro to make the call
+                        */
+
+                       TEST(semop(sem_id_1, &s_buf, 1));
+
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       switch(TEST_ERRNO) {
+                       case EFBIG:
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       default:
+                               tst_resm(TFAIL, "unexpected error - "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               break;
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore with read and alter permissions */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semop/semop04.c b/test/ipc/semop/semop04.c
new file mode 100644 (file)
index 0000000..8a5f3c3
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semop04.c
+ *
+ * DESCRIPTION
+ *     semop04 - test for EAGAIN error
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     loop if that option was specified
+ *     call semop() with two different invalid cases
+ *     check the errno value
+ *       issue a PASS message if we get EAGAIN
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semop04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+
+char *TCID = "semop04";
+int TST_TOTAL = 2;
+extern int Tst_count;
+
+int exp_enos[] = {EAGAIN, 0};  /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+struct sembuf s_buf;
+
+struct test_case_t {
+       union semun get_arr;
+       short op;
+       short flg;
+       short num;
+       int error;
+} TC[] = {
+       /* EAGAIN sem_op = 0 */
+       {{1}, 0, IPC_NOWAIT, 2, EAGAIN},
+
+       /* EAGAIN sem_op = -1 */
+       {{0}, -1, IPC_NOWAIT, 2, EAGAIN}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int val = 1;                    /* value for SETVAL */
+       
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /* initialize the s_buf buffer */
+                       s_buf.sem_op = TC[i].op;
+                       s_buf.sem_flg = TC[i].flg;
+                       s_buf.sem_num = TC[i].num;
+
+                       /* initialize all the primitive semaphores */
+                       TC[i].get_arr.val = val--;
+                       if (semctl(sem_id_1, TC[i].num, SETVAL, TC[i].get_arr)
+                           == -1) {
+                               tst_brkm(TBROK, cleanup, "semctl() failed");
+                       }
+
+                       /*
+                        * make the call with the TEST macro
+                        */
+
+                       TEST(semop(sem_id_1, &s_buf, 1));
+
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = %d"                                          " : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "unexpected error - "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       /* and PSEMS "primitive" semaphores                       */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/semop/semop05.c b/test/ipc/semop/semop05.c
new file mode 100644 (file)
index 0000000..f30db6b
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     semop05.c
+ *
+ * DESCRIPTION
+ *     semop05 - test for EINTR and EIDRM errors
+ *
+ * ALGORITHM
+ *     create a semaphore set with read and alter permissions
+ *     loop if that option was specified
+ *     set up the s_buf buffer
+ *     initialize the primitive semaphores
+ *     fork a child process
+ *     child calls semop() and sleeps
+ *     parent either removes the semaphore set or sends a signal to the child
+ *     parent then exits
+ *     child gets a return from the semop() call
+ *     check the errno value
+ *       issue a PASS message if we get EINTR or EIDRM
+ *     otherwise, the tests fails
+ *       issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  semop05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcsem.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void sighandler(int);
+
+char *TCID = "semop05";
+int TST_TOTAL = 4;
+extern int Tst_count;
+
+int exp_enos[] = {EINTR, EIDRM, 0};  /* 0 terminated list of expected errnos */
+
+int sem_id_1 = -1;
+
+struct sembuf s_buf;
+
+struct test_case_t {
+       union semun semunptr;
+       short op;
+       short flg;
+       short num;
+       int error;
+} TC[] = {
+       /* EIRDM sem_op = 0 */
+       {{1}, 0, 0, 2, EIDRM},
+
+       /* EIRDM sem_op = -1 */
+       {{0}, -1, 0, 3, EIDRM},
+
+       /* EINTR sem_op = 0 */
+       {{1}, 0, 0, 4, EINTR},
+
+       /* EINTR sem_op = -1 */
+       {{0}, -1, 0, 5, EINTR}
+};
+
+#ifdef UCLINUX
+void do_child_uclinux();
+static int i_uclinux;
+#endif
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+       pid_t pid;
+       void do_child(int);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+#ifdef UCLINUX
+       maybe_run_child(&do_child_uclinux, "dd", &i_uclinux, &sem_id_1);
+#endif
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /* initialize the s_buf buffer */
+                       s_buf.sem_op = TC[i].op;
+                       s_buf.sem_flg = TC[i].flg;
+                       s_buf.sem_num = TC[i].num;
+
+                       /* initialize all of the primitive semaphores */
+                       if (semctl(sem_id_1, TC[i].num, SETVAL, TC[i].semunptr)
+                           == -1) {
+                               tst_brkm(TBROK, cleanup, "semctl() failed");
+                       }
+
+                       if ((pid = fork()) == -1) {
+                               tst_brkm(TBROK, cleanup, "could not fork");
+                       }
+
+                       if (pid == 0) {         /* child */
+#ifdef UCLINUX
+                               if (self_exec(av[0], "dd", i, sem_id_1) < 0) {
+                                       tst_brkm(TBROK, cleanup,
+                                                "could not self_exec");
+                               }
+#else
+                               do_child(i);
+#endif
+                       } else {                /* parent */
+                               usleep(250000);
+
+                               /*
+                                * If we are testing for EIDRM then remove
+                                * the semaphore, else send a signal that
+                                * must be caught as we are testing for
+                                * EINTR.
+                                */
+                               if (TC[i].error == EIDRM) {
+                                       /* remove the semaphore resource */
+                                       rm_sema(sem_id_1);
+                               } else {
+                                       if (kill(pid, SIGHUP) == -1) {
+                                               tst_brkm(TBROK, cleanup,
+                                                        "kill failed");
+                                       }
+                               }
+
+                               /* let the child carry on */
+                               waitpid(pid,NULL,0);
+                       }
+
+                       /*
+                        * recreate the semaphore resource if needed
+                        */
+                       if (TC[i].error == EINTR) {
+                               continue;
+                       }
+
+                       if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT |
+                                              IPC_EXCL | SEM_RA)) == -1) {
+                               tst_brkm(TBROK, cleanup, "couldn't recreate "
+                                        "semaphore");
+                       }
+               }
+       }
+       
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * do_child()
+ */
+void
+do_child(int i)
+{
+       /*
+        * make the call with the TEST macro
+        */
+
+       TEST(semop(sem_id_1, &s_buf, 1));
+
+       if (TEST_RETURN != -1) {
+               tst_resm(TFAIL, "call succeeded when error expected");
+               exit(-1);
+       }
+       
+       TEST_ERROR_LOG(TEST_ERRNO);
+
+       if (TEST_ERRNO == TC[i].error) {
+               tst_resm(TPASS, "expected failure - errno = %d"
+                        " : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+       } else {
+               tst_resm(TFAIL, "unexpected error - "
+                        "%d : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+       }
+
+       exit(0);
+}
+
+#ifdef UCLINUX
+/*
+ * do_child_uclinux() - capture signals, re-initialize s_buf then call do_child
+ *                      with the appropriate argument
+ */
+void
+do_child_uclinux()
+{
+       int i = i_uclinux;
+
+       /* capture signals */
+       tst_sig(FORK, sighandler, cleanup);
+
+       /* initialize the s_buf buffer */
+       s_buf.sem_op = TC[i].op;
+       s_buf.sem_flg = TC[i].flg;
+       s_buf.sem_num = TC[i].num;
+
+       do_child(i);
+}
+#endif
+
+/*
+ * sighandler() - handle signals
+ */
+void
+sighandler(int sig)
+{
+       /* we don't need to do anything here */
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(FORK, sighandler, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       semkey = getipckey();
+
+       /* create a semaphore set with read and alter permissions */
+       /* and PSEMS "primitive" semaphores                       */
+       if ((sem_id_1 =
+            semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the semaphore resource */
+       rm_sema(sem_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+
+       tst_exit();
+}
+
diff --git a/test/ipc/semop/test.sh b/test/ipc/semop/test.sh
new file mode 100644 (file)
index 0000000..81607b9
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+./semop01
+./semop02
+./semop03
+./semop04
+./semop05
diff --git a/test/ipc/shmat/Makefile b/test/ipc/shmat/Makefile
new file mode 100644 (file)
index 0000000..146d4fc
--- /dev/null
@@ -0,0 +1,39 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = shmat01 shmat02 shmat03
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+shmat01: shmat01.c
+shmat02: shmat02.c
+shmat03: shmat03.c
diff --git a/test/ipc/shmat/shmat01.c b/test/ipc/shmat/shmat01.c
new file mode 100644 (file)
index 0000000..8f88f98
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmat01.c
+ *
+ * DESCRIPTION
+ *     shmat01 - test that shmat() works correctly
+ *
+ * ALGORITHM
+ *     create a shared memory resouce with read/write permissions
+ *     loop if that option was specified
+ *     call shmat() with the TEST() macro using three valid conditions
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             check for the correct conditions after the call
+ *             if correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmat01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmat01";
+int TST_TOTAL = 3;
+extern int Tst_count;
+
+#define CASE0          10              /* values to write into the shared */
+#define CASE1          20              /* memory location.                */
+
+#ifdef __ia64__
+#define UNALIGNED      0x5ff00eee      /* an address not evenly divisible by */
+#elif defined __XTENSA__               /* SHMLBA which defaults to 0x8048e8b */
+/* TASK_SIZE on Xtensa is only 0x40000000 */
+#define UNALIGNED      0x28ffeeee
+#elif defined __arm__
+#define UNALIGNED      0x28ffeeee
+#else
+#define UNALIGNED      0x5fffeeee
+#endif
+
+int shm_id_1 = -1;
+
+void   *addr;                          /* for result of shmat-call */
+
+struct test_case_t {
+       int *shmid;
+       void *addr;
+       int flags;
+} TC[] = {
+       /* a straight forward read/write attach */
+       {&shm_id_1, 0, 0},
+
+       /* an attach using non aligned memory */
+       {&shm_id_1, (void *)UNALIGNED, SHM_RND},
+
+       /* a read only attach */
+       {&shm_id_1, 0, SHM_RDONLY}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+       void check_functionality(int);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /*
+                        * Use TEST macro to make the call
+                        */
+                       errno = 0;
+                       addr = shmat(*(TC[i].shmid), (void *)(TC[i].addr),
+                                  TC[i].flags);
+                       TEST_ERRNO = errno;
+       
+                       if (addr == (void *)-1) {
+                               tst_brkm(TFAIL, cleanup, "%s call failed - "
+                                        "errno = %d : %s", TCID, TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               if (STD_FUNCTIONAL_TEST) {
+                                       check_functionality(i);
+                               } else {
+                                       tst_resm(TPASS, "call succeeded");
+                               }
+                       }
+
+                       /*
+                        * clean up things in case we are looping - in
+                        * this case, detach the shared memory
+                        */
+                       if (shmdt((const void *)addr) == -1) {
+                               tst_brkm(TBROK, cleanup,
+                                        "Couldn't detach shared memory");
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * check_functionality - check various conditions to make sure they 
+ *                      are correct.
+ */
+void
+check_functionality(int i)
+{
+       void *orig_add;
+       int *shared;
+       int fail = 0;
+       struct shmid_ds buf;
+
+       shared = (int *)addr;
+
+       /* stat the shared memory ID */
+       if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't stat shared memory");
+       }
+
+       /* check the number of attaches */
+       if (buf.shm_nattch != 1) {
+               tst_resm(TFAIL, "# of attaches is incorrect");
+               return;
+       }
+
+       /* check the size of the segment */
+       if (buf.shm_segsz != INT_SIZE) {
+               tst_resm(TFAIL, "segment size is incorrect");
+               return;
+       }
+
+       /* check for specific conditions depending on the type of attach */
+       switch(i) {
+       case 0:
+               /*
+                * Check the functionality of the first call by simply
+                * "writing" a value to the shared memory space.
+                * If this fails the program will get a SIGSEGV, dump
+                * core and exit.
+                */
+
+               *shared = CASE0;
+               break;
+       case 1:
+               /*
+                * Check the functionality of the second call by writing
+                * a value to the shared memory space and then checking
+                * that the original address given was rounded down as
+                * specified in the man page.
+                */
+
+               *shared = CASE1;
+               orig_add = (void *)((unsigned long)addr + (((unsigned long)TC[i].addr)%SHMLBA));
+               if (orig_add != TC[i].addr) {
+                       tst_resm(TFAIL, "shared memory address is not "
+                                "correct");
+                       fail = 1;
+               }
+               break;
+       case 2:
+               /*
+                * This time the shared memory is read only.  Read the value
+                * and check that it is equal to the value set in case #2,
+                * because shared memory is persistent.
+                */
+
+               if (*shared != CASE1) {
+                       tst_resm(TFAIL, "shared memory value isn't correct");
+                       fail = 1;
+               }
+               break;
+       }
+
+       if (!fail) {
+               tst_resm(TPASS, "conditions and functionality are correct");
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* Get an IPC resouce key */
+       shmkey = getipckey();
+
+       /* create a shared memory resource with read and write permissions */
+       if ((shm_id_1 = shmget(shmkey++, INT_SIZE, SHM_RW | IPC_CREAT |
+            IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "resource 1 in setup()");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the shared memory resource */
+       rm_shm(shm_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmat/shmat02.c b/test/ipc/shmat/shmat02.c
new file mode 100644 (file)
index 0000000..ccaca9e
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmat02.c
+ *
+ * DESCRIPTION
+ *     shmat02 - check for EINVAL and EACCES errors
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *       call shmat() using three invalid test cases
+ *       check the errno value
+ *         issue a PASS message if we get EINVAL or EACCES
+ *       otherwise, the tests fails
+ *         issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmat02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     Must be ran as non-root
+ */
+
+#include "ipcshm.h"
+#include <pwd.h>
+
+char *TCID = "shmat02";
+int TST_TOTAL = 3;
+extern int Tst_count;
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+
+int exp_enos[] = {EINVAL, EACCES, 0};  /* 0 terminated list of */
+                                       /* expected errnos      */
+
+int shm_id_1 = -1;
+int shm_id_2 = -1;
+int shm_id_3 = -1;
+
+void   *addr;                          /* for result of shmat-call */
+
+#define NADDR  0x40FFFEE5              /* a non alligned address value */
+struct test_case_t {
+       int *shmid;
+       void *addr;
+       int error;
+} TC[] = {
+       /* EINVAL - the shared memory ID is not valid */
+       {&shm_id_1, 0, EINVAL},
+
+       /* EINVAL - the address is not page aligned and SHM_RND is not given */
+       {&shm_id_2, (void *)NADDR, EINVAL},
+
+       /* EACCES - the shared memory resource has no read/write permission */
+       {&shm_id_3, 0, EACCES}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+                       /*
+                        * make the call using the TEST() macro - attempt
+                        * various invalid shared memory attaches
+                        */
+                       errno = 0;
+                               addr = shmat(*(TC[i].shmid), (const void *)TC[i].addr, 0);
+                               TEST_ERRNO = errno;
+
+                       if (addr != (void *)-1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       ltpuser = getpwnam(nobody_uid);
+       if (seteuid(ltpuser->pw_uid) == -1) {
+               tst_resm(TINFO, "setuid failed to "
+                               "to set the effective uid to %d",
+                               ltpuser->pw_uid);
+               perror("seteuid");
+       }
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory resource with read and write permissions */
+       /* also post increment the shmkey for the next shmget call */
+       if ((shm_id_2 = shmget(shmkey++, INT_SIZE, SHM_RW | IPC_CREAT |
+            IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "resource #1 in setup()");
+       }
+
+       /* create a shared memory resource without read and write permissions */
+       if ((shm_id_3 = shmget(shmkey, INT_SIZE, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "resource #2 in setup()");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if they exist, remove the shared memory resources */
+       rm_shm(shm_id_2);
+       rm_shm(shm_id_3);
+
+       if (seteuid(0) == -1) {
+               tst_resm(TINFO, "setuid failed to "
+                               "to set the effective uid to root");
+               perror("seteuid");
+       }
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmat/shmat03.c b/test/ipc/shmat/shmat03.c
new file mode 100644 (file)
index 0000000..d0f6a0e
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmat03.c
+ *
+ * DESCRIPTION
+ *     shmat03 - test for EACCES error
+ *
+ * ALGORITHM
+ *     create a shared memory segment with root only read & write permissions
+ *     fork a child process
+ *     if child
+ *       set the ID of the child process to that of "nobody"
+ *       loop if that option was specified
+ *         call shmat() using the TEST() macro
+ *         check the errno value
+ *           issue a PASS message if we get EACCES
+ *         otherwise, the tests fails
+ *           issue a FAIL message
+ *       call cleanup
+ *     if parent
+ *       wait for child to exit
+ *       remove the shared memory segment
+ *
+ * USAGE:  <for command-line>
+ *  shmat03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     test must be run at root
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmat03";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EACCES, 0};  /* 0 terminated list of expected errnos */
+
+int shm_id_1 = -1;
+
+void   *addr;                  /* for result of shmat-call */
+
+uid_t ltp_uid;
+char *ltp_user = "nobody";
+
+int main(int ac, char **av)
+{
+       char *msg;                      /* message returned from parse_opts */
+       int pid;
+       void do_child(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       if ((pid = FORK_OR_VFORK()) == -1) {
+               tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (pid == 0) {         /* child */
+               /* set the user ID of the child to the non root user */
+               if (setuid(ltp_uid) == -1) {
+                       tst_resm(TBROK, "setuid() failed");
+                       exit(1);
+               }
+
+               do_child();
+
+       } else {                /* parent */
+               /* wait for the child to return */
+               if (waitpid(pid, NULL, 0) == -1) {
+                       tst_brkm(TBROK, cleanup, "waitpid failed");
+               }
+
+               /* if it exists, remove the shared memory resource */
+               rm_shm(shm_id_1);
+
+               /* Remove the temporary directory */
+               tst_rmdir();
+       }
+
+       cleanup();
+       return(0);
+}
+
+/*
+ * do_child - make the TEST call as the child process
+ */
+void
+do_child(void)
+{
+       int lc;
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * use TEST macro to make the call
+                */
+               errno = 0;
+               addr = shmat(shm_id_1, (const void *)0, 0);
+               TEST_ERRNO = errno;
+       
+               if (addr != (char *)-1) {
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case EACCES:
+                       tst_resm(TPASS, "expected failure - errno = "
+                                "%d : %s", TEST_ERRNO,
+                                strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "call failed with an "
+                                "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }                       
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* check for root as process owner */
+       check_root();
+
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory segment with read and write permissions */
+       if ((shm_id_1 = shmget(shmkey, SHM_SIZE, 
+                              SHM_RW | IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "segment in setup");
+       }
+
+       /* get the userid for a non root user */
+       ltp_uid = getuserid(ltp_user);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmat/test.sh b/test/ipc/shmat/test.sh
new file mode 100644 (file)
index 0000000..da41753
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./shmat01
+./shmat02
+./shmat03
diff --git a/test/ipc/shmctl/Makefile b/test/ipc/shmctl/Makefile
new file mode 100644 (file)
index 0000000..9799fc9
--- /dev/null
@@ -0,0 +1,40 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = shmctl01 shmctl02 shmctl03 shmctl04
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+shmctl01: shmctl01.c
+shmctl02: shmctl02.c
+shmctl03: shmctl03.c
+shmctl04: shmctl04.c
diff --git a/test/ipc/shmctl/shmctl01.c b/test/ipc/shmctl/shmctl01.c
new file mode 100644 (file)
index 0000000..b308479
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmctl01.c
+ *
+ * DESCRIPTION
+ *     shmctl01 - test the IPC_STAT, IPC_SET and IPC_RMID commands as
+ *                they are used with shmctl()
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     create a shared memory segment with read and write permission
+ *     set up any test case specific conditions
+ *     call shmctl() using the TEST macro
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             call the correct test function
+ *             if the conditions are correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *       otherwise
+ *         issue a PASS message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmctl01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmctl01";
+extern int Tst_count;
+
+int shm_id_1 = -1;
+struct shmid_ds buf;
+long save_time;
+
+#define FIRST  0
+#define SECOND 1
+int stat_time;         /* set to either FIRST or SECOND for IPC_STAT tests */
+
+void *set_shared;
+
+#define N_ATTACH       4
+
+pid_t pid_arr[N_ATTACH];
+
+void sighandler(int);
+
+/*
+ * These are the various setup and check functions for the commands
+ * that we are checking.
+ */
+
+/* Setup, cleanup and check routines for IPC_STAT */
+void stat_setup(void), func_stat(void);
+void stat_cleanup(void);
+
+/* Setup and check routines for IPC_SET */
+void set_setup(void), func_set(void);
+
+/* Check routine for IPC_RMID */
+void func_rmid(void);
+
+/* Child function */
+void do_child(void);
+
+struct test_case_t {
+       int cmd;                /* the command to test */
+       void (*func_test)(void);        /* the test function */
+       void (*func_setup)(void);       /* the setup function if necessary */
+} TC[] = {
+
+       {IPC_STAT, func_stat, stat_setup},
+
+#ifndef UCLINUX
+       /* The second test is not applicable to uClinux; shared memory segments
+          are detached on exec(), so cannot be passed to uClinux children. */
+       {IPC_STAT, func_stat, stat_setup},
+#endif
+
+       {IPC_SET, func_set, set_setup},
+
+       {IPC_RMID, func_rmid, NULL}
+};
+
+int TST_TOTAL = (sizeof(TC) / sizeof(*TC));
+
+#define NEWMODE        0066
+
+#ifdef UCLINUX
+static char *argv0;
+#endif
+
+static int stat_i;     /* Shared between do_child and stat_setup */
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+       void check_functionality(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+#ifdef UCLINUX
+       argv0 = av[0];
+       maybe_run_child(do_child, "ddd", &stat_i, &stat_time, &shm_id_1);
+#endif
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* initialize stat_time */
+               stat_time = FIRST;
+
+               /*
+                * Create a shared memory segment with read and write
+                * permissions.  Do this here instead of in setup()
+                * so that looping (-i) will work correctly.
+                */
+               if ((shm_id_1 = shmget(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL |
+                               SHM_RW)) == -1) {
+                       tst_brkm(TBROK, cleanup, "couldn't create the shared"
+                                " memory segment");
+               }
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+
+                       /*
+                        * if needed, set up any required conditions by
+                        * calling the appropriate setup function
+                        */
+                       if (TC[i].func_setup != NULL) {
+                               (*TC[i].func_setup)();
+                       }
+
+                       /*
+                        * Use TEST macro to make the call
+                        */
+
+                       TEST(shmctl(shm_id_1, TC[i].cmd, &buf));
+
+                       if (TEST_RETURN == -1) {
+                               tst_resm(TFAIL, "%s call failed - errno "
+                                        "= %d : %s", TCID, TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                               continue;
+                       }
+                       if (STD_FUNCTIONAL_TEST) {
+                               (*TC[i].func_test)();
+                       } else {
+                               tst_resm(TPASS, "call succeeded");
+
+                               /* now perform command related cleanup */
+                               switch(TC[i].cmd) {
+                               case IPC_STAT:
+                                       stat_cleanup();
+                                       break;
+                               case IPC_RMID:
+                                       shm_id_1 = -1;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * set_shmat() - Attach the shared memory and return the pointer.  Use
+ *              this seperate routine to avoid code duplication in
+ *              stat_setup() below.
+ */
+void *
+set_shmat(void)
+{
+       void *rval;
+
+       /* attach the shared memory */
+       rval = shmat(shm_id_1, 0, 0);
+
+       /*
+        * if shmat() fails, the only thing we can do is 
+        * print a message to that effect.
+        */
+       if (rval == (void *)-1) {
+               tst_resm(TBROK, "shmat() failed - %s", strerror(errno));
+               cleanup();
+       }
+
+       return rval;
+}
+
+/*
+ * stat_setup() - Set up for the IPC_STAT command with shmctl().
+ *               Make things interesting by forking some children
+ *               that will either attach or inherit the shared memory.
+ */
+void
+stat_setup(void)
+{
+       void *set_shmat(void);
+       pid_t pid;
+
+       /*
+        * The first time through, let the children attach the memory.
+        * The second time through, attach the memory first and let
+        * the children inherit the memory.
+        */
+
+       if (stat_time == SECOND) {
+               /*
+                * use the global "set_shared" variable here so that
+                * it can be removed in the stat_func() routine.
+                */
+               set_shared = set_shmat();
+       }
+
+       tst_flush();
+       for (stat_i=0; stat_i<N_ATTACH; stat_i++) {
+               if ((pid = fork()) == -1) {
+                       tst_brkm(TBROK, cleanup, "could not fork");
+               }
+
+               if (pid == 0) {         /* child */
+#ifdef UCLINUX
+                       if (self_exec(argv0, "ddd", stat_i, stat_time,
+                                     shm_id_1) < 0) {
+                               tst_brkm(TBROK, cleanup, "could not self_exec");
+                       }
+#else
+                       do_child();
+#endif
+
+               } else {                /* parent */
+                       /* save the child's pid for cleanup later */
+                       pid_arr[stat_i] = pid;
+               }
+       }
+       /* sleep briefly to ensure correct execution order */
+       usleep(250000);
+}
+
+/*
+ * do_child
+ */
+void
+do_child()
+{
+       int rval;
+       void *test;
+
+       if (stat_time == FIRST) {
+               test = set_shmat();
+       } else {
+               test = set_shared;
+       }
+       
+       /* do an assignement for fun */
+       *(int *)test = stat_i;
+       
+       /* pause until we get a signal from stat_cleanup() */
+       rval = pause();
+       
+       /* now we're back - detach the memory and exit */
+       if (shmdt(test) == -1) {
+               tst_resm(TBROK, "shmdt() failed - %d", errno);
+       }
+       tst_exit();
+}
+
+/*
+ * func_stat() - check the functionality of the IPC_STAT command with shmctl()
+ *              by looking at the pid of the creator, the segement size,
+ *              the number of attaches and the mode.
+ */
+void
+func_stat()
+{
+       int fail = 0;
+       pid_t pid;
+
+       /* check perm, pid, nattach and size */
+
+       pid = getpid();
+
+       if (buf.shm_cpid != pid) {
+               tst_resm(TFAIL, "creator pid is incorrect");
+               fail = 1;
+       }
+
+       if (!fail && buf.shm_segsz != SHM_SIZE) {
+               tst_resm(TFAIL, "segment size is incorrect");
+               fail = 1;
+       }
+
+       /*
+        * The first time through, only the children attach the memory, so
+        * the attaches equal N_ATTACH + stat_time (0).  The second time
+        * through, the parent attaches the memory and the children inherit
+        * that memory so the attaches equal N_ATTACH + stat_time (1).
+        */
+       if (!fail && buf.shm_nattch != N_ATTACH + stat_time) {
+               tst_resm(TFAIL, "# of attaches is incorrect - %d",
+                        buf.shm_nattch);
+               fail = 1;
+       }
+
+       /* use MODE_MASK to make sure we are comparing the last 9 bits */
+       if (!fail && (buf.shm_perm.mode & MODE_MASK) != ((SHM_RW) & MODE_MASK)) {
+               tst_resm(TFAIL, "segment mode is incorrect");
+               fail = 1;
+       }
+
+       stat_cleanup();
+
+       /* save the change time for use in the next test */
+       save_time = buf.shm_ctime;
+
+       if (fail) {
+               return;
+       }
+
+       tst_resm(TPASS, "pid, size, # of attaches and mode are correct "
+                "- pass #%d", stat_time);
+}
+
+/*
+ * stat_cleanup() - signal the children to clean up after themselves and
+ *                 have the parent make dessert, er, um, make that remove
+ *                 the shared memory that is no longer needed.
+ */
+void
+stat_cleanup()
+{
+       int i;
+
+       /* wake up the childern so they can detach the memory and exit */
+       for (i=0; i<N_ATTACH; i++) {
+               if(kill(pid_arr[i], SIGUSR1) == -1) {
+                       tst_brkm(TBROK, cleanup, "kill failed");
+               }
+       }
+
+       /* remove the parent's shared memory the second time through */
+       if (stat_time == SECOND) {
+               if (shmdt(set_shared) == -1) {
+                       tst_resm(TINFO, "shmdt() failed");
+               }
+       }
+
+       stat_time++;
+}
+
+/*
+ * set_setup() - set up for the IPC_SET command with shmctl()
+ */
+void
+set_setup()
+{
+       /* set up a new mode for the shared memory segment */
+       buf.shm_perm.mode = SHM_RW | NEWMODE;
+
+       /* sleep for one second to get a different shm_ctime value */
+       sleep(1);
+}
+
+/*
+ * func_set() - check the functionality of the IPC_SET command with shmctl()
+ */
+void
+func_set()
+{
+       int fail = 0;
+
+       /* first stat the shared memory to get the new data */
+       if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) {
+               tst_resm(TBROK, "stat failed in func_set()");
+               return;
+       }
+
+       if ((buf.shm_perm.mode & MODE_MASK) != 
+                       ((SHM_RW | NEWMODE) & MODE_MASK)) {
+               tst_resm(TFAIL, "new mode is incorrect");
+               fail = 1;
+       }
+
+       if (!fail && save_time >= buf.shm_ctime) {
+               tst_resm(TFAIL, "change time is incorrect");
+               fail = 1;
+       }
+
+       if (fail) {
+               return;
+       }
+
+       tst_resm(TPASS, "new mode and change time are correct");
+}
+
+/*
+ * func_rmid() - check the functionality of the IPC_RMID command with shmctl()
+ */
+void
+func_rmid()
+{
+       /* Do another shmctl() - we should get EINVAL */
+       if (shmctl(shm_id_1, IPC_STAT, &buf) != -1) {
+               tst_brkm(TBROK, cleanup, "shmctl succeeded on expected fail");
+       }
+
+       if (errno != EINVAL) {
+               tst_resm(TFAIL, "returned unexpected errno %d", errno);
+       } else {
+               tst_resm(TPASS, "shared memory appears to be removed");
+       }
+
+       shm_id_1 = -1;
+}
+
+/*
+ * sighandler() - handle signals, in this case SIGUSR1 is the only one expected
+ */
+void
+sighandler(sig)
+{
+       if (sig != SIGUSR1) {
+               tst_resm(TINFO, "received unexpected signal %d", sig);
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(FORK, sighandler, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the shared memory segment */
+       rm_shm(shm_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmctl/shmctl02.c b/test/ipc/shmctl/shmctl02.c
new file mode 100644 (file)
index 0000000..0801a93
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmctl02.c
+ *
+ * DESCRIPTION
+ *     shmctl02 - check for EACCES, EFAULT and EINVAL errors
+ *
+ * ALGORITHM
+ *     create a shared memory segment without read or write permissions
+ *     create a shared memory segment with read & write permissions
+ *     loop if that option was specified
+ *       call shmctl() using five different invalid cases
+ *       check the errno value
+ *         issue a PASS message if we get EACCES, EFAULT or EINVAL
+ *       otherwise, the tests fails
+ *         issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmctl02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+#include <pwd.h>
+
+char *TCID = "shmctl02";
+extern int Tst_count;
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+int exp_enos[] = {EPERM, EACCES, EFAULT, EINVAL, 0};  /* 0 terminated list  */
+                                                     /* of expected errnos */
+int shm_id_1 = -1;
+int shm_id_2 = -1;
+int shm_id_3 = -1;
+
+struct shmid_ds buf;
+
+struct test_case_t {
+       int *shmid;
+       int cmd;
+       struct shmid_ds *sbuf;
+       int error;
+} TC[] = {
+       /* EACCES - segment has no read or write permissions */
+       {&shm_id_1, IPC_STAT, &buf, EACCES},
+
+       /* EFAULT - IPC_SET & buf isn't valid */
+       {&shm_id_2, IPC_SET, (struct shmid_ds *)-1, EFAULT},
+
+       /* EFAULT - IPC_STAT & buf isn't valid */
+       {&shm_id_2, IPC_STAT, (struct shmid_ds *)-1, EFAULT},
+
+       /* EINVAL - the shmid is not valid */
+       {&shm_id_3, IPC_STAT, &buf, EINVAL},
+
+       /* EINVAL - the command is not valid */
+       {&shm_id_2, -1, &buf, EINVAL},
+
+};
+
+int TST_TOTAL = (sizeof(TC) / sizeof(*TC));
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+                       /*
+                        * use the TEST() macro to make the call
+                        */
+       
+                       TEST(shmctl(*(TC[i].shmid), TC[i].cmd, TC[i].sbuf));
+       
+                       if ((TEST_RETURN != -1)&&(i < 5)) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               if (i >= 5)
+                                       tst_resm(TCONF,"shmctl() did not fail for non-root user."
+                                                 "This may be okay for your distribution.");
+                               else
+                                       tst_resm(TFAIL, "call failed with an "
+                                                "unexpected error - %d : %s",
+                                               TEST_ERRNO, strerror(TEST_ERRNO));
+                       }                       
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+         ltpuser = getpwnam(nobody_uid);
+         if (seteuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("seteuid");
+         }
+
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory segment without read or write permissions */
+       if ((shm_id_1 = shmget(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create shared memory "
+                        "segment #1 in setup()");
+       }
+
+       /* create a shared memory segment with read and write permissions */
+       if ((shm_id_2 = shmget(shmkey + 1, SHM_SIZE, IPC_CREAT | IPC_EXCL |
+            SHM_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create shared memory "
+                        "segment #2 in setup()");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if they exist, remove the shared memory resources */
+       rm_shm(shm_id_1);
+       rm_shm(shm_id_2);
+
+       if (seteuid(0) == -1) {
+               tst_resm(TINFO, "setuid failed to "
+                               "to set the effective uid to %d",
+                               ltpuser->pw_uid);
+               perror("seteuid");
+       }
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmctl/shmctl03.c b/test/ipc/shmctl/shmctl03.c
new file mode 100644 (file)
index 0000000..b7ceeae
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmctl03.c
+ *
+ * DESCRIPTION
+ *     shmctl03 - check for EACCES, and EPERM errors
+ *
+ * ALGORITHM
+ *     create a shared memory segment with root only read & write permissions
+ *     fork a child process
+ *     if child
+ *       set the ID of the child process to that of "ltpuser1"
+ *       call do_child()
+ *       loop if that option was specified
+ *         call shmctl() using three different invalid cases
+ *         check the errno value
+ *           issue a PASS message if we get EACCES or EPERM
+ *         otherwise, the tests fails
+ *           issue a FAIL message
+ *       call cleanup
+ *     if parent
+ *       wait for child to exit
+ *       remove the shared memory segment
+ *
+ * USAGE:  <for command-line>
+ *  shmctl03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     test must be run as root
+ */
+
+#include "ipcshm.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+
+char *TCID = "shmctl03";
+extern int Tst_count;
+
+int exp_enos[] = {EACCES, EPERM, 0};   /* 0 terminated list of */
+                                       /* expected errnos      */
+int shm_id_1 = -1;
+
+uid_t ltp_uid;
+char *ltp_user = "nobody";
+
+struct shmid_ds buf;
+
+struct test_case_t {
+       int *shmid;
+       int cmd;
+       struct shmid_ds *sbuf;
+       int error;
+} TC[] = {
+       /* EACCES - child has no read permission for segment */
+       {&shm_id_1, IPC_STAT, &buf, EACCES},
+
+       /* EPERM - IPC_SET - child doesn't have permission to change segment */
+       {&shm_id_1, IPC_SET, &buf, EPERM},
+
+       /* EPERM - IPC_RMID - child can not remove the segment */
+       {&shm_id_1, IPC_RMID, &buf, EPERM},
+};
+
+int TST_TOTAL = (sizeof(TC) / sizeof(*TC));
+
+int main(int ac, char **av)
+{
+       char *msg;                      /* message returned from parse_opts */
+       int pid;
+       void do_child(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       if ((pid = FORK_OR_VFORK()) == -1) {
+               tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (pid == 0) {         /* child */
+               /* set  the user ID of the child to the non root user */
+               if (setuid(ltp_uid) == -1) {
+                       tst_resm(TBROK, "setuid() failed");
+                       exit(1);
+               }
+
+               do_child();
+       } else {
+               /* wait for the child to return */
+               if (waitpid(pid, NULL, 0) == -1) {
+                       tst_brkm(TBROK, cleanup, "waitpid failed");
+               }
+
+               /* if it exists, remove the shared memory resource */
+               rm_shm(shm_id_1);
+
+               /* Remove the temporary directory */
+               tst_rmdir();
+       }
+       
+       cleanup ();
+       return(0);
+}
+
+/*
+ * do_child - make the call as the child process
+ */
+void
+do_child(void)
+{
+       int i, lc;
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+                       /*
+                        * use the TEST() macro to make the call
+                        */
+       
+                       TEST(shmctl(*(TC[i].shmid), TC[i].cmd, TC[i].sbuf));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }                       
+               }
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* check for root as process owner */
+       check_root();
+
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory segment with read and write permissions */
+       if ((shm_id_1 = shmget(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL |
+            SHM_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create shared memory "
+                        "segment in setup()");
+       }
+
+       /* get the userid for a non root user */
+       ltp_uid = getuserid(ltp_user);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmctl/shmctl04.c b/test/ipc/shmctl/shmctl04.c
new file mode 100644 (file)
index 0000000..efeaf6f
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmctl04.c
+ *
+ * DESCRIPTION
+ *     shmctl04 - test the SHM_INFO command 
+ *                they are used with shmctl() in ipcs
+ *
+ * USAGE:  <for command-line>
+ *  shmctl04 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     09/2002 - Written by Mingming Cao
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmctl04";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+struct shm_info shm_info;
+int max_ids;
+
+/*
+ * These are the various setup and check functions for the commands
+ * that we are checking.
+ */
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+               TEST(shmctl(0, SHM_INFO, (struct shmid_ds *)&shm_info));
+               
+               if (TEST_RETURN != -1) {
+                       tst_resm(TPASS, "SHM_INFO call succeeded");
+                       continue;
+               }
+
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               tst_resm(TFAIL, "SHM_INFO call failed with an unexpected error"
+                       " - %d : %s",TEST_ERRNO, strerror(TEST_ERRNO));
+
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmctl/test.sh b/test/ipc/shmctl/test.sh
new file mode 100644 (file)
index 0000000..b18d146
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+./shmctl01
+./shmctl02
+./shmctl03
+./shmctl04
diff --git a/test/ipc/shmdt/Makefile b/test/ipc/shmdt/Makefile
new file mode 100644 (file)
index 0000000..34b4a8b
--- /dev/null
@@ -0,0 +1,38 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = shmdt01 shmdt02
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+shmdt01: shmdt01.c
+shmdt02: shmdt02.c
diff --git a/test/ipc/shmdt/shmdt01.c b/test/ipc/shmdt/shmdt01.c
new file mode 100644 (file)
index 0000000..1fd30f8
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmdt01.c
+ *
+ * DESCRIPTION
+ *     shmdt01 - check that shared memory is detached correctly
+ *
+ * ALGORITHM
+ *     create a shared memory resource of size sizeof(int)
+ *     attach it to the current process and give it a value
+ *     call shmdt() using the TEST macro       
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             attempt to write a value to the shared memory address
+ *             this should generate a SIGSEGV which will be caught in
+ *                 the signal handler
+ *             if correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmdt01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include <setjmp.h>
+#include "ipcshm.h"
+
+char *TCID = "shmdt01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+void sighandler(int);
+struct shmid_ds buf;
+
+int shm_id_1 = -1;
+int *shared;           /* variable to use for shared memory attach */
+int new;
+int pass = 0;
+sigjmp_buf env;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       void check_functionality(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Use TEST macro to make the shmdt() call
+                */
+
+               TEST(shmdt((const void *)shared));
+
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d : %s",
+                                TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+               } else {
+                       if (STD_FUNCTIONAL_TEST) {
+                               check_functionality();
+                       } else {
+                               tst_resm(TPASS, "call succeeded");
+                       }
+               }
+
+               /* reattach the shared memory segment in case we are looping */
+               shared = (int *)shmat(shm_id_1, 0, 0);
+
+               if (*shared == -1) {
+                       tst_brkm(TBROK, cleanup, "memory reattach failed");
+               }
+
+               /* also reset pass */
+               pass = 0;
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * check_functionality() - make sure the memory is detached correctly
+ */
+void
+check_functionality(void)
+{
+       /* stat the shared memory segment */
+       if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) {
+               tst_resm(TINFO, "error = %d : %s", errno, strerror(errno));
+               tst_brkm(TBROK, cleanup, "could not stat in signal handler");
+       }
+
+       if (buf.shm_nattch != 0) {
+               tst_resm(TFAIL, "# of attaches is incorrect");
+               return;
+       }
+
+       /*
+        * Try writing to the shared memory.  This should generate a
+        * SIGSEGV which will be caught below.
+        *
+        * This is wrapped by the sigsetjmp() call that will take care of
+        * restoring the program's context in an elegant way in conjunction
+        * with the call to siglongjmp() in the signal handler.
+        *
+        * An attempt to do the assignment without using the sigsetjmp()
+        * and siglongjmp() calls will result in an infinite loop.  Program 
+        * control is returned to the assignment statement after the execution
+        * of the signal handler and another SIGSEGV will be generated.
+        */
+
+       if (sigsetjmp(env, 1) == 0) {
+               *shared = 2;
+       }
+
+       if (pass) {
+               tst_resm(TPASS, "shared memory detached correctly");
+       } else {
+               tst_resm(TFAIL, "shared memory was not detached correctly");
+       }
+}
+/*
+ * sighandler()
+ */
+void
+sighandler(sig)
+{
+       /* if we have received a SIGSEGV, we are almost done */
+       if (sig == SIGSEGV) {
+               /* set the global variable and jump back */
+               pass = 1;
+               siglongjmp(env, 1);
+       } else {
+               tst_brkm(TBROK, cleanup, "received an unexpected signal");
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+
+       tst_sig(NOFORK, sighandler, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory resource with read and write permissions */
+       if ((shm_id_1 = shmget(shmkey, INT_SIZE, SHM_RW | IPC_CREAT |
+            IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "resource in setup()");
+       }
+
+       /* attach the shared memory segment */
+       shared = (int *)shmat(shm_id_1, 0, 0);
+
+       if (*shared == -1) {
+               tst_brkm(TBROK, cleanup, "Couldn't attach shared memory");
+       }
+
+       /* give a value to the shared memory integer */
+       *shared = 4;
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, delete the shared memory resource */
+       rm_shm(shm_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmdt/shmdt02.c b/test/ipc/shmdt/shmdt02.c
new file mode 100644 (file)
index 0000000..5741d5f
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmdt02.c
+ *
+ * DESCRIPTION
+ *     shmdt02 - check for EINVAL error
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *       call shmdt() using an invalid shared memory address
+ *       check the errno value
+ *         issue a PASS message if we get EINVAL
+ *       otherwise, the tests fails
+ *         issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmdt02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmdt02";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EINVAL, 0};  /* 0 terminated list of expected errnos */
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int unshared;                   /* a local variable to use to produce */                                        /* the error in the shmdt() call */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * make the call using the TEST() macro - attempt to 
+                * remove an invalid shared memory address
+                */
+       
+               TEST(shmdt(&unshared));
+       
+               if (TEST_RETURN != -1) {
+                       tst_brkm(TFAIL, cleanup, "call succeeded unexpectedly");
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case EINVAL:
+                       tst_resm(TPASS, "expected failure - errno = %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "call failed with an unexpected error "
+                                "- %d : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+                       
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmdt/test.sh b/test/ipc/shmdt/test.sh
new file mode 100644 (file)
index 0000000..1314339
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+./shmdt01
+./shmdt02
diff --git a/test/ipc/shmget/Makefile b/test/ipc/shmget/Makefile
new file mode 100644 (file)
index 0000000..99d6e90
--- /dev/null
@@ -0,0 +1,40 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = shmget01 shmget02 shmget04 shmget05
+
+all: $(PROG)
+
+$(PROG): tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o libipc.o tst_sig.o parse_opts.o tst_tmpdir.o rmobj.o
+
+rmobj.o: ../lib/rmobj.c
+       $(CC) $(CFLAGS) -c -o rmobj.o ../lib/rmobj.c
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+tst_sig.o: ../lib/tst_sig.c
+       $(CC) $(CFLAGS) -c -o tst_sig.o ../lib/tst_sig.c
+
+tst_tmpdir.o: ../lib/tst_tmpdir.c
+       $(CC) $(CFLAGS) -c -o tst_tmpdir.o ../lib/tst_tmpdir.c
+
+parse_opts.o: ../lib/parse_opts.c
+       $(CC) $(CFLAGS) -c -o parse_opts.o ../lib/parse_opts.c
+
+libipc.o: ../lib/libipc.c
+       $(CC) $(CFLAGS) -c -o libipc.o ../lib/libipc.c
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+test:
+       sh ./test.sh
+
+shmget01: shmget01.c
+shmget02: shmget02.c
+shmget04: shmget04.c
+shmget05: shmget05.c
diff --git a/test/ipc/shmget/shmget01.c b/test/ipc/shmget/shmget01.c
new file mode 100644 (file)
index 0000000..93fefd3
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmget01.c
+ *
+ * DESCRIPTION
+ *     shmget01 - test that shmget() correctly creates a shared memory segment
+ *
+ * ALGORITHM
+ *     loop if that option was specified
+ *     use the TEST() macro to call shmget()
+ *     check the return code
+ *       if failure, issue a FAIL message.
+ *     otherwise,
+ *       if doing functionality testing
+ *             stat the shared memory resource
+ *             check the size, creator pid and mode
+ *             if correct,
+ *                     issue a PASS message
+ *             otherwise
+ *                     issue a FAIL message
+ *       else issue a PASS message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmget01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -f   : Turn off functionality Testing.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmget01";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int shm_id_1 = -1;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       struct shmid_ds buf;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Use TEST macro to make the call
+                */
+       
+               TEST(shmget(shmkey, SHM_SIZE, (IPC_CREAT | IPC_EXCL | SHM_RW)));
+       
+               if (TEST_RETURN == -1) {
+                       tst_resm(TFAIL, "%s call failed - errno = %d : %s",
+                                TCID, TEST_ERRNO, strerror(TEST_ERRNO));
+               } else {
+                       shm_id_1 = TEST_RETURN;
+                       if (STD_FUNCTIONAL_TEST) {
+                               /* do a STAT and check some info */
+                               if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) {
+                                       tst_resm(TBROK, "shmctl failed in "
+                                                "functional test");
+                                       continue;
+                               }
+                               /* check the seqment size */
+                               if (buf.shm_segsz != SHM_SIZE) {
+                                       tst_resm(TFAIL, "seqment size is not "
+                                                "correct");
+                                       continue;
+                               }
+                               /* check the pid of the creator */
+                               if (buf.shm_cpid != getpid()) {
+                                       tst_resm(TFAIL, "creator pid is not "
+                                                "correct");
+                                       continue;
+                               }
+                               /*
+                                * check the mode of the seqment
+                                * mask out all but the lower 9 bits
+                                */
+                               if ((buf.shm_perm.mode & MODE_MASK) !=
+                                   ((SHM_RW) & MODE_MASK)) {
+                                       tst_resm(TFAIL, "segment mode is not "
+                                                "correct");
+                                       continue;
+                               }
+                               /* if we get here, everything looks good */
+                               tst_resm(TPASS, "size, pid & mode are correct");
+                       } else {
+                               tst_resm(TPASS, "call succeeded");
+                       }
+               }
+
+               /*
+                * clean up things in case we are looping
+                */
+               if (shmctl(shm_id_1, IPC_RMID, NULL) == -1) {
+                       tst_resm(TBROK, "couldn't remove shared memory");
+               } else {
+                       shm_id_1 = -1;
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+        return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the shared memory resource */
+       rm_shm(shm_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmget/shmget02.c b/test/ipc/shmget/shmget02.c
new file mode 100644 (file)
index 0000000..7792051
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmget02.c
+ *
+ * DESCRIPTION
+ *     shmget02 - check for ENOENT, EEXIST and EINVAL errors
+ *
+ * ALGORITHM
+ *     create a shared memory segment with read & write permissions
+ *     loop if that option was specified
+ *       call shmget() using five different invalid cases
+ *       check the errno value
+ *         issue a PASS message if we get ENOENT, EEXIST or EINVAL
+ *       otherwise, the tests fails
+ *         issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmget02 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+
+#include "ipcshm.h"
+
+char *TCID = "shmget02";
+int TST_TOTAL = 5;
+extern int Tst_count;
+
+int exp_enos[] = {ENOENT, EEXIST, EINVAL, 0};  /* 0 terminated list of */
+                                               /* expected errnos      */
+
+int shm_id_1 = -1;
+int shm_nonexisting_key = -1;
+int shmkey2;
+
+struct test_case_t {
+       int *skey;
+       int size;
+       int flags;
+       int error;
+} TC[] = {
+       /* EINVAL - size is 0 */
+       {&shmkey2, 0, IPC_CREAT | IPC_EXCL | SHM_RW, EINVAL},
+
+       /* EINVAL - size is negative */
+       {&shmkey2, -1, IPC_CREAT | IPC_EXCL | SHM_RW, EINVAL},
+       
+       /* EINVAL - size is larger than created segment */
+       {(int *)&shmkey, SHM_SIZE * 2, SHM_RW, EINVAL},
+       
+       /* EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given */
+       {(int *)&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL | SHM_RW, EEXIST},
+       
+       /* ENOENT - no segment exists for the key and IPC_CREAT is not given */
+       /* use shm_id_2 (-1) as the key */
+       {&shm_nonexisting_key, SHM_SIZE, SHM_RW, ENOENT}
+};
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+       int i;
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /* loop through the test cases */
+               for (i=0; i<TST_TOTAL; i++) {
+                       /*
+                        * Look for a failure ...
+                        */
+       
+                       TEST(shmget(*(TC[i].skey), TC[i].size, TC[i].flags));
+       
+                       if (TEST_RETURN != -1) {
+                               tst_resm(TFAIL, "call succeeded unexpectedly");
+                               continue;
+                       }
+       
+                       TEST_ERROR_LOG(TEST_ERRNO);
+
+                       if (TEST_ERRNO == TC[i].error) {
+                               tst_resm(TPASS, "expected failure - errno = "
+                                        "%d : %s", TEST_ERRNO,
+                                        strerror(TEST_ERRNO));
+                       } else {
+                               tst_resm(TFAIL, "call failed with an "
+                                        "unexpected error - %d : %s",
+                                        TEST_ERRNO, strerror(TEST_ERRNO));
+                       }                       
+               }
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       shmkey2 = shmkey + 1;
+
+       if ((shm_id_1 = shmget(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL |
+            SHM_RW)) == -1) {
+               tst_brkm(TBROK, cleanup, "couldn't create shared memory "
+                        "segment in setup()");
+       }
+
+       /* Make sure shm_nonexisting_key is a nonexisting key */
+       while(1) {
+               while(-1 != shmget(shm_nonexisting_key,1,SHM_RD)) {
+                       shm_nonexisting_key--;
+               }
+               if(errno == ENOENT)
+                       break;
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the shared memory resource */
+       rm_shm(shm_id_1);
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmget/shmget04.c b/test/ipc/shmget/shmget04.c
new file mode 100644 (file)
index 0000000..d42287c
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmget04.c
+ *
+ * DESCRIPTION
+ *     shmget04 - test for EACCES error
+ *
+ * ALGORITHM
+ *     create a shared memory segment without read or write permissions
+ *     loop if that option was specified
+ *       call shmget() with SHM_RW flag using TEST() macro
+ *       check the errno value
+ *         issue a PASS message if we get EACCES
+ *       otherwise, the tests fails
+ *         issue a FAIL message
+ *     call cleanup
+ *
+ * USAGE:  <for command-line>
+ *  shmget04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     none
+ */
+#include <pwd.h>
+#include "ipcshm.h"
+
+char *TCID = "shmget04";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EACCES, 0};  /* 0 terminated list of expected errnos */
+
+char nobody_uid[] = "nobody";
+struct passwd *ltpuser;
+
+int shm_id_1 = -1;
+
+int main(int ac, char **av)
+{
+       int lc;                         /* loop counter */
+       char *msg;                      /* message returned from parse_opts */
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * use the TEST() macro to make the call
+                */
+       
+               TEST(shmget(shmkey, SHM_SIZE, SHM_RW));
+       
+               if (TEST_RETURN != -1) {
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case EACCES:
+                       tst_resm(TPASS, "expected failure - errno = "
+                                "%d : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "call failed with an "
+                                "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }                       
+       }
+
+       cleanup();
+
+       /*NOTREACHED*/
+       return(0);
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* capture signals */
+       tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /* Switch to nobody user for correct error code collection */
+        if (geteuid() != 0) {
+                tst_brkm(TBROK, tst_exit, "Test must be run as root");
+        }
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+        ltpuser = getpwnam(nobody_uid);
+        if (seteuid(ltpuser->pw_uid) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to %d",
+                         ltpuser->pw_uid);
+                perror("seteuid");
+        }
+
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory segment without read or access permissions */
+       if ((shm_id_1 = shmget(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "segment in setup");
+       }
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /* if it exists, remove the shared memory resource */
+       rm_shm(shm_id_1);
+
+        if (seteuid(0) == -1) {
+                tst_resm(TINFO, "setuid failed to "
+                         "to set the effective uid to root");
+                perror("seteuid");
+        }
+
+       /* Remove the temporary directory */
+       tst_rmdir();
+
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmget/shmget05.c b/test/ipc/shmget/shmget05.c
new file mode 100644 (file)
index 0000000..051208f
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2001
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NAME
+ *     shmget05.c
+ *
+ * DESCRIPTION
+ *     shmget05 - test for EACCES error
+ *
+ * ALGORITHM
+ *     create a shared memory segment with root only read & write permissions
+ *     fork a child process
+ *     if child
+ *       set the ID of the child process to that of "nobody"
+ *       loop if that option was specified
+ *         call shmget() using the TEST() macro
+ *         check the errno value
+ *           issue a PASS message if we get EACCES
+ *         otherwise, the tests fails
+ *           issue a FAIL message
+ *       call cleanup
+ *     if parent
+ *       wait for child to exit
+ *       remove the shared memory segment
+ *
+ * USAGE:  <for command-line>
+ *  shmget05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
+ *     where,  -c n : Run n copies concurrently.
+ *             -e   : Turn on errno logging.
+ *            -i n : Execute test n times.
+ *            -I x : Execute test for x seconds.
+ *            -P x : Pause for x seconds between iterations.
+ *            -t   : Turn on syscall timing.
+ *
+ * HISTORY
+ *     03/2001 - Written by Wayne Boyer
+ *
+ * RESTRICTIONS
+ *     test must be run at root
+ */
+
+#include "ipcshm.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+
+char *TCID = "shmget05";
+int TST_TOTAL = 1;
+extern int Tst_count;
+
+int exp_enos[] = {EACCES, 0};  /* 0 terminated list of expected errnos */
+
+int shm_id_1 = -1;
+
+uid_t ltp_uid;
+char *ltp_user = "nobody";
+
+int main(int ac, char **av)
+{
+       char *msg;                      /* message returned from parse_opts */
+       int pid;
+       void do_child(void);
+
+       /* parse standard options */
+       if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
+               tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+       }
+
+       setup();                        /* global setup */
+
+       if ((pid = FORK_OR_VFORK()) == -1) {
+               tst_brkm(TBROK, cleanup, "could not fork");
+       }
+
+       if (pid == 0) {         /* child */
+               /* set the user ID of the child to the non root user */
+               if (setuid(ltp_uid) == -1) {
+                       tst_resm(TBROK, "setuid() failed");
+                       exit(1);
+               }
+
+               do_child();
+
+               cleanup();
+
+               /*NOTREACHED*/
+       } else {                /* parent */
+               /* wait for the child to return */
+               if (waitpid(pid, NULL, 0) == -1) {
+                       tst_brkm(TBROK, cleanup, "waitpid failed");
+               }
+
+               /* if it exists, remove the shared memory resource */
+               rm_shm(shm_id_1);
+
+               /* Remove the temporary directory */
+               tst_rmdir();
+       }
+       return(0);
+}
+
+/*
+ * do_child - make the TEST call as the child process
+ */
+void
+do_child(void)
+{
+       int lc;
+
+       /* The following loop checks looping state if -i option given */
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               /* reset Tst_count in case we are looping */
+               Tst_count = 0;
+
+               /*
+                * Look for a failure ...
+                */
+       
+               TEST(shmget(shmkey, SHM_SIZE, SHM_RW));
+       
+               if (TEST_RETURN != -1) {
+                       tst_resm(TFAIL, "call succeeded when error expected");
+                       continue;
+               }
+       
+               TEST_ERROR_LOG(TEST_ERRNO);
+
+               switch(TEST_ERRNO) {
+               case EACCES:
+                       tst_resm(TPASS, "expected failure - errno = "
+                                "%d : %s", TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               default:
+                       tst_resm(TFAIL, "call failed with an "
+                                "unexpected error - %d : %s",
+                                TEST_ERRNO, strerror(TEST_ERRNO));
+                       break;
+               }                       
+       }
+}
+
+/*
+ * setup() - performs all the ONE TIME setup for this test.
+ */
+void
+setup(void)
+{
+       /* check for root as process owner */
+       check_root();
+
+       /* capture signals */
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+
+       /* Set up the expected error numbers for -e option */
+       TEST_EXP_ENOS(exp_enos);
+
+       /* Pause if that option was specified */
+       TEST_PAUSE;
+
+       /*
+        * Create a temporary directory and cd into it.
+        * This helps to ensure that a unique msgkey is created.
+        * See ../lib/libipc.c for more information.
+        */
+       tst_tmpdir();
+
+       /* get an IPC resource key */
+       shmkey = getipckey();
+
+       /* create a shared memory segment with read and write permissions */
+       if ((shm_id_1 = shmget(shmkey, SHM_SIZE, 
+                              SHM_RW | IPC_CREAT | IPC_EXCL)) == -1) {
+               tst_brkm(TBROK, cleanup, "Failed to create shared memory "
+                        "segment in setup");
+       }
+
+       /* get the userid for a non root user */
+       ltp_uid = getuserid(ltp_user);
+}
+
+/*
+ * cleanup() - performs all the ONE TIME cleanup for this test at completion
+ *            or premature exit.
+ */
+void
+cleanup(void)
+{
+       /*
+        * print timing stats if that option was specified.
+        * print errno log if that option was specified.
+        */
+       TEST_CLEANUP;
+
+       /* exit with return code appropriate for results */
+       tst_exit();
+}
+
diff --git a/test/ipc/shmget/test.sh b/test/ipc/shmget/test.sh
new file mode 100644 (file)
index 0000000..58719be
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+./shmget01
+./shmget02
+./shmget04
+./shmget05
diff --git a/test/ipc/shmt/Makefile b/test/ipc/shmt/Makefile
new file mode 100644 (file)
index 0000000..e92d06c
--- /dev/null
@@ -0,0 +1,31 @@
+# Makefile for the tests
+
+CC = exec cc
+CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE -I../lib/
+
+PROG = shmt02 shmt03 shmt04 shmt05 shmt06 \
+       shmt07 shmt08 shmt10 shmt01
+
+all: $(PROG)
+
+$(PROG): tst_res.o
+       $(CC) $(CFLAGS) -o $@ $@.c tst_res.o
+
+tst_res.o: ../lib/tst_res.c
+       $(CC) $(CFLAGS) -c -o tst_res.o ../lib/tst_res.c
+
+test:
+       sh testshm.sh
+
+clean:
+       /usr/bin/rm -f *.o $(PROG)
+
+shmt01: shmt01.c
+shmt02: shmt02.c
+shmt03: shmt03.c
+shmt04: shmt04.c
+shmt05: shmt05.c
+shmt06: shmt06.c
+shmt07: shmt07.c
+shmt08: shmt08.c
+shmt10: shmt10.c
diff --git a/test/ipc/shmt/shmt01.c b/test/ipc/shmt/shmt01.c
new file mode 100644 (file)
index 0000000..4264b58
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * NAME
+ *              shmt01
+ *
+ * CALLS
+ *              shmat(2) shmget(2) shmdt(2)
+ *
+ * ALGORITHM
+ * Create and attach a shared memory segment, write to it
+ * and then detach the shared memroy twice, the second one will FAIL.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/utsname.h>
+#include <errno.h>
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+char *TCID="shmt01";            /* Test program identifier.    */
+int TST_TOTAL=4;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+
+/**************/
+
+#define K_1 1024
+
+int rm_shm(int);
+
+int main(void)
+{
+                register int            shmid;
+                char                            *cp;
+                key_t                           key;
+                int r;
+
+                errno = 0;
+                key = (key_t)getpid() ;
+
+/*----------------------------------------------------------------*/
+
+
+                if ((shmid = shmget(key, 16*K_1, IPC_CREAT|0666)) < 0 ) {
+                                perror("shmget");
+                                tst_resm(TFAIL, "shmget Failed: shmid = %d, errno = %d\n",
+                                shmid, errno) ;
+                                tst_exit() ;
+                }
+
+                tst_resm(TPASS, "shmget") ;
+
+/*----------------------------------------------------------------*/
+
+
+                /* are we doing with ia64 or arm_arch_4t arch */
+#if defined (__ia64__) || defined (__ARM_ARCH_4T__)
+                cp = (char *) shmat(shmid, (void *)NULL, 0);
+#else          
+                cp = (char *) shmat(shmid, (void *)0x80000, 0);
+#endif
+                if (cp == (char *)-1) {
+                                perror("shmat");
+                                tst_resm(TFAIL, "shmat Failed: shmid = %d, errno = %d\n",
+                                shmid, errno) ;
+                                rm_shm(shmid) ;
+                                tst_exit() ;            
+                }
+
+                *cp     = '1';
+                *(cp+1) = '2';
+
+                tst_resm(TPASS, "shmat") ;
+
+/*----------------------------------------------------------------*/
+
+                r = shmdt(cp);
+                if (r  < 0) {
+                        perror("shmdt");
+                        tst_resm(TFAIL, "shmdt Failed: shmid = %d, errno = %d\n",
+                                        shmid, errno);
+                        rm_shm(shmid);
+                        tst_exit();
+                }
+
+                tst_resm(TPASS, "shmdt first time.");
+
+                r = shmdt(cp);
+                if (r == 0) {
+                        perror("shmdt");
+                        tst_resm(TFAIL, "shmdt Failed: shmid = %d, errno = %d\n",
+                                        shmid, errno);
+                        rm_shm(shmid);
+                        tst_exit();
+                }
+
+                rm_shm(shmid) ;
+
+                tst_resm(TPASS, "shmdt second time.");
+
+/*------------------------------------------------------------------*/
+
+                tst_exit() ; 
+
+/*-------------------- THIS LINE IS NOT REACHED -------------------*/
+                return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+                if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                                perror("shmctl");
+                                tst_resm(TFAIL, 
+                                "shmctl Failed to remove: shmid = %d, errno = %d\n", 
+                                shmid, errno) ;
+                                tst_exit();
+                }
+                return(0);
+}
+
diff --git a/test/ipc/shmt/shmt02.c b/test/ipc/shmt/shmt02.c
new file mode 100644 (file)
index 0000000..836d16d
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002           Port to LTP             robbiew@us.ibm.com */
+/* 06/30/2001           Port to Linux           nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *              shmt02
+ *
+ * CALLS
+ *              shmctl(2) shmget(2)
+ *
+ * ALGORITHM
+ * Create and attach a shared memory segment, write to it
+ * and then remove it.           Verify that the shared memory segment
+ * is accessible as long as the process is still alive.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/utsname.h>
+#include <errno.h>
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+char *TCID="shmt02";            /* Test program identifier.    */
+int TST_TOTAL=3;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+
+
+/**************/
+
+#define K_1 1024
+
+int rm_shm(int);
+
+int main(void)
+{
+                register int            shmid;
+                char                            *cp;
+                key_t                           key;
+
+                errno = 0;
+                key = (key_t)getpid() ;
+
+/*----------------------------------------------------------------*/
+
+
+                if ((shmid = shmget(key, 16*K_1, IPC_CREAT|0666)) < 0 ) {
+                                perror("shmget");
+                                tst_resm(TFAIL, "shmget Failed: shmid = %d, errno = %d\n",
+                                shmid, errno) ;
+                                tst_exit() ;
+                }
+
+                tst_resm(TPASS, "shmget") ;
+
+/*----------------------------------------------------------------*/
+
+
+                /* are we doing with ia64 or arm_arch_4t arch */
+#if defined (__ia64__) || defined (__ARM_ARCH_4T__)
+                cp = (char *) shmat(shmid, (void *)NULL, 0);
+#else          
+                cp = (char *) shmat(shmid, (void *)0x80000, 0);
+#endif
+                if (cp == (char *)-1) {
+                                perror("shmat");
+                                tst_resm(TFAIL, "shmat Failed: shmid = %d, errno = %d\n",
+                                shmid, errno) ;
+                                rm_shm(shmid) ;
+                                tst_exit() ;            
+                }
+
+                *cp     = '1';
+                *(cp+1) = '2';
+
+                tst_resm(TPASS, "shmat") ;
+
+/*----------------------------------------------------------------*/
+
+
+                rm_shm(shmid) ;
+
+                if ( *cp != '1' || *(cp+1) != '2' ) {
+                                tst_resm(TFAIL, 
+                                "Error in shared memory contents: shmid = %d\n",
+                                shmid);
+                }
+                
+                tst_resm(TPASS, "Correct shared memory contents") ;
+
+/*------------------------------------------------------------------*/
+
+                tst_exit() ; 
+
+/*-------------------- THIS LINE IS NOT REACHED -------------------*/
+                return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+                if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                                perror("shmctl");
+                                tst_resm(TFAIL, 
+                                "shmctl Failed to remove: shmid = %d, errno = %d\n", 
+                                shmid, errno) ;
+                                tst_exit();
+                }
+                return(0);
+}
+
diff --git a/test/ipc/shmt/shmt03.c b/test/ipc/shmt/shmt03.c
new file mode 100644 (file)
index 0000000..d3e5564
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001  Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *     shmt3
+ *
+ * CALLS
+ *     shmctl(2) shmget(2) shmat(2)
+ *
+ * ALGORITHM
+ * Create one shared memory segment and attach it twice to the same process, 
+ * at an address that is chosen by the system. After the first attach has
+ * completed, write to it and then do the second attach. 
+ * Verify that the doubly attached segment contains the same data.
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+char *TCID="shmt03";            /* Test program identifier.    */
+int TST_TOTAL=4;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+#define                K_1             1024
+#define        SUCCESSFUL       1
+
+int    first_attach,
+       second_attach;
+int    rm_shm(int);
+
+int main(void)
+{
+       char *cp1, *cp2;
+       int shmid;
+       key_t key ; 
+
+
+       key = (key_t) getpid() ;
+       errno = 0 ;
+
+/*------------------------------------------------------------*/
+
+
+       if ((shmid = shmget(key, 16*K_1, IPC_CREAT|0666)) < 0) {
+               perror("shmget");
+               tst_resm(TFAIL, "shmget Failed: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+               tst_exit() ;
+       }
+
+       tst_resm(TPASS,"shmget");
+
+/*------------------------------------------------------------*/
+
+
+       if ((cp1 = (char *)shmat(shmid, (void *)0, 0)) == (char *)-1) {
+               perror("shmat");
+               tst_resm(TFAIL, "shmat Failed: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+       } else {
+               *cp1 = '1' ;
+               *(cp1+5*K_1) = '2' ;
+               first_attach = SUCCESSFUL ;
+       }
+
+       tst_resm(TPASS,"1st shmat");
+
+/*------------------------------------------------------------*/
+
+
+       if ((cp2 = (char *)shmat(shmid, (void *)0, 0)) == (char *)-1) {
+               perror("shmat");
+               tst_resm(TFAIL, "shmat Failed: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+       } 
+       else { 
+               second_attach = SUCCESSFUL  ;
+               if ( (*cp2 != '1' || *(cp2+5*K_1) != '2') &&
+                                     first_attach == SUCCESSFUL ) {
+                       tst_resm(TFAIL, 
+                       "Error: Shared memory contents\n") ;
+               }
+       }
+
+       tst_resm(TPASS,"2nd shmat");    
+
+/*---------------------------------------------------------------*/
+
+
+       rm_shm(shmid) ;
+
+       if ( first_attach  && second_attach ) {
+               if ( *cp2 != '1' || *(cp2+5*K_1) != '2' ||
+                    *cp1 != '1' || *(cp1+5*K_1) != '2'   ) {
+                       tst_resm(TFAIL, "Error: Shared memory contents\n") ;
+               }
+       }
+
+       tst_resm(TPASS, "Correct shared memory contents");
+/*-----------------------------------------------------------------*/
+       tst_exit() ;
+
+/*----------------------------------------------------------------*/
+       return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                perror("shmctl");
+                tst_resm(TFAIL,
+                "shmctl Failed to remove: shmid = %d, errno = %d\n",
+                shmid, errno) ;
+                tst_exit();
+        }
+        return(0);
+}
+
diff --git a/test/ipc/shmt/shmt04.c b/test/ipc/shmt/shmt04.c
new file mode 100644 (file)
index 0000000..1035cd9
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 03/21/2003   enable ia64     Jacky.Malcles */
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001   Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *              shmt04
+ *
+ * CALLS
+ *              shmctl(2) shmget(2) shmat(2)
+ *
+ * ALGORITHM
+ * Parent process forks a child. Child pauses until parent has created
+ * a shared memory segment, attached to it and written to it too. At that
+ * time child gets the shared memory segment id, attaches to it and 
+ * verifies that its contents are the same as the contents of the
+ * parent attached segment.
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+
+char *TCID="shmt04";            /* Test program identifier.    */
+int TST_TOTAL=2;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+
+key_t key;
+sigset_t sigset;
+
+#define  ADDR1  (void *)0x40000000
+#define  ADDR  (void *)0x80000
+#define  SIZE  16*1024
+
+
+int child(void);
+int rm_shm(int);
+
+int main(void)
+{
+ char *cp=NULL;
+ int pid, pid1, shmid;
+ int status;
+
+ key = (key_t) getpid() ;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset,SIGUSR1);
+ sigprocmask(SIG_BLOCK,&sigset,NULL);
+ pid = fork();
+ switch (pid) {
+ case -1:
+  tst_resm(TBROK,"fork failed");
+  tst_exit() ;
+ case 0:
+  child();
+ }
+
+/*----------------------------------------------------------*/
+
+
+if ((shmid = shmget(key, SIZE, IPC_CREAT|0666)) < 0 ) {
+ perror("shmget");
+ tst_resm(TFAIL,"Error: shmget: shmid = %d, errno = %d\n",
+ shmid, errno) ;
+ /*
+  * kill the child if parent failed to do the attach
+  */
+ (void)kill(pid, SIGINT);
+}
+else {
+#ifdef __ia64__
+  cp = (char *) shmat(shmid, ADDR1, 0);
+#elif defined(__ARM_ARCH_4T__)
+  cp = (char *) shmat(shmid, NULL, 0);
+#else
+  cp = (char *) shmat(shmid, ADDR, 0);
+#endif
+
+ if (cp == (char *)-1) {
+  perror("shmat");
+  tst_resm(TFAIL,
+           "Error: shmat: shmid = %d, errno = %d\n",
+           shmid, errno) ;
+
+/* kill the child if parent failed to do the attch */
+
+ kill(pid, SIGINT) ;   
+
+/* remove shared memory segment */
+
+ rm_shm(shmid) ;  
+
+ tst_exit() ;
+} 
+*cp     = 'A';
+*(cp+1) = 'B';
+*(cp+2) = 'C';
+
+kill(pid, SIGUSR1);
+while ( (pid1 = wait(&status)) < 0 && 
+ (errno == EINTR) ) ;
+ if (pid1 != pid) {
+  tst_resm(TFAIL,"Waited on the wrong child") ;
+  tst_resm(TFAIL,
+           "Error: wait_status = %d, pid1= %d\n", status, pid1) ;
+ }
+}
+
+tst_resm(TPASS,"shmget,shmat");
+
+/*----------------------------------------------------------*/
+
+
+if (shmdt(cp) < 0 ) {
+ tst_resm(TFAIL,"shmdt");
+}
+
+tst_resm(TPASS,"shmdt");
+
+/*----------------------------------------------------------*/
+
+rm_shm(shmid) ;
+tst_exit() ;
+
+/*----------------------------------------------------------*/
+return(0);
+}
+
+int child(void)
+{
+int  shmid, 
+     chld_pid ;
+char *cp;
+
+sigemptyset(&sigset);
+sigsuspend(&sigset);
+chld_pid = getpid() ;
+/*--------------------------------------------------------*/
+
+
+if ((shmid = shmget(key, SIZE, 0)) < 0) {
+ perror("shmget:child process");
+ tst_resm(TFAIL,
+          "Error: shmget: errno=%d, shmid=%d, child_pid=%d\n",
+           errno, shmid, chld_pid);
+}
+else 
+{
+#ifdef __ia64__
+  cp = (char *) shmat(shmid, ADDR1, 0);
+#elif defined(__ARM_ARCH_4T__)
+  cp = (char *) shmat(shmid, NULL, 0);
+#else
+  cp = (char *) shmat(shmid, ADDR, 0);
+#endif
+ if (cp == (char *)-1) {
+  perror("shmat:child process");
+  tst_resm(TFAIL,
+           "Error: shmat: errno=%d, shmid=%d, child_pid=%d\n",
+           errno, shmid, chld_pid);
+} else {
+  if (*cp != 'A') {
+   tst_resm(TFAIL,"child: not A\n");
+  }
+  if (*(cp+1) != 'B') {
+   tst_resm(TFAIL,"child: not B\n");
+  }
+  if (*(cp+2) != 'C') {
+   tst_resm(TFAIL,"child: not C\n");
+  }
+  if (*(cp+8192) != 0) {
+   tst_resm(TFAIL,"child: not 0\n");
+  }
+}
+
+}
+tst_exit() ;
+return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                perror("shmctl");
+                tst_resm(TFAIL,
+                "shmctl Failed to remove: shmid = %d, errno = %d\n",
+                shmid, errno) ;
+                tst_exit();
+        }
+        return(0);
+}
diff --git a/test/ipc/shmt/shmt05.c b/test/ipc/shmt/shmt05.c
new file mode 100644 (file)
index 0000000..93326e9
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001   Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *              shmt05
+ *
+ * CALLS
+ *              shmctl(2) shmget(2) shmat(2)
+ *
+ * ALGORITHM
+ * Create two shared memory segments and attach them to the same process
+ * at two different addresses. The addresses DO BUMP into each other.
+ * The second attach should Fail.
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#include <time.h>
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+
+char *TCID="shmt05";            /* Test program identifier.    */
+int TST_TOTAL=2;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+key_t           key[2];
+
+#define                 ADDR            (void *)0x80000
+#define                 ADDR1           (void *)0x81000
+#define ADDR_IA    (void *)0x40000000
+#define ADDR1_IA    (void *)0x40000010
+
+#define                 SIZE            16*1024
+
+#define                srand48 srand
+#define                lrand48 rand
+
+int rm_shm(int);
+
+int main(void)
+{
+ int            shmid, shmid1;
+ char           *cp, *cp1;
+
+ srand48((getpid() << 16) + (unsigned)time((time_t *)NULL));
+
+ key[0] = (key_t) lrand48();
+ key[1] = (key_t) lrand48();
+
+/*--------------------------------------------------------*/
+
+
+ if ((shmid = shmget(key[0], SIZE, IPC_CREAT|0666)) < 0) {
+  perror("shmget");
+  tst_resm(TFAIL,
+  "Error: shmget: shmid = %d, errno = %d\n",
+  shmid, errno) ;
+ } else {
+#ifdef __ia64__ 
+  cp = (char *) shmat(shmid, ADDR_IA, 0);
+#elif defined(__ARM_ARCH_4T__)
+  cp = (char *) shmat(shmid, (void *)NULL, 0);
+#else
+  cp = (char *) shmat(shmid, ADDR, 0);
+#endif
+  if (cp == (char *)-1) {
+   tst_resm(TFAIL,"shmat");
+   rm_shm(shmid) ;
+  }
+ }
+
+ tst_resm(TPASS,"shmget & shmat");              
+
+/*--------------------------------------------------------*/
+
+
+ if ((shmid1 = shmget(key[1], SIZE, IPC_CREAT|0666)) < 0) {
+  perror("shmget2");
+  tst_resm(TFAIL,
+  "Error: shmget: shmid1 = %d, errno = %d\n",
+  shmid1, errno) ;
+ } else {
+#ifdef __ia64__
+   cp1 = (char *) shmat(shmid1, ADDR1_IA, 0);
+#elif defined(__ARM_ARCH_4T__)
+   cp1 = (char *) shmat(shmid1, (void *)NULL, 0);
+#else
+   cp1 = (char *) shmat(shmid1, ADDR1, 0);
+#endif
+  if (cp1 != (char *)-1) {
+   perror("shmat");
+   tst_resm(TFAIL,
+     "Error: shmat: shmid1 = %d, addr= %#x, errno = %d\n",
+     shmid1, cp1, errno);
+  }
+ }
+
+ tst_resm(TPASS,"2nd shmget & shmat"); 
+
+/*------------------------------------------------------*/
+
+ rm_shm(shmid) ;
+ rm_shm(shmid1) ;
+
+ tst_exit() ;
+
+/*-------------------------------------------------------*/
+ return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+  if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+   perror("shmctl");
+   tst_resm(TFAIL,
+            "shmctl Failed to remove: shmid = %d, errno = %d\n",
+            shmid, errno) ;
+   tst_exit();
+  }
+  return(0);
+}
diff --git a/test/ipc/shmt/shmt06.c b/test/ipc/shmt/shmt06.c
new file mode 100644 (file)
index 0000000..e3ba11d
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001   Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *     shmt06
+ *
+ * CALLS
+ *     shmctl(2) shmget(2) shmat(2)
+ *
+ * ALGORITHM
+ * Parent process forks a child. Child pauses until parent has created
+ * a shared memory segment, attached to it and written to it too. At that
+ * time child gets the shared memory segment id, attaches to it at a
+ * different address than the parents and verifies that its contents are 
+ * the same as the contents of the parent attached segment.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/utsname.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define                ADDR            (void *)0x80000
+#define                ADDR1           (void *)0xA0000
+#define         ADDR_MIPS       (void *)0x80000
+#define         ADDR1_MIPS      (void *)0xC0000
+#define        ADDR_IA         (void *)0x40000000
+#define        ADDR1_IA        (void *)0x50000000
+#define                SIZE            16*1024
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+
+char *TCID="shmt06";            /* Test program identifier.    */
+int TST_TOTAL=2;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+key_t  key;
+sigset_t sigset;
+
+int child(void);
+int rm_shm(int);
+
+int main(void)
+{
+       char    *cp=NULL;
+       int     pid, pid1, shmid;
+       int     status;
+       
+       key = (key_t)getpid() ;
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset,SIGUSR1);
+       sigprocmask(SIG_BLOCK,&sigset,NULL);
+
+       pid = fork();
+       switch (pid) {
+       case -1:
+               tst_resm(TBROK,"fork failed");
+                tst_exit() ;
+       case 0:
+               child();
+       }
+
+/*------------------------------------------------------*/
+
+
+       if ((shmid = shmget(key, SIZE, IPC_CREAT|0666)) < 0) {
+               perror("shmget");
+               tst_resm(TFAIL,"Error: shmget: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+               /*
+                * kill the child if parent failed to do the attach
+                */
+               (void)kill(pid, SIGINT);
+       }
+       else {
+#ifdef __ia64__
+                 cp = (char *) shmat(shmid, ADDR_IA, 0);
+#elif defined(__ARM_ARCH_4T__)
+                 cp = (char *) shmat(shmid, (void*) NULL, 0);
+#elif defined(__mips__)
+                 cp = (char *) shmat(shmid, ADDR_MIPS, 0);
+#else
+                 cp = (char *) shmat(shmid, ADDR, 0);
+#endif 
+               if (cp == (char *)-1) {
+                       perror("shmat") ;
+                       tst_resm(TFAIL,
+                       "Error: shmat: shmid = %d, errno = %d\n",
+                       shmid, errno) ;
+
+               /* kill the child if parent failed to do the attch */
+
+                       kill(pid, SIGINT) ;   
+
+               /* remove shared memory segment */
+
+                       rm_shm(shmid) ;  
+
+                       tst_exit() ;
+               } 
+               *cp     = 'A';
+               *(cp+1) = 'B';
+               *(cp+2) = 'C';
+
+               kill(pid, SIGUSR1);
+               while ( (pid1 = wait(&status)) < 0 && 
+                       (errno == EINTR) ) ;
+               if (pid1 != pid) {
+                       tst_resm(TFAIL,"Waited on the wrong child") ;
+                       tst_resm(TFAIL,
+                       "Error: wait_status = %d, pid1= %d\n", status, pid1) ;
+               }
+       }
+
+       tst_resm(TPASS,"shmget,shmat");
+
+/*---------------------------------------------------------------*/
+
+
+       if (shmdt(cp) < 0) {
+               tst_resm(TFAIL,"shmdt");
+       }
+
+       tst_resm(TPASS,"shmdt");
+
+/*-------------------------------------------------------------*/
+
+       rm_shm(shmid) ;
+       tst_exit() ;
+
+/*-----------------------------------------------------------*/
+       return(0);
+}
+
+int child(void)
+{
+       int     shmid ,
+               chld_pid ;
+       char    *cp;
+
+       sigemptyset(&sigset);
+       sigsuspend(&sigset);
+       chld_pid = getpid() ;
+       
+       if ((shmid = shmget(key, SIZE, 0)) < 0) {
+               perror("shmget:child process");
+               tst_resm(TFAIL,
+               "Error: shmget: errno=%d, shmid=%d, child_pid=%d\n",
+               errno, shmid, chld_pid);
+       }
+       else {
+#ifdef __ia64__        
+                 cp = (char *) shmat(shmid, ADDR1_IA, 0);
+#elif defined(__ARM_ARCH_4T__) 
+                 cp = (char *) shmat(shmid, (void *) NULL, 0);
+#elif defined(__mips__)        
+                 cp = (char *) shmat(shmid, ADDR1_MIPS, 0);
+#else
+                 cp = (char *) shmat(shmid, ADDR1, 0);
+#endif
+               if (cp == (char *)-1) {
+                       perror("shmat:child process");
+                       tst_resm(TFAIL,
+                       "Error: shmat: errno=%d, shmid=%d, child_pid=%d\n",
+                       errno, shmid, chld_pid);
+               } else {
+                       if (*cp != 'A') {
+                               tst_resm(TFAIL,"child: not A\n");
+                       }
+                       if (*(cp+1) != 'B') {
+                               tst_resm(TFAIL,"child: not B\n");
+                       }
+                       if (*(cp+2) != 'C') {
+                               tst_resm(TFAIL,"child: not C\n");
+                       }
+                       if (*(cp+8192) != 0) {
+                               tst_resm(TFAIL,"child: not 0\n");
+                       }
+               }
+
+       }
+       tst_exit() ;
+        return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                perror("shmctl");
+                tst_resm(TFAIL,
+                "shmctl Failed to remove: shmid = %d, errno = %d\n",
+                shmid, errno) ;
+                tst_exit();
+        }
+        return(0);
+}
+
diff --git a/test/ipc/shmt/shmt07.c b/test/ipc/shmt/shmt07.c
new file mode 100644 (file)
index 0000000..dbf7f13
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001   Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *     shmt07
+ *
+ * CALLS
+ *     shmctl(2) shmget(2) shmat(2)
+ *
+ * ALGORITHM
+ * Create and attach a shared memory segment, write to it
+ * and then fork a child. The child Verifies that the shared memory segment
+ * that it inherited from the parent conatins the same data that was originally
+ * written to it by the parent.
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define                ADDR    (void *)0x80000
+#define                ADDR_IA (void *)0x40000000
+#define                SIZE    16*1024
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+
+char *TCID="shmt07";            /* Test program identifier.    */
+int TST_TOTAL=2;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+int child(void);
+int rm_shm(int);
+
+int main(void)
+{
+       char    *cp=NULL;
+       int     shmid, pid, status;
+       key_t   key;
+
+       key = (key_t) getpid() ;
+
+/*---------------------------------------------------------*/
+
+       errno = 0;
+
+       if ((shmid = shmget(key, SIZE, IPC_CREAT|0666)) < 0) {
+               perror("shmget");
+               tst_resm(TFAIL,"Error: shmget: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+               tst_exit() ;
+       }
+
+#ifdef __ia64__        
+         cp = (char *) shmat(shmid, ADDR_IA, 0);
+#elif defined(__ARM_ARCH_4T__)
+         cp = (char *) shmat(shmid, (void *) NULL, 0);
+#else
+         cp = (char *) shmat(shmid, ADDR, 0);
+#endif
+       if (cp == (char *)-1) {
+               perror("shmat");
+               tst_resm(TFAIL,
+               "Error: shmat: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+               rm_shm(shmid) ;
+               tst_exit() ;
+       }
+
+       *cp     = '1';
+       *(cp+1) = '2';
+
+       tst_resm(TPASS,"shmget,shmat");
+
+/*-------------------------------------------------------*/
+
+
+       pid = fork() ;
+       switch (pid) {
+           case -1 :
+                       tst_resm(TBROK,"fork failed");
+                               tst_exit() ;
+       
+           case 0  :   
+                       if (*cp != '1') {
+                               tst_resm(TFAIL, "Error: not 1\n");
+                       }
+                       if (*(cp+1) != '2') {
+                               tst_resm(TFAIL, "Error: not 2\n");
+                       }
+                       tst_exit() ;
+       }
+
+       /* parent */
+       while( wait(&status) < 0 && errno == EINTR ) ;
+
+       tst_resm(TPASS,"cp & cp+1 correct") ;
+
+/*-----------------------------------------------------------*/
+       rm_shm(shmid) ;
+       tst_exit() ;
+/*-----------------------------------------------------------*/
+       return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                perror("shmctl");
+                tst_resm(TFAIL,
+                "shmctl Failed to remove: shmid = %d, errno = %d\n",
+                shmid, errno) ;
+                tst_exit();
+        }
+        return(0);
+}
+
diff --git a/test/ipc/shmt/shmt08.c b/test/ipc/shmt/shmt08.c
new file mode 100644 (file)
index 0000000..36c4062
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001   Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *     shmt08
+ *
+ * CALLS
+ *     shmctl(2) shmget(2) shmat(2) shmdt(2)
+ *
+ * ALGORITHM
+ * Create a shared memory segment. Attach it twice at an address
+ * that is provided by the system.  Detach the previously attached 
+ * segments from the process.
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+#define K_1  1024
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+char *TCID="shmt08";            /* Test program identifier.    */
+int TST_TOTAL=2;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+key_t  key;
+
+int rm_shm(int);
+
+int main(void)
+{
+       char    *cp=NULL, *cp1=NULL;
+       int     shmid;
+
+       key = (key_t) getpid() ;
+       errno = 0 ;
+/*-------------------------------------------------------*/
+
+
+       if ((shmid = shmget(key, 24*K_1, IPC_CREAT|0666)) < 0) {
+               perror("shmget");
+               tst_resm(TFAIL,"Error: shmget: shmid = %d, errno = %d\n",
+               shmid, errno) ;
+               tst_exit() ;
+       }
+
+       cp = (char *) shmat(shmid, (void *)0, 0);
+       if (cp == (char *)-1) {
+               tst_resm(TFAIL,"shmat1 Failed");
+               rm_shm(shmid) ;
+               tst_exit() ;
+       }
+
+       cp1 = (char *) shmat(shmid, (void *)0, 0);
+       if (cp1 == (char *)-1) {
+               perror("shmat2");
+               rm_shm(shmid) ;
+               tst_exit() ;
+       }
+
+       tst_resm(TPASS,"shmget,shmat");
+
+/*--------------------------------------------------------*/
+
+
+       if (shmdt(cp) < 0) {
+               perror("shmdt2");
+               tst_resm(TFAIL,"shmdt:cp") ;
+       }
+
+       if (shmdt(cp1) < 0 ) {
+               perror("shmdt1");
+               tst_resm(TFAIL,"shmdt:cp1") ;
+       }
+
+       tst_resm(TPASS,"shmdt");
+
+/*---------------------------------------------------------*/
+       rm_shm(shmid) ;
+       tst_exit() ;
+
+/*---------------------------------------------------------*/
+       return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                perror("shmctl");
+                tst_resm(TFAIL,
+                "shmctl Failed to remove: shmid = %d, errno = %d\n",
+                shmid, errno) ;
+                tst_exit();
+        }
+        return(0);
+}
+
diff --git a/test/ipc/shmt/shmt10.c b/test/ipc/shmt/shmt10.c
new file mode 100644 (file)
index 0000000..fd1d7ba
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* 12/20/2002   Port to LTP     robbiew@us.ibm.com */
+/* 06/30/2001   Port to Linux   nsharoff@us.ibm.com */
+
+/*
+ * NAME
+ *     shmt10.c - test simultaneous shmat/shmdt
+ *
+ * CALLS
+ *     shmget, shmat, shmdt, shmctl
+ *
+ * ALGORITHM
+ *     Create a shared memory segment and fork a child. Both
+ *     parent and child spin in a loop attaching and detaching
+ *     the segment. After completing the specified number of
+ *     iterations, the child exits and the parent deletes the
+ *     segment.
+ *
+ * USAGE
+ *  shmt10 [-i 500]
+ *     -i # of iterations, default 500
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+
+#define        SIZE    0x32768
+
+/** LTP Port **/
+#include "test.h"
+#include "usctest.h"
+
+char *TCID="shmt10";            /* Test program identifier.    */
+int TST_TOTAL=2;                /* Total number of test cases. */
+extern int Tst_count;           /* Test Case counter for tst_* routines */
+/**************/
+
+int shmid;
+key_t key;
+
+int child(int);
+int rm_shm(int);
+void fini(int);
+
+int main(int argc, char *argv[])
+{
+       char *c1=NULL;
+       int pid, st;
+       register int i;
+       int iter = 500;
+       int c;
+       extern char *optarg;
+
+       key = (key_t)getpid();
+       signal(SIGTERM, fini);
+
+/*--------------------------------------------------------*/
+
+       while ((c = getopt(argc, argv, "i:")) != EOF) {
+               switch (c) {
+               case 'i':
+                       iter = atoi(optarg);
+                       break;
+               default:
+                       tst_resm(TCONF, "usage: %s [-i <# iterations>]", argv[0]);
+                       tst_exit();
+               }
+       }
+
+
+/*------------------------------------------------------------------------*/
+
+       if ((shmid = shmget(key, SIZE, IPC_CREAT|0666)) < 0) {
+               tst_resm(TFAIL,"shmget") ;
+               tst_resm(TFAIL, "Error: shmid = %d\n", shmid) ;
+               tst_exit() ;
+       }
+
+       pid = fork();
+       switch(pid) {
+       case -1:
+               tst_resm(TBROK,"fork failed");
+                tst_exit() ;
+       case 0:
+               child(iter);
+               tst_exit();
+       }
+
+       for (i = 0; i < iter; i++) {
+               if ((c1 = (char *) shmat(shmid, (void *)0, 0)) == (char *)-1) {
+                       tst_resm(TFAIL, 
+                       "Error shmat: iter %d, shmid = %d\n", i, shmid);
+                       break;
+               }
+               if (shmdt(c1) < 0) {
+                       tst_resm(TFAIL, 
+                       "Error: shmdt: iter %d ", i) ;
+                       break;
+               }
+       }
+       while ( wait(&st) < 0 && errno == EINTR ) 
+                      ;
+       tst_resm(TPASS,"shmat,shmdt");
+/*------------------------------------------------------------------------*/
+
+       rm_shm(shmid);
+       tst_exit();
+
+/*------------------------------------------------------------------------*/
+       return(0);
+}
+
+int rm_shm(shmid)
+int shmid ;
+{
+        if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+                perror("shmctl");
+                tst_resm(TFAIL,
+                "shmctl Failed to remove: shmid = %d, errno = %d\n",
+                shmid, errno) ;
+                tst_exit();
+        }
+        return(0);
+}
+
+int child(iter)
+int iter;
+{
+       register int i;
+       char *c1;
+
+       for (i = 0; i < iter; i++) {
+               if ((c1 = (char *) shmat(shmid, (void *)0, 0)) == (char *)-1) {
+                       tst_resm(TFAIL, 
+                       "Error:child proc: shmat: iter %d, shmid = %d\n", 
+                       i, shmid);
+                       tst_exit();
+               }
+               if (shmdt(c1) < 0) {
+                       tst_resm(TFAIL, 
+                       "Error: child proc: shmdt: iter %d ", i);
+                       tst_exit();
+               }
+       }
+       return(0);
+}
+
+void 
+fini(int sig)
+{
+       rm_shm(shmid);
+}
diff --git a/test/ipc/shmt/testshm.sh b/test/ipc/shmt/testshm.sh
new file mode 100644 (file)
index 0000000..792bd4a
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+make
+# execute them one by one
+# the results are obvious
+./shmt01
+./shmt02
+./shmt03
+./shmt04
+./shmt05
+./shmt06
+./shmt07
+./shmt08
+./shmt10