xref: /freebsd/contrib/sendmail/libsm/sem.c (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
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: sem.c,v 1.15 2013-11-22 20:51:43 ca Exp $")
12 
13 #if SM_CONF_SEM
14 # include <stdlib.h>
15 # include <unistd.h>
16 # include <errno.h>
17 # include <sm/string.h>
18 # include <sm/heap.h>
19 # include <sm/conf.h>
20 # include <sm/sem.h>
21 
22 /*
23 **  SM_SEM_START -- initialize semaphores
24 **
25 **	Parameters:
26 **		key -- key for semaphores.
27 **		nsem -- number of semaphores.
28 **		semflg -- flag for semget(), if 0, use a default.
29 **		owner -- create semaphores.
30 **
31 **	Returns:
32 **		id for semaphores.
33 **		< 0 on failure.
34 */
35 
36 int
37 sm_sem_start(key, nsem, semflg, owner)
38 	key_t key;
39 	int nsem;
40 	int semflg;
41 	bool owner;
42 {
43 	int semid, i, err;
44 	unsigned short *semvals;
45 
46 	semvals = NULL;
47 	if (semflg == 0)
48 		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
49 	if (owner)
50 		semflg |= IPC_CREAT|IPC_EXCL;
51 	semid = semget(key, nsem, semflg);
52 	if (semid < 0)
53 		goto error;
54 
55 	if (owner)
56 	{
57 		union semun semarg;
58 
59 		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
60 		if (semvals == NULL)
61 			goto error;
62 		semarg.array = semvals;
63 
64 		/* initialize semaphore values to be available */
65 		for (i = 0; i < nsem; i++)
66 			semvals[i] = 1;
67 		if (semctl(semid, 0, SETALL, semarg) < 0)
68 			goto error;
69 	}
70 	return semid;
71 
72 error:
73 	err = errno;
74 	if (semvals != NULL)
75 		sm_free(semvals);
76 	if (semid >= 0)
77 		sm_sem_stop(semid);
78 	return (err > 0) ? (0 - err) : -1;
79 }
80 
81 /*
82 **  SM_SEM_STOP -- stop using semaphores.
83 **
84 **	Parameters:
85 **		semid -- id for semaphores.
86 **
87 **	Returns:
88 **		0 on success.
89 **		< 0 on failure.
90 */
91 
92 int
93 sm_sem_stop(semid)
94 	int semid;
95 {
96 	return semctl(semid, 0, IPC_RMID, NULL);
97 }
98 
99 /*
100 **  SM_SEM_ACQ -- acquire semaphore.
101 **
102 **	Parameters:
103 **		semid -- id for semaphores.
104 **		semnum -- number of semaphore.
105 **		timeout -- how long to wait for operation to succeed.
106 **
107 **	Returns:
108 **		0 on success.
109 **		< 0 on failure.
110 */
111 
112 int
113 sm_sem_acq(semid, semnum, timeout)
114 	int semid;
115 	int semnum;
116 	int timeout;
117 {
118 	int r;
119 	struct sembuf semops[1];
120 
121 	semops[0].sem_num = semnum;
122 	semops[0].sem_op = -1;
123 	semops[0].sem_flg = SEM_UNDO |
124 			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
125 	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
126 		return semop(semid, semops, 1);
127 	do
128 	{
129 		r = semop(semid, semops, 1);
130 		if (r == 0)
131 			return r;
132 		sleep(1);
133 		--timeout;
134 	} while (timeout > 0);
135 	return r;
136 }
137 
138 /*
139 **  SM_SEM_REL -- release semaphore.
140 **
141 **	Parameters:
142 **		semid -- id for semaphores.
143 **		semnum -- number of semaphore.
144 **		timeout -- how long to wait for operation to succeed.
145 **
146 **	Returns:
147 **		0 on success.
148 **		< 0 on failure.
149 */
150 
151 int
152 sm_sem_rel(semid, semnum, timeout)
153 	int semid;
154 	int semnum;
155 	int timeout;
156 {
157 	int r;
158 	struct sembuf semops[1];
159 
160 # if PARANOID
161 	/* XXX should we check whether the value is already 0 ? */
162 	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
163 # endif
164 
165 	semops[0].sem_num = semnum;
166 	semops[0].sem_op = 1;
167 	semops[0].sem_flg = SEM_UNDO |
168 			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
169 	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
170 		return semop(semid, semops, 1);
171 	do
172 	{
173 		r = semop(semid, semops, 1);
174 		if (r == 0)
175 			return r;
176 		sleep(1);
177 		--timeout;
178 	} while (timeout > 0);
179 	return r;
180 }
181 
182 /*
183 **  SM_SEM_GET -- get semaphore value.
184 **
185 **	Parameters:
186 **		semid -- id for semaphores.
187 **		semnum -- number of semaphore.
188 **
189 **	Returns:
190 **		value of semaphore on success.
191 **		< 0 on failure.
192 */
193 
194 int
195 sm_sem_get(semid, semnum)
196 	int semid;
197 	int semnum;
198 {
199 	int semval;
200 
201 	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
202 		return -1;
203 	return semval;
204 }
205 
206 /*
207 **  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
208 **
209 **	Parameters:
210 **		semid -- id for semaphores.
211 **		uid -- uid to use
212 **		gid -- gid to use
213 **		mode -- mode to use
214 **
215 **	Returns:
216 **		0 on success.
217 **		< 0 on failure.
218 */
219 
220 #ifdef __STDC__
221 int
222 sm_semsetowner(int semid, uid_t uid, gid_t gid, MODE_T mode)
223 #else /* __STDC__ */
224 int
225 sm_semsetowner(semid, uid, gid, mode)
226 	int semid;
227 	uid_t uid;
228 	gid_t gid;
229 	MODE_T mode;
230 #endif /* __STDC__ */
231 {
232 	int r;
233 	struct semid_ds	semidds;
234 	union semun {
235 		int		val;
236 		struct semid_ds	*buf;
237 		ushort		*array;
238 	} arg;
239 
240 	memset(&semidds, 0, sizeof(semidds));
241 	arg.buf = &semidds;
242 	if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
243 		return r;
244 	semidds.sem_perm.uid = uid;
245 	semidds.sem_perm.gid = gid;
246 	semidds.sem_perm.mode = mode;
247 	if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
248 		return r;
249 	return 0;
250 }
251 #endif /* SM_CONF_SEM */
252