xref: /freebsd/contrib/sendmail/libsm/sem.c (revision 5b0945b57059d1cde0831d3afea7ec56c7d79508)
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>
169bd497b8SGregory Neil Shapiro # include <sm/string.h>
1713d88268SGregory Neil Shapiro # include <sm/sem.h>
1813d88268SGregory Neil Shapiro # include <sm/heap.h>
194e4196cbSGregory Neil Shapiro # include <errno.h>
2013d88268SGregory Neil Shapiro 
2113d88268SGregory Neil Shapiro /*
2213d88268SGregory Neil Shapiro **  SM_SEM_START -- initialize semaphores
2313d88268SGregory Neil Shapiro **
2413d88268SGregory Neil Shapiro **	Parameters:
2513d88268SGregory Neil Shapiro **		key -- key for semaphores.
2613d88268SGregory Neil Shapiro **		nsem -- number of semaphores.
2713d88268SGregory Neil Shapiro **		semflg -- flag for semget(), if 0, use a default.
2813d88268SGregory Neil Shapiro **		owner -- create semaphores.
2913d88268SGregory Neil Shapiro **
3013d88268SGregory Neil Shapiro **	Returns:
3113d88268SGregory Neil Shapiro **		id for semaphores.
3213d88268SGregory Neil Shapiro **		< 0 on failure.
3313d88268SGregory Neil Shapiro */
3413d88268SGregory Neil Shapiro 
3513d88268SGregory Neil Shapiro int
3613d88268SGregory Neil Shapiro sm_sem_start(key, nsem, semflg, owner)
3713d88268SGregory Neil Shapiro 	key_t key;
3813d88268SGregory Neil Shapiro 	int nsem;
3913d88268SGregory Neil Shapiro 	int semflg;
4013d88268SGregory Neil Shapiro 	bool owner;
4113d88268SGregory Neil Shapiro {
424e4196cbSGregory Neil Shapiro 	int semid, i, err;
4313d88268SGregory Neil Shapiro 	unsigned short *semvals;
4413d88268SGregory Neil Shapiro 
4513d88268SGregory Neil Shapiro 	semvals = NULL;
4613d88268SGregory Neil Shapiro 	if (semflg == 0)
4713d88268SGregory Neil Shapiro 		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
4813d88268SGregory Neil Shapiro 	if (owner)
4913d88268SGregory Neil Shapiro 		semflg |= IPC_CREAT|IPC_EXCL;
5013d88268SGregory Neil Shapiro 	semid = semget(key, nsem, semflg);
5113d88268SGregory Neil Shapiro 	if (semid < 0)
5213d88268SGregory Neil Shapiro 		goto error;
5313d88268SGregory Neil Shapiro 
5413d88268SGregory Neil Shapiro 	if (owner)
5513d88268SGregory Neil Shapiro 	{
5613d88268SGregory Neil Shapiro 		union semun semarg;
5713d88268SGregory Neil Shapiro 
5813d88268SGregory Neil Shapiro 		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
5913d88268SGregory Neil Shapiro 		if (semvals == NULL)
6013d88268SGregory Neil Shapiro 			goto error;
6113d88268SGregory Neil Shapiro 		semarg.array = semvals;
6213d88268SGregory Neil Shapiro 
6313d88268SGregory Neil Shapiro 		/* initialize semaphore values to be available */
6413d88268SGregory Neil Shapiro 		for (i = 0; i < nsem; i++)
6513d88268SGregory Neil Shapiro 			semvals[i] = 1;
6613d88268SGregory Neil Shapiro 		if (semctl(semid, 0, SETALL, semarg) < 0)
6713d88268SGregory Neil Shapiro 			goto error;
6813d88268SGregory Neil Shapiro 	}
6913d88268SGregory Neil Shapiro 	return semid;
7013d88268SGregory Neil Shapiro 
7113d88268SGregory Neil Shapiro error:
724e4196cbSGregory Neil Shapiro 	err = errno;
7313d88268SGregory Neil Shapiro 	if (semvals != NULL)
7413d88268SGregory Neil Shapiro 		sm_free(semvals);
7513d88268SGregory Neil Shapiro 	if (semid >= 0)
7613d88268SGregory Neil Shapiro 		sm_sem_stop(semid);
774e4196cbSGregory Neil Shapiro 	return (err > 0) ? (0 - err) : -1;
7813d88268SGregory Neil Shapiro }
7913d88268SGregory Neil Shapiro 
8013d88268SGregory Neil Shapiro /*
8113d88268SGregory Neil Shapiro **  SM_SEM_STOP -- stop using semaphores.
8213d88268SGregory Neil Shapiro **
8313d88268SGregory Neil Shapiro **	Parameters:
8413d88268SGregory Neil Shapiro **		semid -- id for semaphores.
8513d88268SGregory Neil Shapiro **
8613d88268SGregory Neil Shapiro **	Returns:
8713d88268SGregory Neil Shapiro **		0 on success.
8813d88268SGregory Neil Shapiro **		< 0 on failure.
8913d88268SGregory Neil Shapiro */
9013d88268SGregory Neil Shapiro 
9113d88268SGregory Neil Shapiro int
9213d88268SGregory Neil Shapiro sm_sem_stop(semid)
9313d88268SGregory Neil Shapiro 	int semid;
9413d88268SGregory Neil Shapiro {
9513d88268SGregory Neil Shapiro 	return semctl(semid, 0, IPC_RMID, NULL);
9613d88268SGregory Neil Shapiro }
9713d88268SGregory Neil Shapiro 
9813d88268SGregory Neil Shapiro /*
9913d88268SGregory Neil Shapiro **  SM_SEM_ACQ -- acquire semaphore.
10013d88268SGregory Neil Shapiro **
10113d88268SGregory Neil Shapiro **	Parameters:
10213d88268SGregory Neil Shapiro **		semid -- id for semaphores.
10313d88268SGregory Neil Shapiro **		semnum -- number of semaphore.
10413d88268SGregory Neil Shapiro **		timeout -- how long to wait for operation to succeed.
10513d88268SGregory Neil Shapiro **
10613d88268SGregory Neil Shapiro **	Returns:
10713d88268SGregory Neil Shapiro **		0 on success.
10813d88268SGregory Neil Shapiro **		< 0 on failure.
10913d88268SGregory Neil Shapiro */
11013d88268SGregory Neil Shapiro 
11113d88268SGregory Neil Shapiro int
11213d88268SGregory Neil Shapiro sm_sem_acq(semid, semnum, timeout)
11313d88268SGregory Neil Shapiro 	int semid;
11413d88268SGregory Neil Shapiro 	int semnum;
11513d88268SGregory Neil Shapiro 	int timeout;
11613d88268SGregory Neil Shapiro {
11713d88268SGregory Neil Shapiro 	int r;
11813d88268SGregory Neil Shapiro 	struct sembuf semops[1];
11913d88268SGregory Neil Shapiro 
12013d88268SGregory Neil Shapiro 	semops[0].sem_num = semnum;
12113d88268SGregory Neil Shapiro 	semops[0].sem_op = -1;
12213d88268SGregory Neil Shapiro 	semops[0].sem_flg = SEM_UNDO |
12313d88268SGregory Neil Shapiro 			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
12413d88268SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
12513d88268SGregory Neil Shapiro 		return semop(semid, semops, 1);
12613d88268SGregory Neil Shapiro 	do
12713d88268SGregory Neil Shapiro 	{
12813d88268SGregory Neil Shapiro 		r = semop(semid, semops, 1);
12913d88268SGregory Neil Shapiro 		if (r == 0)
13013d88268SGregory Neil Shapiro 			return r;
13113d88268SGregory Neil Shapiro 		sleep(1);
13213d88268SGregory Neil Shapiro 		--timeout;
13313d88268SGregory Neil Shapiro 	} while (timeout > 0);
13413d88268SGregory Neil Shapiro 	return r;
13513d88268SGregory Neil Shapiro }
13613d88268SGregory Neil Shapiro 
13713d88268SGregory Neil Shapiro /*
13813d88268SGregory Neil Shapiro **  SM_SEM_REL -- release semaphore.
13913d88268SGregory Neil Shapiro **
14013d88268SGregory Neil Shapiro **	Parameters:
14113d88268SGregory Neil Shapiro **		semid -- id for semaphores.
14213d88268SGregory Neil Shapiro **		semnum -- number of semaphore.
14313d88268SGregory Neil Shapiro **		timeout -- how long to wait for operation to succeed.
14413d88268SGregory Neil Shapiro **
14513d88268SGregory Neil Shapiro **	Returns:
14613d88268SGregory Neil Shapiro **		0 on success.
14713d88268SGregory Neil Shapiro **		< 0 on failure.
14813d88268SGregory Neil Shapiro */
14913d88268SGregory Neil Shapiro 
15013d88268SGregory Neil Shapiro int
15113d88268SGregory Neil Shapiro sm_sem_rel(semid, semnum, timeout)
15213d88268SGregory Neil Shapiro 	int semid;
15313d88268SGregory Neil Shapiro 	int semnum;
15413d88268SGregory Neil Shapiro 	int timeout;
15513d88268SGregory Neil Shapiro {
15613d88268SGregory Neil Shapiro 	int r;
15713d88268SGregory Neil Shapiro 	struct sembuf semops[1];
15813d88268SGregory Neil Shapiro 
15913d88268SGregory Neil Shapiro #if PARANOID
16013d88268SGregory Neil Shapiro 	/* XXX should we check whether the value is already 0 ? */
16113d88268SGregory Neil Shapiro 	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
162*5b0945b5SGregory Neil Shapiro #endif
16313d88268SGregory Neil Shapiro 
16413d88268SGregory Neil Shapiro 	semops[0].sem_num = semnum;
16513d88268SGregory Neil Shapiro 	semops[0].sem_op = 1;
16613d88268SGregory Neil Shapiro 	semops[0].sem_flg = SEM_UNDO |
16713d88268SGregory Neil Shapiro 			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
16813d88268SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
16913d88268SGregory Neil Shapiro 		return semop(semid, semops, 1);
17013d88268SGregory Neil Shapiro 	do
17113d88268SGregory Neil Shapiro 	{
17213d88268SGregory Neil Shapiro 		r = semop(semid, semops, 1);
17313d88268SGregory Neil Shapiro 		if (r == 0)
17413d88268SGregory Neil Shapiro 			return r;
17513d88268SGregory Neil Shapiro 		sleep(1);
17613d88268SGregory Neil Shapiro 		--timeout;
17713d88268SGregory Neil Shapiro 	} while (timeout > 0);
17813d88268SGregory Neil Shapiro 	return r;
17913d88268SGregory Neil Shapiro }
18013d88268SGregory Neil Shapiro 
18113d88268SGregory Neil Shapiro /*
18213d88268SGregory Neil Shapiro **  SM_SEM_GET -- get semaphore value.
18313d88268SGregory Neil Shapiro **
18413d88268SGregory Neil Shapiro **	Parameters:
18513d88268SGregory Neil Shapiro **		semid -- id for semaphores.
18613d88268SGregory Neil Shapiro **		semnum -- number of semaphore.
18713d88268SGregory Neil Shapiro **
18813d88268SGregory Neil Shapiro **	Returns:
18913d88268SGregory Neil Shapiro **		value of semaphore on success.
19013d88268SGregory Neil Shapiro **		< 0 on failure.
19113d88268SGregory Neil Shapiro */
19213d88268SGregory Neil Shapiro 
19313d88268SGregory Neil Shapiro int
19413d88268SGregory Neil Shapiro sm_sem_get(semid, semnum)
19513d88268SGregory Neil Shapiro 	int semid;
19613d88268SGregory Neil Shapiro 	int semnum;
19713d88268SGregory Neil Shapiro {
19813d88268SGregory Neil Shapiro 	int semval;
19913d88268SGregory Neil Shapiro 
20013d88268SGregory Neil Shapiro 	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
20113d88268SGregory Neil Shapiro 		return -1;
20213d88268SGregory Neil Shapiro 	return semval;
20313d88268SGregory Neil Shapiro }
2049bd497b8SGregory Neil Shapiro 
2059bd497b8SGregory Neil Shapiro /*
2069bd497b8SGregory Neil Shapiro **  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
2079bd497b8SGregory Neil Shapiro **
2089bd497b8SGregory Neil Shapiro **	Parameters:
2099bd497b8SGregory Neil Shapiro **		semid -- id for semaphores.
2109bd497b8SGregory Neil Shapiro **		uid -- uid to use
2119bd497b8SGregory Neil Shapiro **		gid -- gid to use
2129bd497b8SGregory Neil Shapiro **		mode -- mode to use
2139bd497b8SGregory Neil Shapiro **
2149bd497b8SGregory Neil Shapiro **	Returns:
2159bd497b8SGregory Neil Shapiro **		0 on success.
2169bd497b8SGregory Neil Shapiro **		< 0 on failure.
2179bd497b8SGregory Neil Shapiro */
2189bd497b8SGregory Neil Shapiro 
2199bd497b8SGregory Neil Shapiro int
2209bd497b8SGregory Neil Shapiro sm_semsetowner(semid, uid, gid, mode)
2219bd497b8SGregory Neil Shapiro 	int semid;
2229bd497b8SGregory Neil Shapiro 	uid_t uid;
2239bd497b8SGregory Neil Shapiro 	gid_t gid;
2249bd497b8SGregory Neil Shapiro 	mode_t mode;
2259bd497b8SGregory Neil Shapiro {
2269bd497b8SGregory Neil Shapiro 	int r;
2279bd497b8SGregory Neil Shapiro 	struct semid_ds	semidds;
2289bd497b8SGregory Neil Shapiro 	union semun {
2299bd497b8SGregory Neil Shapiro 		int		val;
2309bd497b8SGregory Neil Shapiro 		struct semid_ds	*buf;
2319bd497b8SGregory Neil Shapiro 		ushort		*array;
2329bd497b8SGregory Neil Shapiro 	} arg;
2339bd497b8SGregory Neil Shapiro 
2349bd497b8SGregory Neil Shapiro 	memset(&semidds, 0, sizeof(semidds));
2359bd497b8SGregory Neil Shapiro 	arg.buf = &semidds;
2369bd497b8SGregory Neil Shapiro 	if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
2379bd497b8SGregory Neil Shapiro 		return r;
2389bd497b8SGregory Neil Shapiro 	semidds.sem_perm.uid = uid;
2399bd497b8SGregory Neil Shapiro 	semidds.sem_perm.gid = gid;
2409bd497b8SGregory Neil Shapiro 	semidds.sem_perm.mode = mode;
2419bd497b8SGregory Neil Shapiro 	if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
2429bd497b8SGregory Neil Shapiro 		return r;
2439bd497b8SGregory Neil Shapiro 	return 0;
2449bd497b8SGregory Neil Shapiro }
24513d88268SGregory Neil Shapiro #endif /* SM_CONF_SEM */
246