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