1 /*
2 * Copyright (c) 2000-2001, 2005-2008 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 */
9
10 #include <sm/gen.h>
11 SM_RCSID("@(#)$Id: t-sem.c,v 1.17 2008/05/30 16:26:38 ca Exp $")
12
13 #include <stdio.h>
14
15 #if SM_CONF_SEM
16 # include <stdlib.h>
17 # include <unistd.h>
18 # include <sysexits.h>
19 # include <sm/heap.h>
20 # include <sm/string.h>
21 # include <sm/signal.h>
22 # include <sm/test.h>
23 # include <sm/sem.h>
24
25 # define T_SM_SEM_KEY (4321L)
26
27 static void
28 delay(t, s)
29 int t;
30 char *s;
31 {
32 if (t > 0)
33 {
34 #if DEBUG
35 fprintf(stderr, "sleep(%d) before %s\n", t, s);
36 #endif /* DEBUG */
37 sleep(t);
38 }
39 #if DEBUG
40 fprintf(stderr, "%s\n", s);
41 #endif /* DEBUG */
42 }
43
44
45 /*
46 ** SEMINTER -- interactive testing of semaphores.
47 **
48 ** Parameters:
49 ** owner -- create semaphores.
50 **
51 ** Returns:
52 ** 0 on success
53 ** < 0 on failure.
54 */
55
56 static int
seminter(owner)57 seminter(owner)
58 bool owner;
59 {
60 int semid;
61 int t;
62
63 semid = sm_sem_start(T_SM_SEM_KEY, SM_NSEM, 0, owner);
64 if (semid < 0)
65 {
66 perror("sm_sem_start failed");
67 return 1;
68 }
69
70 while ((t = getchar()) != EOF)
71 {
72 switch (t)
73 {
74 case 'a':
75 delay(0, "try to acq");
76 if (sm_sem_acq(semid, 0, 2) < 0)
77 {
78 perror("sm_sem_acq failed");
79 return 1;
80 }
81 delay(0, "acquired");
82 break;
83
84 case 'r':
85 delay(0, "try to rel");
86 if (sm_sem_rel(semid, 0, 2) < 0)
87 {
88 perror("sm_sem_rel failed");
89 return 1;
90 }
91 delay(0, "released");
92 break;
93
94 case 'v':
95 if ((t = sm_sem_get(semid, 0)) < 0)
96 {
97 perror("get_sem failed");
98 return 1;
99 }
100 printf("semval: %d\n", t);
101 break;
102
103 }
104 }
105 if (owner)
106 return sm_sem_stop(semid);
107 return 0;
108 }
109
110 /*
111 ** SEM_CLEANUP -- cleanup if something breaks
112 **
113 ** Parameters:
114 ** sig -- signal.
115 **
116 ** Returns:
117 ** none.
118 */
119
120 static int semid_c = -1;
121 void
sem_cleanup(sig)122 sem_cleanup(sig)
123 int sig;
124 {
125 if (semid_c >= 0)
126 (void) sm_sem_stop(semid_c);
127 exit(EX_UNAVAILABLE);
128 }
129
130 static int
drop_priv(uid,gid)131 drop_priv(uid, gid)
132 uid_t uid;
133 gid_t gid;
134 {
135 int r;
136
137 r = setgid(gid);
138 if (r != 0)
139 return r;
140 r = setuid(uid);
141 return r;
142 }
143
144 /*
145 ** SEMTEST -- test of semaphores
146 **
147 ** Parameters:
148 ** owner -- create semaphores.
149 **
150 ** Returns:
151 ** 0 on success
152 ** < 0 on failure.
153 */
154
155 # define MAX_CNT 10
156
157 static int
semtest(owner,uid,gid)158 semtest(owner, uid, gid)
159 int owner;
160 uid_t uid;
161 gid_t gid;
162 {
163 int semid, r;
164 int cnt = 0;
165
166 if (!owner && uid != 0)
167 {
168 r = drop_priv(uid, gid);
169 if (r < 0)
170 {
171 perror("drop_priv child failed");
172 return -1;
173 }
174 }
175 semid = sm_sem_start(T_SM_SEM_KEY, 1, 0, owner);
176 if (semid < 0)
177 {
178 perror("sm_sem_start failed");
179 return -1;
180 }
181
182 if (owner)
183 {
184 if (uid != 0)
185 {
186 r = sm_semsetowner(semid, uid, gid, 0660);
187 if (r < 0)
188 {
189 perror("sm_semsetowner failed");
190 return -1;
191 }
192 r = drop_priv(uid, gid);
193 if (r < 0)
194 {
195 perror("drop_priv owner failed");
196 return -1;
197 }
198 }
199
200 /* just in case someone kills the program... */
201 semid_c = semid;
202 (void) sm_signal(SIGHUP, sem_cleanup);
203 (void) sm_signal(SIGINT, sem_cleanup);
204 (void) sm_signal(SIGTERM, sem_cleanup);
205
206 delay(1, "parent: acquire 1");
207 cnt = 0;
208 do
209 {
210 r = sm_sem_acq(semid, 0, 0);
211 if (r < 0)
212 {
213 sleep(1);
214 ++cnt;
215 }
216 } while (r < 0 && cnt <= MAX_CNT);
217 SM_TEST(r >= 0);
218 if (r < 0)
219 return r;
220
221 delay(3, "parent: release 1");
222 cnt = 0;
223 do
224 {
225 r = sm_sem_rel(semid, 0, 0);
226 if (r < 0)
227 {
228 sleep(1);
229 ++cnt;
230 }
231 } while (r < 0 && cnt <= MAX_CNT);
232 SM_TEST(r >= 0);
233 if (r < 0)
234 return r;
235
236 delay(1, "parent: getval");
237 cnt = 0;
238 do
239 {
240 r = sm_sem_get(semid, 0);
241 if (r <= 0)
242 {
243 sleep(1);
244 ++cnt;
245 }
246 } while (r <= 0 && cnt <= MAX_CNT);
247 SM_TEST(r > 0);
248 if (r <= 0)
249 return r;
250
251 delay(1, "parent: acquire 2");
252 cnt = 0;
253 do
254 {
255 r = sm_sem_acq(semid, 0, 0);
256 if (r < 0)
257 {
258 sleep(1);
259 ++cnt;
260 }
261 } while (r < 0 && cnt <= MAX_CNT);
262 SM_TEST(r >= 0);
263 if (r < 0)
264 return r;
265
266 cnt = 0;
267 do
268 {
269 r = sm_sem_rel(semid, 0, 0);
270 if (r < 0)
271 {
272 sleep(1);
273 ++cnt;
274 }
275 } while (r < 0 && cnt <= MAX_CNT);
276 SM_TEST(r >= 0);
277 if (r < 0)
278 return r;
279 }
280 else
281 {
282 delay(1, "child: acquire 1");
283 cnt = 0;
284 do
285 {
286 r = sm_sem_acq(semid, 0, 0);
287 if (r < 0)
288 {
289 sleep(1);
290 ++cnt;
291 }
292 } while (r < 0 && cnt <= MAX_CNT);
293 SM_TEST(r >= 0);
294 if (r < 0)
295 return r;
296
297 delay(1, "child: release 1");
298 cnt = 0;
299 do
300 {
301 r = sm_sem_rel(semid, 0, 0);
302 if (r < 0)
303 {
304 sleep(1);
305 ++cnt;
306 }
307 } while (r < 0 && cnt <= MAX_CNT);
308 SM_TEST(r >= 0);
309 if (r < 0)
310 return r;
311
312 }
313 if (owner)
314 return sm_sem_stop(semid);
315 return 0;
316 }
317
318 int
main(argc,argv)319 main(argc, argv)
320 int argc;
321 char *argv[];
322 {
323 bool interactive = false;
324 bool owner = false;
325 int ch, r;
326 uid_t uid;
327 gid_t gid;
328
329 uid = 0;
330 gid = 0;
331 r = 0;
332
333 # define OPTIONS "iog:u:"
334 while ((ch = getopt(argc, argv, OPTIONS)) != -1)
335 {
336 switch ((char) ch)
337 {
338 case 'g':
339 gid = (gid_t)strtoul(optarg, 0, 0);
340 break;
341
342 case 'i':
343 interactive = true;
344 break;
345
346 case 'u':
347 uid = (uid_t)strtoul(optarg, 0, 0);
348 break;
349
350 case 'o':
351 owner = true;
352 break;
353
354 default:
355 break;
356 }
357 }
358
359 if (interactive)
360 r = seminter(owner);
361 else
362 {
363 pid_t pid;
364
365 printf("This test takes about 8 seconds.\n");
366 printf("If it takes longer than 30 seconds, please interrupt it\n");
367 printf("and compile again without semaphore support, i.e.,");
368 printf("-DSM_CONF_SEM=0\n");
369 if ((pid = fork()) < 0)
370 {
371 perror("fork failed\n");
372 return -1;
373 }
374
375 sm_test_begin(argc, argv, "test semaphores");
376 if (pid == 0)
377 {
378 /* give the parent the chance to setup data */
379 sleep(1);
380 r = semtest(false, uid, gid);
381 }
382 else
383 {
384 r = semtest(true, uid, gid);
385 }
386 SM_TEST(r == 0);
387 return sm_test_end();
388 }
389 return r;
390 }
391 #else /* SM_CONF_SEM */
392 int
393 main(argc, argv)
394 int argc;
395 char *argv[];
396 {
397 printf("No support for semaphores configured on this machine\n");
398 return 0;
399 }
400 #endif /* SM_CONF_SEM */
401