blob: 8d3b7aeef890f1fb558df6ae9b5a9dd7ba6462bd [file] [log] [blame]
Matus Marhefka30a55782014-10-02 16:48:40 +02001/* Copyright (c) 2014 Red Hat, Inc.
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of version 2 the GNU General Public License as
5 * published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 ***********************************************************************
15 * File: sem_comm.c
16 *
17 * Description:
18 * 1. Clones two child processes with CLONE_NEWIPC flag, each child
19 * creates System V semaphore (sem) with the _identical_ key.
20 * 2. Child1 locks the semaphore.
21 * 3. Child2 locks the semaphore.
22 * 4. Locking the semaphore with the identical key but from two different
23 * IPC namespaces should not interfere with each other, so if child2
24 * is able to lock the semaphore (after child1 locked it), test passes,
25 * otherwise test fails.
26 */
27
28#define _GNU_SOURCE
29#include <sys/ipc.h>
30#include <sys/sem.h>
31#include <sys/types.h>
32#include <sys/wait.h>
33#include <stdio.h>
34#include <errno.h>
Matus Marhefka30a55782014-10-02 16:48:40 +020035#include "test.h"
36#include "safe_macros.h"
37#include "libclone.h"
38#include "ipcns_helper.h"
39
40
41#define TESTKEY 124426L
42char *TCID = "sem_comm";
43int TST_TOTAL = 1;
44struct tst_checkpoint checkpoint1;
45struct tst_checkpoint checkpoint2;
46
47
48static void cleanup(void)
49{
50 tst_rmdir();
51}
52
53static void setup(void)
54{
55 tst_require_root(NULL);
56 check_newipc();
57 tst_tmpdir();
58 TST_CHECKPOINT_CREATE(&checkpoint1);
59 TST_CHECKPOINT_CREATE(&checkpoint2);
60}
61
62int chld1_sem(void *arg)
63{
64 int id;
65 struct sembuf sm;
66
67 id = semget(TESTKEY, 1, IPC_CREAT);
68 if (id == -1) {
69 perror("semget");
70 return 2;
71 }
72
73 if (semctl(id, 0, SETVAL, 1) == -1) {
74 perror("semctl");
75 semctl(id, 0, IPC_RMID);
76 return 2;
77 }
78
79 /* tell child2 to continue */
80 TST_CHECKPOINT_SIGNAL_CHILD(NULL, &checkpoint1);
81
82 /* wait for child2 to create the semaphore */
83 TST_CHECKPOINT_CHILD_WAIT(&checkpoint2);
84
85 sm.sem_num = 0;
86 sm.sem_op = -1;
87 sm.sem_flg = IPC_NOWAIT;
88 if (semop(id, &sm, 1) == -1) {
89 perror("semop");
90 semctl(id, 0, IPC_RMID);
91 return 2;
92 }
93
94 /* tell child2 to continue */
95 TST_CHECKPOINT_SIGNAL_CHILD(NULL, &checkpoint1);
96
97 /* wait for child2 to lock the semaphore */
98 TST_CHECKPOINT_CHILD_WAIT(&checkpoint2);
99
100 sm.sem_op = 1;
101 semop(id, &sm, 1);
102
103 semctl(id, 0, IPC_RMID);
104 return 0;
105}
106
107int chld2_sem(void *arg)
108{
109 int id, rval = 0;
110 struct sembuf sm;
111
112 /* wait for child1 to create the semaphore */
113 TST_CHECKPOINT_CHILD_WAIT(&checkpoint1);
114
115 id = semget(TESTKEY, 1, IPC_CREAT);
116 if (id == -1) {
117 perror("semget");
118 return 2;
119 }
120
121 if (semctl(id, 0, SETVAL, 1) == -1) {
122 perror("semctl");
123 semctl(id, 0, IPC_RMID);
124 return 2;
125 }
126
127 /* tell child1 to continue */
128 TST_CHECKPOINT_SIGNAL_CHILD(NULL, &checkpoint2);
129
130 /* wait for child1 to lock the semaphore */
131 TST_CHECKPOINT_CHILD_WAIT(&checkpoint1);
132
133 sm.sem_num = 0;
134 sm.sem_op = -1;
135 sm.sem_flg = IPC_NOWAIT;
136 if (semop(id, &sm, 1) == -1) {
137 if (errno == EAGAIN) {
138 rval = 1;
139 } else {
140 perror("semop");
141 semctl(id, 0, IPC_RMID);
142 return 2;
143 }
144 }
145
146 /* tell child1 to continue */
147 TST_CHECKPOINT_SIGNAL_CHILD(NULL, &checkpoint2);
148
149 sm.sem_op = 1;
150 semop(id, &sm, 1);
151
152 semctl(id, 0, IPC_RMID);
153 return rval;
154}
155
156static void test(void)
157{
158 int status, ret = 0;
159
160 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem, NULL);
161 if (ret == -1)
162 tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
163
164 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem, NULL);
165 if (ret == -1)
166 tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
167
168
169 while (wait(&status) > 0) {
170 if (WIFEXITED(status) && WEXITSTATUS(status) == 1)
171 ret = 1;
172 if (WIFEXITED(status) && WEXITSTATUS(status) == 2)
173 tst_brkm(TBROK | TERRNO, cleanup, "error in child");
174 if (WIFSIGNALED(status)) {
175 tst_resm(TFAIL, "child was killed with signal %s",
176 tst_strsig(WTERMSIG(status)));
177 return;
178 }
179 }
180
181 if (ret)
182 tst_resm(TFAIL, "SysV sem: communication with identical keys"
183 " between namespaces");
184 else
185 tst_resm(TPASS, "SysV sem: communication with identical keys"
186 " between namespaces");
187}
188
189int main(int argc, char *argv[])
190{
191 const char *msg;
192 int lc;
193
194 msg = parse_opts(argc, argv, NULL, NULL);
195 if (msg != NULL)
196 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
197
198 setup();
199
200 for (lc = 0; TEST_LOOPING(lc); lc++)
201 test();
202
203 cleanup();
204 tst_exit();
205}