1147078Sgshapiro/*
2261194Sgshapiro * Copyright (c) 2000-2001, 2005, 2008 Proofpoint, 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>
11266527SgshapiroSM_RCSID("@(#)$Id: sem.c,v 1.15 2013-11-22 20:51:43 ca Exp $")
12147078Sgshapiro
13147078Sgshapiro#if SM_CONF_SEM
14147078Sgshapiro# include <stdlib.h>
15147078Sgshapiro# include <unistd.h>
16203004Sgshapiro# include <sm/string.h>
17147078Sgshapiro# include <sm/sem.h>
18147078Sgshapiro# include <sm/heap.h>
19157001Sgshapiro# include <errno.h>
20147078Sgshapiro
21147078Sgshapiro/*
22147078Sgshapiro**  SM_SEM_START -- initialize semaphores
23147078Sgshapiro**
24147078Sgshapiro**	Parameters:
25147078Sgshapiro**		key -- key for semaphores.
26147078Sgshapiro**		nsem -- number of semaphores.
27147078Sgshapiro**		semflg -- flag for semget(), if 0, use a default.
28147078Sgshapiro**		owner -- create semaphores.
29147078Sgshapiro**
30147078Sgshapiro**	Returns:
31147078Sgshapiro**		id for semaphores.
32147078Sgshapiro**		< 0 on failure.
33147078Sgshapiro*/
34147078Sgshapiro
35147078Sgshapiroint
36147078Sgshapirosm_sem_start(key, nsem, semflg, owner)
37147078Sgshapiro	key_t key;
38147078Sgshapiro	int nsem;
39147078Sgshapiro	int semflg;
40147078Sgshapiro	bool owner;
41147078Sgshapiro{
42157001Sgshapiro	int semid, i, err;
43147078Sgshapiro	unsigned short *semvals;
44147078Sgshapiro
45147078Sgshapiro	semvals = NULL;
46147078Sgshapiro	if (semflg == 0)
47147078Sgshapiro		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
48147078Sgshapiro	if (owner)
49147078Sgshapiro		semflg |= IPC_CREAT|IPC_EXCL;
50147078Sgshapiro	semid = semget(key, nsem, semflg);
51147078Sgshapiro	if (semid < 0)
52147078Sgshapiro		goto error;
53147078Sgshapiro
54147078Sgshapiro	if (owner)
55147078Sgshapiro	{
56147078Sgshapiro		union semun semarg;
57147078Sgshapiro
58147078Sgshapiro		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
59147078Sgshapiro		if (semvals == NULL)
60147078Sgshapiro			goto error;
61147078Sgshapiro		semarg.array = semvals;
62147078Sgshapiro
63147078Sgshapiro		/* initialize semaphore values to be available */
64147078Sgshapiro		for (i = 0; i < nsem; i++)
65147078Sgshapiro			semvals[i] = 1;
66147078Sgshapiro		if (semctl(semid, 0, SETALL, semarg) < 0)
67147078Sgshapiro			goto error;
68147078Sgshapiro	}
69147078Sgshapiro	return semid;
70147078Sgshapiro
71147078Sgshapiroerror:
72157001Sgshapiro	err = errno;
73147078Sgshapiro	if (semvals != NULL)
74147078Sgshapiro		sm_free(semvals);
75147078Sgshapiro	if (semid >= 0)
76147078Sgshapiro		sm_sem_stop(semid);
77157001Sgshapiro	return (err > 0) ? (0 - err) : -1;
78147078Sgshapiro}
79147078Sgshapiro
80147078Sgshapiro/*
81147078Sgshapiro**  SM_SEM_STOP -- stop using semaphores.
82147078Sgshapiro**
83147078Sgshapiro**	Parameters:
84147078Sgshapiro**		semid -- id for semaphores.
85147078Sgshapiro**
86147078Sgshapiro**	Returns:
87147078Sgshapiro**		0 on success.
88147078Sgshapiro**		< 0 on failure.
89147078Sgshapiro*/
90147078Sgshapiro
91147078Sgshapiroint
92147078Sgshapirosm_sem_stop(semid)
93147078Sgshapiro	int semid;
94147078Sgshapiro{
95147078Sgshapiro	return semctl(semid, 0, IPC_RMID, NULL);
96147078Sgshapiro}
97147078Sgshapiro
98147078Sgshapiro/*
99147078Sgshapiro**  SM_SEM_ACQ -- acquire semaphore.
100147078Sgshapiro**
101147078Sgshapiro**	Parameters:
102147078Sgshapiro**		semid -- id for semaphores.
103147078Sgshapiro**		semnum -- number of semaphore.
104147078Sgshapiro**		timeout -- how long to wait for operation to succeed.
105147078Sgshapiro**
106147078Sgshapiro**	Returns:
107147078Sgshapiro**		0 on success.
108147078Sgshapiro**		< 0 on failure.
109147078Sgshapiro*/
110147078Sgshapiro
111147078Sgshapiroint
112147078Sgshapirosm_sem_acq(semid, semnum, timeout)
113147078Sgshapiro	int semid;
114147078Sgshapiro	int semnum;
115147078Sgshapiro	int timeout;
116147078Sgshapiro{
117147078Sgshapiro	int r;
118147078Sgshapiro	struct sembuf semops[1];
119147078Sgshapiro
120147078Sgshapiro	semops[0].sem_num = semnum;
121147078Sgshapiro	semops[0].sem_op = -1;
122147078Sgshapiro	semops[0].sem_flg = SEM_UNDO |
123147078Sgshapiro			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
124147078Sgshapiro	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
125147078Sgshapiro		return semop(semid, semops, 1);
126147078Sgshapiro	do
127147078Sgshapiro	{
128147078Sgshapiro		r = semop(semid, semops, 1);
129147078Sgshapiro		if (r == 0)
130147078Sgshapiro			return r;
131147078Sgshapiro		sleep(1);
132147078Sgshapiro		--timeout;
133147078Sgshapiro	} while (timeout > 0);
134147078Sgshapiro	return r;
135147078Sgshapiro}
136147078Sgshapiro
137147078Sgshapiro/*
138147078Sgshapiro**  SM_SEM_REL -- release semaphore.
139147078Sgshapiro**
140147078Sgshapiro**	Parameters:
141147078Sgshapiro**		semid -- id for semaphores.
142147078Sgshapiro**		semnum -- number of semaphore.
143147078Sgshapiro**		timeout -- how long to wait for operation to succeed.
144147078Sgshapiro**
145147078Sgshapiro**	Returns:
146147078Sgshapiro**		0 on success.
147147078Sgshapiro**		< 0 on failure.
148147078Sgshapiro*/
149147078Sgshapiro
150147078Sgshapiroint
151147078Sgshapirosm_sem_rel(semid, semnum, timeout)
152147078Sgshapiro	int semid;
153147078Sgshapiro	int semnum;
154147078Sgshapiro	int timeout;
155147078Sgshapiro{
156147078Sgshapiro	int r;
157147078Sgshapiro	struct sembuf semops[1];
158147078Sgshapiro
159147078Sgshapiro#if PARANOID
160147078Sgshapiro	/* XXX should we check whether the value is already 0 ? */
161147078Sgshapiro	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
162147078Sgshapiro#endif /* PARANOID */
163147078Sgshapiro
164147078Sgshapiro	semops[0].sem_num = semnum;
165147078Sgshapiro	semops[0].sem_op = 1;
166147078Sgshapiro	semops[0].sem_flg = SEM_UNDO |
167147078Sgshapiro			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
168147078Sgshapiro	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
169147078Sgshapiro		return semop(semid, semops, 1);
170147078Sgshapiro	do
171147078Sgshapiro	{
172147078Sgshapiro		r = semop(semid, semops, 1);
173147078Sgshapiro		if (r == 0)
174147078Sgshapiro			return r;
175147078Sgshapiro		sleep(1);
176147078Sgshapiro		--timeout;
177147078Sgshapiro	} while (timeout > 0);
178147078Sgshapiro	return r;
179147078Sgshapiro}
180147078Sgshapiro
181147078Sgshapiro/*
182147078Sgshapiro**  SM_SEM_GET -- get semaphore value.
183147078Sgshapiro**
184147078Sgshapiro**	Parameters:
185147078Sgshapiro**		semid -- id for semaphores.
186147078Sgshapiro**		semnum -- number of semaphore.
187147078Sgshapiro**
188147078Sgshapiro**	Returns:
189147078Sgshapiro**		value of semaphore on success.
190147078Sgshapiro**		< 0 on failure.
191147078Sgshapiro*/
192147078Sgshapiro
193147078Sgshapiroint
194147078Sgshapirosm_sem_get(semid, semnum)
195147078Sgshapiro	int semid;
196147078Sgshapiro	int semnum;
197147078Sgshapiro{
198147078Sgshapiro	int semval;
199147078Sgshapiro
200147078Sgshapiro	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
201147078Sgshapiro		return -1;
202147078Sgshapiro	return semval;
203147078Sgshapiro}
204203004Sgshapiro
205203004Sgshapiro/*
206203004Sgshapiro**  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
207203004Sgshapiro**
208203004Sgshapiro**	Parameters:
209203004Sgshapiro**		semid -- id for semaphores.
210203004Sgshapiro**		uid -- uid to use
211203004Sgshapiro**		gid -- gid to use
212203004Sgshapiro**		mode -- mode to use
213203004Sgshapiro**
214203004Sgshapiro**	Returns:
215203004Sgshapiro**		0 on success.
216203004Sgshapiro**		< 0 on failure.
217203004Sgshapiro*/
218203004Sgshapiro
219203004Sgshapiroint
220203004Sgshapirosm_semsetowner(semid, uid, gid, mode)
221203004Sgshapiro	int semid;
222203004Sgshapiro	uid_t uid;
223203004Sgshapiro	gid_t gid;
224203004Sgshapiro	mode_t mode;
225203004Sgshapiro{
226203004Sgshapiro	int r;
227203004Sgshapiro	struct semid_ds	semidds;
228203004Sgshapiro	union semun {
229203004Sgshapiro		int		val;
230203004Sgshapiro		struct semid_ds	*buf;
231203004Sgshapiro		ushort		*array;
232203004Sgshapiro	} arg;
233203004Sgshapiro
234203004Sgshapiro	memset(&semidds, 0, sizeof(semidds));
235203004Sgshapiro	arg.buf = &semidds;
236203004Sgshapiro	if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
237203004Sgshapiro		return r;
238203004Sgshapiro	semidds.sem_perm.uid = uid;
239203004Sgshapiro	semidds.sem_perm.gid = gid;
240203004Sgshapiro	semidds.sem_perm.mode = mode;
241203004Sgshapiro	if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
242203004Sgshapiro		return r;
243203004Sgshapiro	return 0;
244203004Sgshapiro}
245147078Sgshapiro#endif /* SM_CONF_SEM */
246