1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * msgsnd06.c 23 * 24 * DESCRIPTION 25 * msgsnd06 - test for EIDRM error 26 * 27 * ALGORITHM 28 * loop if that option was specified 29 * create a message queue with read/write permissions 30 * initialize a message buffer with a known message and type 31 * enqueue messages in a loop until the queue is full 32 * fork a child process 33 * child attempts to enqueue a message to the full queue and sleeps 34 * parent removes the queue and then exits 35 * child get a return from msgsnd() 36 * check the errno value 37 * issue a PASS message if we get EIDRM 38 * otherwise, the tests fails 39 * issue a FAIL message 40 * call cleanup 41 * 42 * USAGE: <for command-line> 43 * msgsnd06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 44 * where, -c n : Run n copies concurrently. 45 * -e : Turn on errno logging. 46 * -i n : Execute test n times. 47 * -I x : Execute test for x seconds. 48 * -P x : Pause for x seconds between iterations. 49 * -t : Turn on syscall timing. 50 * 51 * HISTORY 52 * 03/2001 - Written by Wayne Boyer 53 * 14/03/2008 Matthieu Fertr (Matthieu.Fertre (at) irisa.fr) 54 * - Fix concurrency issue. Due to the use of usleep function to 55 * synchronize processes, synchronization issues can occur on a loaded 56 * system. Fix this by using pipes to synchronize processes. 57 * 58 * RESTRICTIONS 59 * none 60 */ 61 62 #include <sys/wait.h> 63 #include "test.h" 64 65 #include "ipcmsg.h" 66 67 void cleanup(void); 68 void setup(void); 69 void do_child(void); 70 71 char *TCID = "msgsnd06"; 72 int TST_TOTAL = 1; 73 74 int msg_q_1 = -1; /* The message queue id created in setup */ 75 76 MSGBUF msg_buf; 77 78 int main(int ac, char **av) 79 { 80 int lc; 81 pid_t c_pid; 82 int status, e_code; 83 84 tst_parse_opts(ac, av, NULL, NULL); 85 86 #ifdef UCLINUX 87 #define PIPE_NAME "msgsnd06" 88 maybe_run_child(&do_child, "d", &msg_q_1); 89 #endif 90 91 setup(); /* global setup */ 92 93 /* The following loop checks looping state if -i option given */ 94 95 for (lc = 0; TEST_LOOPING(lc); lc++) { 96 /* reset tst_count in case we are looping */ 97 tst_count = 0; 98 99 msgkey = getipckey(); 100 101 /* create a message queue with read/write permission */ 102 if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) 103 == -1) { 104 tst_brkm(TBROK, cleanup, "Can't create message queue"); 105 } 106 107 /* initialize the message buffer */ 108 init_buf(&msg_buf, MSGTYPE, MSGSIZE); 109 110 /* write messages to the queue until it is full */ 111 while (msgsnd(msg_q_1, &msg_buf, MSGSIZE, IPC_NOWAIT) != -1) { 112 msg_buf.mtype += 1; 113 } 114 115 /* 116 * fork a child that will attempt to write a message 117 * to the queue without IPC_NOWAIT 118 */ 119 if ((c_pid = FORK_OR_VFORK()) == -1) { 120 tst_brkm(TBROK, cleanup, "could not fork"); 121 } 122 123 if (c_pid == 0) { /* child */ 124 125 #ifdef UCLINUX 126 if (self_exec(av[0], "d", msg_q_1) < 0) { 127 tst_brkm(TBROK, cleanup, "could not self_exec"); 128 } 129 #else 130 do_child(); 131 #endif 132 } else { 133 TST_PROCESS_STATE_WAIT(cleanup, c_pid, 'S'); 134 135 /* remove the queue */ 136 rm_queue(msg_q_1); 137 138 /* wait for the child to finish */ 139 wait(&status); 140 /* make sure the child returned a good exit status */ 141 e_code = status >> 8; 142 if (e_code != 0) { 143 tst_resm(TFAIL, "Failures reported above"); 144 } 145 } 146 } 147 148 cleanup(); 149 150 tst_exit(); 151 } 152 153 /* 154 * do_child() 155 */ 156 void do_child(void) 157 { 158 int retval = 0; 159 160 #ifdef UCLINUX 161 /* initialize the message buffer */ 162 init_buf(&msg_buf, MSGTYPE, MSGSIZE); 163 164 #endif 165 /* 166 * Attempt to write another message to the full queue. 167 * Without the IPC_NOWAIT flag, the child sleeps 168 */ 169 TEST(msgsnd(msg_q_1, &msg_buf, MSGSIZE, 0)); 170 171 if (TEST_RETURN != -1) { 172 retval = 1; 173 tst_resm(TFAIL, "call succeeded when error expected"); 174 exit(retval); 175 } 176 177 switch (TEST_ERRNO) { 178 case EIDRM: 179 tst_resm(TPASS, "expected failure - errno = %d : %s", 180 TEST_ERRNO, strerror(TEST_ERRNO)); 181 182 /* mark the queue as invalid as it was removed */ 183 msg_q_1 = -1; 184 break; 185 default: 186 retval = 1; 187 tst_resm(TFAIL, 188 "call failed with an unexpected error - %d : %s", 189 TEST_ERRNO, strerror(TEST_ERRNO)); 190 break; 191 } 192 exit(retval); 193 } 194 195 /* 196 * setup() - performs all the ONE TIME setup for this test. 197 */ 198 void setup(void) 199 { 200 201 tst_sig(FORK, DEF_HANDLER, cleanup); 202 203 TEST_PAUSE; 204 205 /* 206 * Create a temporary directory and cd into it. 207 * This helps to ensure that a unique msgkey is created. 208 * See ../lib/libipc.c for more information. 209 */ 210 tst_tmpdir(); 211 } 212 213 /* 214 * cleanup() - performs all the ONE TIME cleanup for this test at completion 215 * or premature exit. 216 */ 217 void cleanup(void) 218 { 219 220 tst_rmdir(); 221 222 } 223