xref: /freebsd/contrib/sendmail/libsm/sem.c (revision 2fb4f839f3fc72ce2bab12f9ba4760f97f73e97f)
113d88268SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 2000-2001, 2005, 2008 Proofpoint, Inc. and its suppliers.
313d88268SGregory Neil Shapiro  *      All rights reserved.
413d88268SGregory Neil Shapiro  *
513d88268SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
613d88268SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
713d88268SGregory Neil Shapiro  * the sendmail distribution.
813d88268SGregory Neil Shapiro  */
913d88268SGregory Neil Shapiro 
1013d88268SGregory Neil Shapiro #include <sm/gen.h>
114313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: sem.c,v 1.15 2013-11-22 20:51:43 ca Exp $")
1213d88268SGregory Neil Shapiro 
1313d88268SGregory Neil Shapiro #if SM_CONF_SEM
1413d88268SGregory Neil Shapiro # include <stdlib.h>
1513d88268SGregory Neil Shapiro # include <unistd.h>
164e4196cbSGregory Neil Shapiro # include <errno.h>
17*2fb4f839SGregory Neil Shapiro # include <sm/string.h>
18*2fb4f839SGregory Neil Shapiro # include <sm/heap.h>
19*2fb4f839SGregory Neil Shapiro # include <sm/conf.h>
20*2fb4f839SGregory Neil Shapiro # include <sm/sem.h>
2113d88268SGregory Neil Shapiro 
2213d88268SGregory Neil Shapiro /*
2313d88268SGregory Neil Shapiro **  SM_SEM_START -- initialize semaphores
2413d88268SGregory Neil Shapiro **
2513d88268SGregory Neil Shapiro **	Parameters:
2613d88268SGregory Neil Shapiro **		key -- key for semaphores.
2713d88268SGregory Neil Shapiro **		nsem -- number of semaphores.
2813d88268SGregory Neil Shapiro **		semflg -- flag for semget(), if 0, use a default.
2913d88268SGregory Neil Shapiro **		owner -- create semaphores.
3013d88268SGregory Neil Shapiro **
3113d88268SGregory Neil Shapiro **	Returns:
3213d88268SGregory Neil Shapiro **		id for semaphores.
3313d88268SGregory Neil Shapiro **		< 0 on failure.
3413d88268SGregory Neil Shapiro */
3513d88268SGregory Neil Shapiro 
3613d88268SGregory Neil Shapiro int
3713d88268SGregory Neil Shapiro sm_sem_start(key, nsem, semflg, owner)
3813d88268SGregory Neil Shapiro 	key_t key;
3913d88268SGregory Neil Shapiro 	int nsem;
4013d88268SGregory Neil Shapiro 	int semflg;
4113d88268SGregory Neil Shapiro 	bool owner;
4213d88268SGregory Neil Shapiro {
434e4196cbSGregory Neil Shapiro 	int semid, i, err;
4413d88268SGregory Neil Shapiro 	unsigned short *semvals;
4513d88268SGregory Neil Shapiro 
4613d88268SGregory Neil Shapiro 	semvals = NULL;
4713d88268SGregory Neil Shapiro 	if (semflg == 0)
4813d88268SGregory Neil Shapiro 		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
4913d88268SGregory Neil Shapiro 	if (owner)
5013d88268SGregory Neil Shapiro 		semflg |= IPC_CREAT|IPC_EXCL;
5113d88268SGregory Neil Shapiro 	semid = semget(key, nsem, semflg);
5213d88268SGregory Neil Shapiro 	if (semid < 0)
5313d88268SGregory Neil Shapiro 		goto error;
5413d88268SGregory Neil Shapiro 
5513d88268SGregory Neil Shapiro 	if (owner)
5613d88268SGregory Neil Shapiro 	{
5713d88268SGregory Neil Shapiro 		union semun semarg;
5813d88268SGregory Neil Shapiro 
5913d88268SGregory Neil Shapiro 		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
6013d88268SGregory Neil Shapiro 		if (semvals == NULL)
6113d88268SGregory Neil Shapiro 			goto error;
6213d88268SGregory Neil Shapiro 		semarg.array = semvals;
6313d88268SGregory Neil Shapiro 
6413d88268SGregory Neil Shapiro 		/* initialize semaphore values to be available */
6513d88268SGregory Neil Shapiro 		for (i = 0; i < nsem; i++)
6613d88268SGregory Neil Shapiro 			semvals[i] = 1;
6713d88268SGregory Neil Shapiro 		if (semctl(semid, 0, SETALL, semarg) < 0)
6813d88268SGregory Neil Shapiro 			goto error;
6913d88268SGregory Neil Shapiro 	}
7013d88268SGregory Neil Shapiro 	return semid;
7113d88268SGregory Neil Shapiro 
7213d88268SGregory Neil Shapiro error:
734e4196cbSGregory Neil Shapiro 	err = errno;
7413d88268SGregory Neil Shapiro 	if (semvals != NULL)
7513d88268SGregory Neil Shapiro 		sm_free(semvals);
7613d88268SGregory Neil Shapiro 	if (semid >= 0)
7713d88268SGregory Neil Shapiro 		sm_sem_stop(semid);
784e4196cbSGregory Neil Shapiro 	return (err > 0) ? (0 - err) : -1;
7913d88268SGregory Neil Shapiro }
8013d88268SGregory Neil Shapiro 
8113d88268SGregory Neil Shapiro /*
8213d88268SGregory Neil Shapiro **  SM_SEM_STOP -- stop using semaphores.
8313d88268SGregory Neil Shapiro **
8413d88268SGregory Neil Shapiro **	Parameters:
8513d88268SGregory Neil Shapiro **		semid -- id for semaphores.
8613d88268SGregory Neil Shapiro **
8713d88268SGregory Neil Shapiro **	Returns:
8813d88268SGregory Neil Shapiro **		0 on success.
8913d88268SGregory Neil Shapiro **		< 0 on failure.
9013d88268SGregory Neil Shapiro */
9113d88268SGregory Neil Shapiro 
9213d88268SGregory Neil Shapiro int
sm_sem_stop(semid)9313d88268SGregory Neil Shapiro sm_sem_stop(semid)
9413d88268SGregory Neil Shapiro 	int semid;
9513d88268SGregory Neil Shapiro {
9613d88268SGregory Neil Shapiro 	return semctl(semid, 0, IPC_RMID, NULL);
9713d88268SGregory Neil Shapiro }
9813d88268SGregory Neil Shapiro 
9913d88268SGregory Neil Shapiro /*
10013d88268SGregory Neil Shapiro **  SM_SEM_ACQ -- acquire semaphore.
10113d88268SGregory Neil Shapiro **
10213d88268SGregory Neil Shapiro **	Parameters:
10313d88268SGregory Neil Shapiro **		semid -- id for semaphores.
10413d88268SGregory Neil Shapiro **		semnum -- number of semaphore.
10513d88268SGregory Neil Shapiro **		timeout -- how long to wait for operation to succeed.
10613d88268SGregory Neil Shapiro **
10713d88268SGregory Neil Shapiro **	Returns:
10813d88268SGregory Neil Shapiro **		0 on success.
10913d88268SGregory Neil Shapiro **		< 0 on failure.
11013d88268SGregory Neil Shapiro */
11113d88268SGregory Neil Shapiro 
11213d88268SGregory Neil Shapiro int
sm_sem_acq(semid,semnum,timeout)11313d88268SGregory Neil Shapiro sm_sem_acq(semid, semnum, timeout)
11413d88268SGregory Neil Shapiro 	int semid;
11513d88268SGregory Neil Shapiro 	int semnum;
11613d88268SGregory Neil Shapiro 	int timeout;
11713d88268SGregory Neil Shapiro {
11813d88268SGregory Neil Shapiro 	int r;
11913d88268SGregory Neil Shapiro 	struct sembuf semops[1];
12013d88268SGregory Neil Shapiro 
12113d88268SGregory Neil Shapiro 	semops[0].sem_num = semnum;
12213d88268SGregory Neil Shapiro 	semops[0].sem_op = -1;
12313d88268SGregory Neil Shapiro 	semops[0].sem_flg = SEM_UNDO |
12413d88268SGregory Neil Shapiro 			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
12513d88268SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
12613d88268SGregory Neil Shapiro 		return semop(semid, semops, 1);
12713d88268SGregory Neil Shapiro 	do
12813d88268SGregory Neil Shapiro 	{
12913d88268SGregory Neil Shapiro 		r = semop(semid, semops, 1);
13013d88268SGregory Neil Shapiro 		if (r == 0)
13113d88268SGregory Neil Shapiro 			return r;
13213d88268SGregory Neil Shapiro 		sleep(1);
13313d88268SGregory Neil Shapiro 		--timeout;
13413d88268SGregory Neil Shapiro 	} while (timeout > 0);
13513d88268SGregory Neil Shapiro 	return r;
13613d88268SGregory Neil Shapiro }
13713d88268SGregory Neil Shapiro 
13813d88268SGregory Neil Shapiro /*
13913d88268SGregory Neil Shapiro **  SM_SEM_REL -- release semaphore.
14013d88268SGregory Neil Shapiro **
14113d88268SGregory Neil Shapiro **	Parameters:
14213d88268SGregory Neil Shapiro **		semid -- id for semaphores.
14313d88268SGregory Neil Shapiro **		semnum -- number of semaphore.
14413d88268SGregory Neil Shapiro **		timeout -- how long to wait for operation to succeed.
14513d88268SGregory Neil Shapiro **
14613d88268SGregory Neil Shapiro **	Returns:
14713d88268SGregory Neil Shapiro **		0 on success.
14813d88268SGregory Neil Shapiro **		< 0 on failure.
14913d88268SGregory Neil Shapiro */
15013d88268SGregory Neil Shapiro 
15113d88268SGregory Neil Shapiro int
sm_sem_rel(semid,semnum,timeout)15213d88268SGregory Neil Shapiro sm_sem_rel(semid, semnum, timeout)
15313d88268SGregory Neil Shapiro 	int semid;
15413d88268SGregory Neil Shapiro 	int semnum;
15513d88268SGregory Neil Shapiro 	int timeout;
15613d88268SGregory Neil Shapiro {
15713d88268SGregory Neil Shapiro 	int r;
15813d88268SGregory Neil Shapiro 	struct sembuf semops[1];
15913d88268SGregory Neil Shapiro 
16013d88268SGregory Neil Shapiro # if PARANOID
16113d88268SGregory Neil Shapiro 	/* XXX should we check whether the value is already 0 ? */
16213d88268SGregory Neil Shapiro 	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
1635b0945b5SGregory Neil Shapiro # endif
16413d88268SGregory Neil Shapiro 
16513d88268SGregory Neil Shapiro 	semops[0].sem_num = semnum;
16613d88268SGregory Neil Shapiro 	semops[0].sem_op = 1;
16713d88268SGregory Neil Shapiro 	semops[0].sem_flg = SEM_UNDO |
16813d88268SGregory Neil Shapiro 			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
16913d88268SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
17013d88268SGregory Neil Shapiro 		return semop(semid, semops, 1);
17113d88268SGregory Neil Shapiro 	do
17213d88268SGregory Neil Shapiro 	{
17313d88268SGregory Neil Shapiro 		r = semop(semid, semops, 1);
17413d88268SGregory Neil Shapiro 		if (r == 0)
17513d88268SGregory Neil Shapiro 			return r;
17613d88268SGregory Neil Shapiro 		sleep(1);
17713d88268SGregory Neil Shapiro 		--timeout;
17813d88268SGregory Neil Shapiro 	} while (timeout > 0);
17913d88268SGregory Neil Shapiro 	return r;
18013d88268SGregory Neil Shapiro }
18113d88268SGregory Neil Shapiro 
18213d88268SGregory Neil Shapiro /*
18313d88268SGregory Neil Shapiro **  SM_SEM_GET -- get semaphore value.
18413d88268SGregory Neil Shapiro **
18513d88268SGregory Neil Shapiro **	Parameters:
18613d88268SGregory Neil Shapiro **		semid -- id for semaphores.
18713d88268SGregory Neil Shapiro **		semnum -- number of semaphore.
18813d88268SGregory Neil Shapiro **
18913d88268SGregory Neil Shapiro **	Returns:
19013d88268SGregory Neil Shapiro **		value of semaphore on success.
19113d88268SGregory Neil Shapiro **		< 0 on failure.
19213d88268SGregory Neil Shapiro */
19313d88268SGregory Neil Shapiro 
19413d88268SGregory Neil Shapiro int
sm_sem_get(semid,semnum)19513d88268SGregory Neil Shapiro sm_sem_get(semid, semnum)
19613d88268SGregory Neil Shapiro 	int semid;
19713d88268SGregory Neil Shapiro 	int semnum;
19813d88268SGregory Neil Shapiro {
19913d88268SGregory Neil Shapiro 	int semval;
20013d88268SGregory Neil Shapiro 
20113d88268SGregory Neil Shapiro 	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
20213d88268SGregory Neil Shapiro 		return -1;
20313d88268SGregory Neil Shapiro 	return semval;
20413d88268SGregory Neil Shapiro }
2059bd497b8SGregory Neil Shapiro 
2069bd497b8SGregory Neil Shapiro /*
2079bd497b8SGregory Neil Shapiro **  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
2089bd497b8SGregory Neil Shapiro **
2099bd497b8SGregory Neil Shapiro **	Parameters:
2109bd497b8SGregory Neil Shapiro **		semid -- id for semaphores.
2119bd497b8SGregory Neil Shapiro **		uid -- uid to use
2129bd497b8SGregory Neil Shapiro **		gid -- gid to use
2139bd497b8SGregory Neil Shapiro **		mode -- mode to use
2149bd497b8SGregory Neil Shapiro **
2159bd497b8SGregory Neil Shapiro **	Returns:
2169bd497b8SGregory Neil Shapiro **		0 on success.
2179bd497b8SGregory Neil Shapiro **		< 0 on failure.
2189bd497b8SGregory Neil Shapiro */
2199bd497b8SGregory Neil Shapiro 
220*2fb4f839SGregory Neil Shapiro #ifdef __STDC__
221*2fb4f839SGregory Neil Shapiro int
sm_semsetowner(int semid,uid_t uid,gid_t gid,MODE_T mode)222*2fb4f839SGregory Neil Shapiro sm_semsetowner(int semid, uid_t uid, gid_t gid, MODE_T mode)
223*2fb4f839SGregory Neil Shapiro #else /* __STDC__ */
2249bd497b8SGregory Neil Shapiro int
2259bd497b8SGregory Neil Shapiro sm_semsetowner(semid, uid, gid, mode)
2269bd497b8SGregory Neil Shapiro 	int semid;
2279bd497b8SGregory Neil Shapiro 	uid_t uid;
2289bd497b8SGregory Neil Shapiro 	gid_t gid;
229*2fb4f839SGregory Neil Shapiro 	MODE_T mode;
230*2fb4f839SGregory Neil Shapiro #endif /* __STDC__ */
2319bd497b8SGregory Neil Shapiro {
2329bd497b8SGregory Neil Shapiro 	int r;
2339bd497b8SGregory Neil Shapiro 	struct semid_ds	semidds;
2349bd497b8SGregory Neil Shapiro 	union semun {
2359bd497b8SGregory Neil Shapiro 		int		val;
2369bd497b8SGregory Neil Shapiro 		struct semid_ds	*buf;
2379bd497b8SGregory Neil Shapiro 		ushort		*array;
2389bd497b8SGregory Neil Shapiro 	} arg;
2399bd497b8SGregory Neil Shapiro 
2409bd497b8SGregory Neil Shapiro 	memset(&semidds, 0, sizeof(semidds));
2419bd497b8SGregory Neil Shapiro 	arg.buf = &semidds;
2429bd497b8SGregory Neil Shapiro 	if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
2439bd497b8SGregory Neil Shapiro 		return r;
2449bd497b8SGregory Neil Shapiro 	semidds.sem_perm.uid = uid;
2459bd497b8SGregory Neil Shapiro 	semidds.sem_perm.gid = gid;
2469bd497b8SGregory Neil Shapiro 	semidds.sem_perm.mode = mode;
2479bd497b8SGregory Neil Shapiro 	if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
2489bd497b8SGregory Neil Shapiro 		return r;
2499bd497b8SGregory Neil Shapiro 	return 0;
2509bd497b8SGregory Neil Shapiro }
25113d88268SGregory Neil Shapiro #endif /* SM_CONF_SEM */
252