From: Ben Gras Date: Mon, 21 Sep 2009 14:53:53 +0000 (+0000) Subject: ipc tests by GQ X-Git-Tag: v3.1.5~115 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=a4d1b17453312aa47b0be1abaeec33978b5446fa;p=minix.git ipc tests by GQ --- diff --git a/test/ipc/Makefile b/test/ipc/Makefile new file mode 100644 index 000000000..0aeac0e5b --- /dev/null +++ b/test/ipc/Makefile @@ -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 index 000000000..0ade066fc --- /dev/null +++ b/test/ipc/lib/Makefile @@ -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 index 000000000..4265afdb9 --- /dev/null +++ b/test/ipc/lib/ipcmsg.h @@ -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 +#include +#include + +#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 index 000000000..c89b76bff --- /dev/null +++ b/test/ipc/lib/ipcsem.h @@ -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 +#include +#include + + +#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 index 000000000..003046601 --- /dev/null +++ b/test/ipc/lib/ipcshm.h @@ -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 +#include +#include +#include + +#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 index 000000000..30374da3a --- /dev/null +++ b/test/ipc/lib/libipc.c @@ -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 +#include +#include +#include +#include + + +/* + * 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; imtext[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 index 000000000..43e3d47e9 --- /dev/null +++ b/test/ipc/lib/parse_opts.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + + +#if UNIT_TEST +#include +#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= 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 /* for errno */ +#include /* for NULL */ +#include /* for malloc() */ +#include /* for string function */ +#include /* for PATH_MAX */ +#include /* for opendir(), readdir(), closedir(), stat() */ +#include /* for [l]stat() */ +#include /* for opendir(), readdir(), closedir() */ +#include /* 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 index 000000000..4808ca258 --- /dev/null +++ b/test/ipc/lib/rmobj.h @@ -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 index 000000000..ca93e3274 --- /dev/null +++ b/test/ipc/lib/test.h @@ -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 +#include +#include +#include +#include + +#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 index 000000000..0b426ac5d --- /dev/null +++ b/test/ipc/lib/tst_res.c @@ -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 +#include +#include /* for I/O functions, BUFSIZ */ +#include /* for getenv() */ +#include /* for varargs stuff */ +#include /* 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 ( 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 ( 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 ( 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 index 000000000..658df4969 --- /dev/null +++ b/test/ipc/lib/tst_sig.c @@ -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 +#include +#include +#include +#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 index 000000000..ea2ff4675 --- /dev/null +++ b/test/ipc/lib/tst_tmpdir.c @@ -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 +#include +#include /* for getenv() */ +#include /* for string functions */ +#include /* for sysconf(), getcwd(), rmdir() */ +#include /* for mkdir() */ +#include /* 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 index 000000000..0858cec29 --- /dev/null +++ b/test/ipc/lib/usctest.h @@ -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 +#endif + +#include + +/* + * 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 0, + * issue a PASS message + * otherwise + * issue a FAIL message + * else issue a PASS message + * call cleanup + * + * USAGE: + * 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 index 000000000..32e03f866 --- /dev/null +++ b/test/ipc/msgctl/msgctl02.c @@ -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: + * 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 index 000000000..3027b9ca4 --- /dev/null +++ b/test/ipc/msgctl/msgctl03.c @@ -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: + * 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 index 000000000..fc8866b94 --- /dev/null +++ b/test/ipc/msgctl/msgctl04.c @@ -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: + * 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 + +#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; ipw_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 index 000000000..153a918d4 --- /dev/null +++ b/test/ipc/msgctl/msgctl05.c @@ -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: + * 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 +#include +#include + +#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 /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed by testhead.h */ +#include /* 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 index 000000000..826bc508d --- /dev/null +++ b/test/ipc/msgctl/msgctl07.c @@ -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 /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed by testhead.h */ +#include "test.h" +#include "usctest.h" +#include +#include +#include + +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> 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> 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 000000000..ec36e8a52 --- /dev/null +++ b/test/ipc/msgctl/msgctl09.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 000000000..9071354e0 --- /dev/null +++ b/test/ipc/msgget/Makefile @@ -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 index 000000000..e8ca99530 --- /dev/null +++ b/test/ipc/msgget/msgget01.c @@ -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: + * 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 + +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 index 000000000..a7040f670 --- /dev/null +++ b/test/ipc/msgget/msgget02.c @@ -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: + * 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 + * 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 + * 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 +#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; ipw_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 index 000000000..9071354e0 --- /dev/null +++ b/test/ipc/msgrcv/Makefile @@ -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 index 000000000..66c92d084 --- /dev/null +++ b/test/ipc/msgrcv/msgrcv01.c @@ -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: + * 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 +#include + +#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 index 000000000..c5cbdc3fa --- /dev/null +++ b/test/ipc/msgrcv/msgrcv02.c @@ -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: + * 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 + +#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; ipw_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 index 000000000..b069b27b4 --- /dev/null +++ b/test/ipc/msgrcv/msgrcv03.c @@ -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: + * 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 + * 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 + * 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 +#include + +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 index 000000000..e5a1f6259 --- /dev/null +++ b/test/ipc/msgrcv/msgrcv06.c @@ -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: + * 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 +#include + +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 index 000000000..9071354e0 --- /dev/null +++ b/test/ipc/msgsnd/Makefile @@ -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 index 000000000..368ea376d --- /dev/null +++ b/test/ipc/msgsnd/msgsnd01.c @@ -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: + * 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 index 000000000..24af375b5 --- /dev/null +++ b/test/ipc/msgsnd/msgsnd02.c @@ -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: + * 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 +#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; ipw_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 index 000000000..821492c5c --- /dev/null +++ b/test/ipc/msgsnd/msgsnd03.c @@ -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: + * 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 + * 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 index 000000000..eb0bb71b8 --- /dev/null +++ b/test/ipc/msgsnd/msgsnd05.c @@ -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: + * 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 +#include + +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 index 000000000..b7ed964e0 --- /dev/null +++ b/test/ipc/msgsnd/msgsnd06.c @@ -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: + * 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 +#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 index 000000000..6fdccf7c3 --- /dev/null +++ b/test/ipc/semctl/Makefile @@ -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 index 000000000..111ea45f6 --- /dev/null +++ b/test/ipc/semctl/semctl01.c @@ -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: + * 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 + * 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 + +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 index 000000000..0e522549a --- /dev/null +++ b/test/ipc/semctl/semctl03.c @@ -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: + * 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 + * 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 +#include + +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 + * 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 +#endif + +#include /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include +#include +#include +#include +#include "test.h" +#include "usctest.h" +#include +#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 index 000000000..b93bf9209 --- /dev/null +++ b/test/ipc/semctl/semctl07.c @@ -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 /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed for test */ +#include /* needed by testhead.h */ +#include /* 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 index 000000000..baf468ba8 --- /dev/null +++ b/test/ipc/semctl/test.sh @@ -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 index 000000000..c1aa8f114 --- /dev/null +++ b/test/ipc/semget/Makefile @@ -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 index 000000000..e23928c89 --- /dev/null +++ b/test/ipc/semget/semget01.c @@ -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: + * 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 index 000000000..8efd18c4c --- /dev/null +++ b/test/ipc/semget/semget02.c @@ -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: + * 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 + +#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; ipw_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 index 000000000..1b5c78077 --- /dev/null +++ b/test/ipc/semget/semget03.c @@ -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: + * 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 index 000000000..1c6b6108c --- /dev/null +++ b/test/ipc/semget/semget05.c @@ -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: + * 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 + * 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 + * 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 + * 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 + +#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; ipw_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 index 000000000..47a984510 --- /dev/null +++ b/test/ipc/semop/semop03.c @@ -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: + * 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 + * 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 + * 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 +#include + +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 + * 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 + * 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 + +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; ipw_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 index 000000000..d0f6a0e9a --- /dev/null +++ b/test/ipc/shmat/shmat03.c @@ -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: + * 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 index 000000000..da417531a --- /dev/null +++ b/test/ipc/shmat/test.sh @@ -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 index 000000000..9799fc9d4 --- /dev/null +++ b/test/ipc/shmctl/Makefile @@ -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 index 000000000..b308479b8 --- /dev/null +++ b/test/ipc/shmctl/shmctl01.c @@ -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: + * 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= 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 index 000000000..0801a9320 --- /dev/null +++ b/test/ipc/shmctl/shmctl02.c @@ -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: + * 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 + +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= 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 index 000000000..b7ceeaed0 --- /dev/null +++ b/test/ipc/shmctl/shmctl03.c @@ -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: + * 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 +#include + +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 + * 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 index 000000000..b18d1463b --- /dev/null +++ b/test/ipc/shmctl/test.sh @@ -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 index 000000000..34b4a8bf2 --- /dev/null +++ b/test/ipc/shmdt/Makefile @@ -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 index 000000000..1fd30f852 --- /dev/null +++ b/test/ipc/shmdt/shmdt01.c @@ -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: + * 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 +#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 index 000000000..5741d5f5a --- /dev/null +++ b/test/ipc/shmdt/shmdt02.c @@ -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: + * 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 index 000000000..131433930 --- /dev/null +++ b/test/ipc/shmdt/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +./shmdt01 +./shmdt02 diff --git a/test/ipc/shmget/Makefile b/test/ipc/shmget/Makefile new file mode 100644 index 000000000..99d6e903e --- /dev/null +++ b/test/ipc/shmget/Makefile @@ -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 index 000000000..93fefd398 --- /dev/null +++ b/test/ipc/shmget/shmget01.c @@ -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: + * 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 index 000000000..7792051c0 --- /dev/null +++ b/test/ipc/shmget/shmget02.c @@ -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: + * 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 + * 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 +#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 index 000000000..051208fe2 --- /dev/null +++ b/test/ipc/shmget/shmget05.c @@ -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: + * 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 +#include + +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 index 000000000..58719be71 --- /dev/null +++ b/test/ipc/shmget/test.sh @@ -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 index 000000000..e92d06cc7 --- /dev/null +++ b/test/ipc/shmt/Makefile @@ -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 index 000000000..4264b5878 --- /dev/null +++ b/test/ipc/shmt/shmt01.c @@ -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 +#include +#include +#include +#include +#include + +/** 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 index 000000000..836d16d31 --- /dev/null +++ b/test/ipc/shmt/shmt02.c @@ -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 +#include +#include +#include +#include +#include + +/** 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 index 000000000..d3e556461 --- /dev/null +++ b/test/ipc/shmt/shmt03.c @@ -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 +#include +#include +#include +#include + +/** 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 index 000000000..1035cd98e --- /dev/null +++ b/test/ipc/shmt/shmt04.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** 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 index 000000000..93326e9e0 --- /dev/null +++ b/test/ipc/shmt/shmt05.c @@ -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 +#include +#include +#include +#include +#include +#include + +/** 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 index 000000000..e3ba11dd6 --- /dev/null +++ b/test/ipc/shmt/shmt06.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..dbf7f136c --- /dev/null +++ b/test/ipc/shmt/shmt07.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..36c406255 --- /dev/null +++ b/test/ipc/shmt/shmt08.c @@ -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 +#include +#include +#include +#include + +#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 index 000000000..fd1d7bab0 --- /dev/null +++ b/test/ipc/shmt/shmt10.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..792bd4a66 --- /dev/null +++ b/test/ipc/shmt/testshm.sh @@ -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