1147078Sgshapiro/*
2203004Sgshapiro * Copyright (c) 2000-2001, 2005-2008 Sendmail, Inc. and its suppliers.
3147078Sgshapiro *      All rights reserved.
4147078Sgshapiro *
5147078Sgshapiro * By using this file, you agree to the terms and conditions set
6147078Sgshapiro * forth in the LICENSE file which can be found at the top level of
7147078Sgshapiro * the sendmail distribution.
8147078Sgshapiro */
9147078Sgshapiro
10147078Sgshapiro#include <sm/gen.h>
11203004SgshapiroSM_RCSID("@(#)$Id: t-sem.c,v 1.17 2008/05/30 16:26:38 ca Exp $")
12147078Sgshapiro
13147078Sgshapiro#include <stdio.h>
14147078Sgshapiro
15147078Sgshapiro#if SM_CONF_SEM
16147078Sgshapiro# include <stdlib.h>
17147078Sgshapiro# include <unistd.h>
18147078Sgshapiro# include <sysexits.h>
19147078Sgshapiro# include <sm/heap.h>
20147078Sgshapiro# include <sm/string.h>
21147078Sgshapiro# include <sm/signal.h>
22147078Sgshapiro# include <sm/test.h>
23147078Sgshapiro# include <sm/sem.h>
24147078Sgshapiro
25168515Sgshapiro# define T_SM_SEM_KEY (4321L)
26168515Sgshapiro
27147078Sgshapirostatic void
28147078Sgshapirodelay(t, s)
29147078Sgshapiro	int t;
30147078Sgshapiro	char *s;
31147078Sgshapiro{
32147078Sgshapiro	if (t > 0)
33147078Sgshapiro	{
34147078Sgshapiro#if DEBUG
35147078Sgshapiro		fprintf(stderr, "sleep(%d) before %s\n", t, s);
36147078Sgshapiro#endif /* DEBUG */
37147078Sgshapiro		sleep(t);
38147078Sgshapiro	}
39147078Sgshapiro#if DEBUG
40147078Sgshapiro	fprintf(stderr, "%s\n", s);
41147078Sgshapiro#endif /* DEBUG */
42147078Sgshapiro}
43147078Sgshapiro
44147078Sgshapiro
45147078Sgshapiro/*
46147078Sgshapiro**  SEMINTER -- interactive testing of semaphores.
47147078Sgshapiro**
48147078Sgshapiro**	Parameters:
49147078Sgshapiro**		owner -- create semaphores.
50147078Sgshapiro**
51147078Sgshapiro**	Returns:
52147078Sgshapiro**		0 on success
53147078Sgshapiro**		< 0 on failure.
54147078Sgshapiro*/
55147078Sgshapiro
56147078Sgshapirostatic int
57147078Sgshapiroseminter(owner)
58147078Sgshapiro	bool owner;
59147078Sgshapiro{
60147078Sgshapiro	int semid;
61147078Sgshapiro	int t;
62147078Sgshapiro
63168515Sgshapiro	semid = sm_sem_start(T_SM_SEM_KEY, SM_NSEM, 0, owner);
64147078Sgshapiro	if (semid < 0)
65147078Sgshapiro	{
66147078Sgshapiro		perror("sm_sem_start failed");
67147078Sgshapiro		return 1;
68147078Sgshapiro	}
69147078Sgshapiro
70147078Sgshapiro	while ((t = getchar()) != EOF)
71147078Sgshapiro	{
72147078Sgshapiro		switch (t)
73147078Sgshapiro		{
74147078Sgshapiro		  case 'a':
75147078Sgshapiro			delay(0, "try to acq");
76147078Sgshapiro			if (sm_sem_acq(semid, 0, 2) < 0)
77147078Sgshapiro			{
78147078Sgshapiro				perror("sm_sem_acq failed");
79147078Sgshapiro				return 1;
80147078Sgshapiro			}
81147078Sgshapiro			delay(0, "acquired");
82147078Sgshapiro			break;
83147078Sgshapiro
84147078Sgshapiro		  case 'r':
85147078Sgshapiro			delay(0, "try to rel");
86147078Sgshapiro			if (sm_sem_rel(semid, 0, 2) < 0)
87147078Sgshapiro			{
88147078Sgshapiro				perror("sm_sem_rel failed");
89147078Sgshapiro				return 1;
90147078Sgshapiro			}
91147078Sgshapiro			delay(0, "released");
92147078Sgshapiro			break;
93147078Sgshapiro
94147078Sgshapiro		  case 'v':
95147078Sgshapiro			if ((t = sm_sem_get(semid, 0)) < 0)
96147078Sgshapiro			{
97147078Sgshapiro				perror("get_sem failed");
98147078Sgshapiro				return 1;
99147078Sgshapiro			}
100147078Sgshapiro			printf("semval: %d\n", t);
101147078Sgshapiro			break;
102147078Sgshapiro
103147078Sgshapiro		}
104147078Sgshapiro	}
105147078Sgshapiro	if (owner)
106147078Sgshapiro		return sm_sem_stop(semid);
107147078Sgshapiro	return 0;
108147078Sgshapiro}
109147078Sgshapiro
110147078Sgshapiro/*
111147078Sgshapiro**  SEM_CLEANUP -- cleanup if something breaks
112147078Sgshapiro**
113147078Sgshapiro**	Parameters:
114147078Sgshapiro**		sig -- signal.
115147078Sgshapiro**
116147078Sgshapiro**	Returns:
117147078Sgshapiro**		none.
118147078Sgshapiro*/
119147078Sgshapiro
120147078Sgshapirostatic int semid_c = -1;
121147078Sgshapirovoid
122147078Sgshapirosem_cleanup(sig)
123147078Sgshapiro	int sig;
124147078Sgshapiro{
125147078Sgshapiro	if (semid_c >= 0)
126147078Sgshapiro		(void) sm_sem_stop(semid_c);
127147078Sgshapiro	exit(EX_UNAVAILABLE);
128147078Sgshapiro}
129147078Sgshapiro
130203004Sgshapirostatic int
131203004Sgshapirodrop_priv(uid, gid)
132203004Sgshapiro	uid_t uid;
133203004Sgshapiro	gid_t gid;
134203004Sgshapiro{
135203004Sgshapiro	int r;
136203004Sgshapiro
137203004Sgshapiro	r = setgid(gid);
138203004Sgshapiro	if (r != 0)
139203004Sgshapiro		return r;
140203004Sgshapiro	r = setuid(uid);
141203004Sgshapiro	return r;
142203004Sgshapiro}
143203004Sgshapiro
144147078Sgshapiro/*
145147078Sgshapiro**  SEMTEST -- test of semaphores
146147078Sgshapiro**
147147078Sgshapiro**	Parameters:
148147078Sgshapiro**		owner -- create semaphores.
149147078Sgshapiro**
150147078Sgshapiro**	Returns:
151147078Sgshapiro**		0 on success
152147078Sgshapiro**		< 0 on failure.
153147078Sgshapiro*/
154147078Sgshapiro
155147078Sgshapiro# define MAX_CNT	10
156147078Sgshapiro
157147078Sgshapirostatic int
158203004Sgshapirosemtest(owner, uid, gid)
159147078Sgshapiro	int owner;
160203004Sgshapiro	uid_t uid;
161203004Sgshapiro	gid_t gid;
162147078Sgshapiro{
163147078Sgshapiro	int semid, r;
164147078Sgshapiro	int cnt = 0;
165147078Sgshapiro
166203004Sgshapiro	if (!owner && uid != 0)
167203004Sgshapiro	{
168203004Sgshapiro		r = drop_priv(uid, gid);
169203004Sgshapiro		if (r < 0)
170203004Sgshapiro		{
171203004Sgshapiro			perror("drop_priv child failed");
172203004Sgshapiro			return -1;
173203004Sgshapiro		}
174203004Sgshapiro	}
175168515Sgshapiro	semid = sm_sem_start(T_SM_SEM_KEY, 1, 0, owner);
176147078Sgshapiro	if (semid < 0)
177147078Sgshapiro	{
178147078Sgshapiro		perror("sm_sem_start failed");
179147078Sgshapiro		return -1;
180147078Sgshapiro	}
181147078Sgshapiro
182147078Sgshapiro	if (owner)
183147078Sgshapiro	{
184203004Sgshapiro		if (uid != 0)
185203004Sgshapiro		{
186203004Sgshapiro			r = sm_semsetowner(semid, uid, gid, 0660);
187203004Sgshapiro			if (r < 0)
188203004Sgshapiro			{
189203004Sgshapiro				perror("sm_semsetowner failed");
190203004Sgshapiro				return -1;
191203004Sgshapiro			}
192203004Sgshapiro			r = drop_priv(uid, gid);
193203004Sgshapiro			if (r < 0)
194203004Sgshapiro			{
195203004Sgshapiro				perror("drop_priv owner failed");
196203004Sgshapiro				return -1;
197203004Sgshapiro			}
198203004Sgshapiro		}
199203004Sgshapiro
200147078Sgshapiro		/* just in case someone kills the program... */
201147078Sgshapiro		semid_c = semid;
202147078Sgshapiro		(void) sm_signal(SIGHUP, sem_cleanup);
203147078Sgshapiro		(void) sm_signal(SIGINT, sem_cleanup);
204147078Sgshapiro		(void) sm_signal(SIGTERM, sem_cleanup);
205147078Sgshapiro
206147078Sgshapiro		delay(1, "parent: acquire 1");
207147078Sgshapiro		cnt = 0;
208147078Sgshapiro		do
209147078Sgshapiro		{
210147078Sgshapiro			r = sm_sem_acq(semid, 0, 0);
211147078Sgshapiro			if (r < 0)
212147078Sgshapiro			{
213147078Sgshapiro				sleep(1);
214147078Sgshapiro				++cnt;
215147078Sgshapiro			}
216147078Sgshapiro		} while (r < 0 && cnt <= MAX_CNT);
217147078Sgshapiro		SM_TEST(r >= 0);
218147078Sgshapiro		if (r < 0)
219147078Sgshapiro			return r;
220147078Sgshapiro
221147078Sgshapiro		delay(3, "parent: release 1");
222147078Sgshapiro		cnt = 0;
223147078Sgshapiro		do
224147078Sgshapiro		{
225147078Sgshapiro			r = sm_sem_rel(semid, 0, 0);
226147078Sgshapiro			if (r < 0)
227147078Sgshapiro			{
228147078Sgshapiro				sleep(1);
229147078Sgshapiro				++cnt;
230147078Sgshapiro			}
231147078Sgshapiro		} while (r < 0 && cnt <= MAX_CNT);
232147078Sgshapiro		SM_TEST(r >= 0);
233147078Sgshapiro		if (r < 0)
234147078Sgshapiro			return r;
235147078Sgshapiro
236147078Sgshapiro		delay(1, "parent: getval");
237147078Sgshapiro		cnt = 0;
238147078Sgshapiro		do
239147078Sgshapiro		{
240147078Sgshapiro			r = sm_sem_get(semid, 0);
241147078Sgshapiro			if (r <= 0)
242147078Sgshapiro			{
243147078Sgshapiro				sleep(1);
244147078Sgshapiro				++cnt;
245147078Sgshapiro			}
246147078Sgshapiro		} while (r <= 0 && cnt <= MAX_CNT);
247147078Sgshapiro		SM_TEST(r > 0);
248147078Sgshapiro		if (r <= 0)
249147078Sgshapiro			return r;
250147078Sgshapiro
251147078Sgshapiro		delay(1, "parent: acquire 2");
252147078Sgshapiro		cnt = 0;
253147078Sgshapiro		do
254147078Sgshapiro		{
255147078Sgshapiro			r = sm_sem_acq(semid, 0, 0);
256147078Sgshapiro			if (r < 0)
257147078Sgshapiro			{
258147078Sgshapiro				sleep(1);
259147078Sgshapiro				++cnt;
260147078Sgshapiro			}
261147078Sgshapiro		} while (r < 0 && cnt <= MAX_CNT);
262147078Sgshapiro		SM_TEST(r >= 0);
263147078Sgshapiro		if (r < 0)
264147078Sgshapiro			return r;
265147078Sgshapiro
266147078Sgshapiro		cnt = 0;
267147078Sgshapiro		do
268147078Sgshapiro		{
269147078Sgshapiro			r = sm_sem_rel(semid, 0, 0);
270147078Sgshapiro			if (r < 0)
271147078Sgshapiro			{
272147078Sgshapiro				sleep(1);
273147078Sgshapiro				++cnt;
274147078Sgshapiro			}
275147078Sgshapiro		} while (r < 0 && cnt <= MAX_CNT);
276147078Sgshapiro		SM_TEST(r >= 0);
277147078Sgshapiro		if (r < 0)
278147078Sgshapiro			return r;
279147078Sgshapiro	}
280147078Sgshapiro	else
281147078Sgshapiro	{
282147078Sgshapiro		delay(1, "child: acquire 1");
283147078Sgshapiro		cnt = 0;
284147078Sgshapiro		do
285147078Sgshapiro		{
286147078Sgshapiro			r = sm_sem_acq(semid, 0, 0);
287147078Sgshapiro			if (r < 0)
288147078Sgshapiro			{
289147078Sgshapiro				sleep(1);
290147078Sgshapiro				++cnt;
291147078Sgshapiro			}
292147078Sgshapiro		} while (r < 0 && cnt <= MAX_CNT);
293147078Sgshapiro		SM_TEST(r >= 0);
294147078Sgshapiro		if (r < 0)
295147078Sgshapiro			return r;
296147078Sgshapiro
297147078Sgshapiro		delay(1, "child: release 1");
298147078Sgshapiro		cnt = 0;
299147078Sgshapiro		do
300147078Sgshapiro		{
301147078Sgshapiro			r = sm_sem_rel(semid, 0, 0);
302147078Sgshapiro			if (r < 0)
303147078Sgshapiro			{
304147078Sgshapiro				sleep(1);
305147078Sgshapiro				++cnt;
306147078Sgshapiro			}
307147078Sgshapiro		} while (r < 0 && cnt <= MAX_CNT);
308147078Sgshapiro		SM_TEST(r >= 0);
309147078Sgshapiro		if (r < 0)
310147078Sgshapiro			return r;
311147078Sgshapiro
312147078Sgshapiro	}
313147078Sgshapiro	if (owner)
314147078Sgshapiro		return sm_sem_stop(semid);
315147078Sgshapiro	return 0;
316147078Sgshapiro}
317147078Sgshapiro
318147078Sgshapiroint
319147078Sgshapiromain(argc, argv)
320147078Sgshapiro	int argc;
321147078Sgshapiro	char *argv[];
322147078Sgshapiro{
323147078Sgshapiro	bool interactive = false;
324147078Sgshapiro	bool owner = false;
325203004Sgshapiro	int ch, r;
326203004Sgshapiro	uid_t uid;
327203004Sgshapiro	gid_t gid;
328147078Sgshapiro
329203004Sgshapiro	uid = 0;
330203004Sgshapiro	gid = 0;
331203004Sgshapiro	r = 0;
332203004Sgshapiro
333203004Sgshapiro# define OPTIONS	"iog:u:"
334147078Sgshapiro	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
335147078Sgshapiro	{
336147078Sgshapiro		switch ((char) ch)
337147078Sgshapiro		{
338203004Sgshapiro		  case 'g':
339203004Sgshapiro			gid = (gid_t)strtoul(optarg, 0, 0);
340203004Sgshapiro			break;
341203004Sgshapiro
342147078Sgshapiro		  case 'i':
343147078Sgshapiro			interactive = true;
344147078Sgshapiro			break;
345147078Sgshapiro
346203004Sgshapiro		  case 'u':
347203004Sgshapiro			uid = (uid_t)strtoul(optarg, 0, 0);
348203004Sgshapiro			break;
349203004Sgshapiro
350147078Sgshapiro		  case 'o':
351147078Sgshapiro			owner = true;
352147078Sgshapiro			break;
353147078Sgshapiro
354147078Sgshapiro		  default:
355147078Sgshapiro			break;
356147078Sgshapiro		}
357147078Sgshapiro	}
358147078Sgshapiro
359147078Sgshapiro	if (interactive)
360147078Sgshapiro		r = seminter(owner);
361147078Sgshapiro	else
362147078Sgshapiro	{
363147078Sgshapiro		pid_t pid;
364147078Sgshapiro
365147078Sgshapiro		printf("This test takes about 8 seconds.\n");
366157001Sgshapiro		printf("If it takes longer than 30 seconds, please interrupt it\n");
367147078Sgshapiro		printf("and compile again without semaphore support, i.e.,");
368147078Sgshapiro		printf("-DSM_CONF_SEM=0\n");
369147078Sgshapiro		if ((pid = fork()) < 0)
370147078Sgshapiro		{
371147078Sgshapiro			perror("fork failed\n");
372147078Sgshapiro			return -1;
373147078Sgshapiro		}
374147078Sgshapiro
375147078Sgshapiro		sm_test_begin(argc, argv, "test semaphores");
376147078Sgshapiro		if (pid == 0)
377147078Sgshapiro		{
378147078Sgshapiro			/* give the parent the chance to setup data */
379147078Sgshapiro			sleep(1);
380203004Sgshapiro			r = semtest(false, uid, gid);
381147078Sgshapiro		}
382147078Sgshapiro		else
383147078Sgshapiro		{
384203004Sgshapiro			r = semtest(true, uid, gid);
385147078Sgshapiro		}
386147078Sgshapiro		SM_TEST(r == 0);
387147078Sgshapiro		return sm_test_end();
388147078Sgshapiro	}
389147078Sgshapiro	return r;
390147078Sgshapiro}
391147078Sgshapiro#else /* SM_CONF_SEM */
392147078Sgshapiroint
393147078Sgshapiromain(argc, argv)
394147078Sgshapiro	int argc;
395147078Sgshapiro	char *argv[];
396147078Sgshapiro{
397147078Sgshapiro	printf("No support for semaphores configured on this machine\n");
398147078Sgshapiro	return 0;
399147078Sgshapiro}
400147078Sgshapiro#endif /* SM_CONF_SEM */
401