]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/sendmail/libsm/t-sem.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / sendmail / libsm / t-sem.c
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
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
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
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
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
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 */