17c478bdstevel@tonic-gate/*
2e9af4bcJohn Beck * Copyright (c) 2000-2001, 2005, 2008 Sendmail, Inc. and its suppliers.
37c478bdstevel@tonic-gate *      All rights reserved.
47c478bdstevel@tonic-gate *
57c478bdstevel@tonic-gate * By using this file, you agree to the terms and conditions set
67c478bdstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
77c478bdstevel@tonic-gate * the sendmail distribution.
87c478bdstevel@tonic-gate */
97c478bdstevel@tonic-gate
107c478bdstevel@tonic-gate#include <sm/gen.h>
11e9af4bcJohn BeckSM_RCSID("@(#)$Id: sem.c,v 1.14 2008/05/30 16:26:38 ca Exp $")
127c478bdstevel@tonic-gate
137c478bdstevel@tonic-gate#if SM_CONF_SEM
147c478bdstevel@tonic-gate# include <stdlib.h>
157c478bdstevel@tonic-gate# include <unistd.h>
16e9af4bcJohn Beck# include <sm/string.h>
177c478bdstevel@tonic-gate# include <sm/sem.h>
187c478bdstevel@tonic-gate# include <sm/heap.h>
1949218d4jbeck# include <errno.h>
207c478bdstevel@tonic-gate
217c478bdstevel@tonic-gate/*
227c478bdstevel@tonic-gate**  SM_SEM_START -- initialize semaphores
237c478bdstevel@tonic-gate**
247c478bdstevel@tonic-gate**	Parameters:
257c478bdstevel@tonic-gate**		key -- key for semaphores.
267c478bdstevel@tonic-gate**		nsem -- number of semaphores.
277c478bdstevel@tonic-gate**		semflg -- flag for semget(), if 0, use a default.
287c478bdstevel@tonic-gate**		owner -- create semaphores.
297c478bdstevel@tonic-gate**
307c478bdstevel@tonic-gate**	Returns:
317c478bdstevel@tonic-gate**		id for semaphores.
327c478bdstevel@tonic-gate**		< 0 on failure.
337c478bdstevel@tonic-gate*/
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gateint
367c478bdstevel@tonic-gatesm_sem_start(key, nsem, semflg, owner)
377c478bdstevel@tonic-gate	key_t key;
387c478bdstevel@tonic-gate	int nsem;
397c478bdstevel@tonic-gate	int semflg;
407c478bdstevel@tonic-gate	bool owner;
417c478bdstevel@tonic-gate{
4249218d4jbeck	int semid, i, err;
437c478bdstevel@tonic-gate	unsigned short *semvals;
447c478bdstevel@tonic-gate
457c478bdstevel@tonic-gate	semvals = NULL;
467c478bdstevel@tonic-gate	if (semflg == 0)
477c478bdstevel@tonic-gate		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
487c478bdstevel@tonic-gate	if (owner)
497c478bdstevel@tonic-gate		semflg |= IPC_CREAT|IPC_EXCL;
507c478bdstevel@tonic-gate	semid = semget(key, nsem, semflg);
517c478bdstevel@tonic-gate	if (semid < 0)
527c478bdstevel@tonic-gate		goto error;
537c478bdstevel@tonic-gate
547c478bdstevel@tonic-gate	if (owner)
557c478bdstevel@tonic-gate	{
567c478bdstevel@tonic-gate		union semun semarg;
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gate		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
597c478bdstevel@tonic-gate		if (semvals == NULL)
607c478bdstevel@tonic-gate			goto error;
617c478bdstevel@tonic-gate		semarg.array = semvals;
627c478bdstevel@tonic-gate
637c478bdstevel@tonic-gate		/* initialize semaphore values to be available */
647c478bdstevel@tonic-gate		for (i = 0; i < nsem; i++)
657c478bdstevel@tonic-gate			semvals[i] = 1;
667c478bdstevel@tonic-gate		if (semctl(semid, 0, SETALL, semarg) < 0)
677c478bdstevel@tonic-gate			goto error;
687c478bdstevel@tonic-gate	}
697c478bdstevel@tonic-gate	return semid;
707c478bdstevel@tonic-gate
717c478bdstevel@tonic-gateerror:
7249218d4jbeck	err = errno;
737c478bdstevel@tonic-gate	if (semvals != NULL)
747c478bdstevel@tonic-gate		sm_free(semvals);
757c478bdstevel@tonic-gate	if (semid >= 0)
767c478bdstevel@tonic-gate		sm_sem_stop(semid);
7749218d4jbeck	return (err > 0) ? (0 - err) : -1;
787c478bdstevel@tonic-gate}
797c478bdstevel@tonic-gate
807c478bdstevel@tonic-gate/*
817c478bdstevel@tonic-gate**  SM_SEM_STOP -- stop using semaphores.
827c478bdstevel@tonic-gate**
837c478bdstevel@tonic-gate**	Parameters:
847c478bdstevel@tonic-gate**		semid -- id for semaphores.
857c478bdstevel@tonic-gate**
867c478bdstevel@tonic-gate**	Returns:
877c478bdstevel@tonic-gate**		0 on success.
887c478bdstevel@tonic-gate**		< 0 on failure.
897c478bdstevel@tonic-gate*/
907c478bdstevel@tonic-gate
917c478bdstevel@tonic-gateint
927c478bdstevel@tonic-gatesm_sem_stop(semid)
937c478bdstevel@tonic-gate	int semid;
947c478bdstevel@tonic-gate{
957c478bdstevel@tonic-gate	return semctl(semid, 0, IPC_RMID, NULL);
967c478bdstevel@tonic-gate}
977c478bdstevel@tonic-gate
987c478bdstevel@tonic-gate/*
997c478bdstevel@tonic-gate**  SM_SEM_ACQ -- acquire semaphore.
1007c478bdstevel@tonic-gate**
1017c478bdstevel@tonic-gate**	Parameters:
1027c478bdstevel@tonic-gate**		semid -- id for semaphores.
1037c478bdstevel@tonic-gate**		semnum -- number of semaphore.
1047c478bdstevel@tonic-gate**		timeout -- how long to wait for operation to succeed.
1057c478bdstevel@tonic-gate**
1067c478bdstevel@tonic-gate**	Returns:
1077c478bdstevel@tonic-gate**		0 on success.
1087c478bdstevel@tonic-gate**		< 0 on failure.
1097c478bdstevel@tonic-gate*/
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gateint
1127c478bdstevel@tonic-gatesm_sem_acq(semid, semnum, timeout)
1137c478bdstevel@tonic-gate	int semid;
1147c478bdstevel@tonic-gate	int semnum;
1157c478bdstevel@tonic-gate	int timeout;
1167c478bdstevel@tonic-gate{
1177c478bdstevel@tonic-gate	int r;
1187c478bdstevel@tonic-gate	struct sembuf semops[1];
1197c478bdstevel@tonic-gate
1207c478bdstevel@tonic-gate	semops[0].sem_num = semnum;
1217c478bdstevel@tonic-gate	semops[0].sem_op = -1;
1227c478bdstevel@tonic-gate	semops[0].sem_flg = SEM_UNDO |
1237c478bdstevel@tonic-gate			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
1247c478bdstevel@tonic-gate	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
1257c478bdstevel@tonic-gate		return semop(semid, semops, 1);
1267c478bdstevel@tonic-gate	do
1277c478bdstevel@tonic-gate	{
1287c478bdstevel@tonic-gate		r = semop(semid, semops, 1);
1297c478bdstevel@tonic-gate		if (r == 0)
1307c478bdstevel@tonic-gate			return r;
1317c478bdstevel@tonic-gate		sleep(1);
1327c478bdstevel@tonic-gate		--timeout;
1337c478bdstevel@tonic-gate	} while (timeout > 0);
1347c478bdstevel@tonic-gate	return r;
1357c478bdstevel@tonic-gate}
1367c478bdstevel@tonic-gate
1377c478bdstevel@tonic-gate/*
1387c478bdstevel@tonic-gate**  SM_SEM_REL -- release semaphore.
1397c478bdstevel@tonic-gate**
1407c478bdstevel@tonic-gate**	Parameters:
1417c478bdstevel@tonic-gate**		semid -- id for semaphores.
1427c478bdstevel@tonic-gate**		semnum -- number of semaphore.
1437c478bdstevel@tonic-gate**		timeout -- how long to wait for operation to succeed.
1447c478bdstevel@tonic-gate**
1457c478bdstevel@tonic-gate**	Returns:
1467c478bdstevel@tonic-gate**		0 on success.
1477c478bdstevel@tonic-gate**		< 0 on failure.
1487c478bdstevel@tonic-gate*/
1497c478bdstevel@tonic-gate
1507c478bdstevel@tonic-gateint
1517c478bdstevel@tonic-gatesm_sem_rel(semid, semnum, timeout)
1527c478bdstevel@tonic-gate	int semid;
1537c478bdstevel@tonic-gate	int semnum;
1547c478bdstevel@tonic-gate	int timeout;
1557c478bdstevel@tonic-gate{
1567c478bdstevel@tonic-gate	int r;
1577c478bdstevel@tonic-gate	struct sembuf semops[1];
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate#if PARANOID
1607c478bdstevel@tonic-gate	/* XXX should we check whether the value is already 0 ? */
1617c478bdstevel@tonic-gate	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
1627c478bdstevel@tonic-gate#endif /* PARANOID */
1637c478bdstevel@tonic-gate
1647c478bdstevel@tonic-gate	semops[0].sem_num = semnum;
1657c478bdstevel@tonic-gate	semops[0].sem_op = 1;
1667c478bdstevel@tonic-gate	semops[0].sem_flg = SEM_UNDO |
1677c478bdstevel@tonic-gate			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
1687c478bdstevel@tonic-gate	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
1697c478bdstevel@tonic-gate		return semop(semid, semops, 1);
1707c478bdstevel@tonic-gate	do
1717c478bdstevel@tonic-gate	{
1727c478bdstevel@tonic-gate		r = semop(semid, semops, 1);
1737c478bdstevel@tonic-gate		if (r == 0)
1747c478bdstevel@tonic-gate			return r;
1757c478bdstevel@tonic-gate		sleep(1);
1767c478bdstevel@tonic-gate		--timeout;
1777c478bdstevel@tonic-gate	} while (timeout > 0);
1787c478bdstevel@tonic-gate	return r;
1797c478bdstevel@tonic-gate}
1807c478bdstevel@tonic-gate
1817c478bdstevel@tonic-gate/*
1827c478bdstevel@tonic-gate**  SM_SEM_GET -- get semaphore value.
1837c478bdstevel@tonic-gate**
1847c478bdstevel@tonic-gate**	Parameters:
1857c478bdstevel@tonic-gate**		semid -- id for semaphores.
1867c478bdstevel@tonic-gate**		semnum -- number of semaphore.
1877c478bdstevel@tonic-gate**
1887c478bdstevel@tonic-gate**	Returns:
1897c478bdstevel@tonic-gate**		value of semaphore on success.
1907c478bdstevel@tonic-gate**		< 0 on failure.
1917c478bdstevel@tonic-gate*/
1927c478bdstevel@tonic-gate
1937c478bdstevel@tonic-gateint
1947c478bdstevel@tonic-gatesm_sem_get(semid, semnum)
1957c478bdstevel@tonic-gate	int semid;
1967c478bdstevel@tonic-gate	int semnum;
1977c478bdstevel@tonic-gate{
1987c478bdstevel@tonic-gate	int semval;
1997c478bdstevel@tonic-gate
2007c478bdstevel@tonic-gate	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
2017c478bdstevel@tonic-gate		return -1;
2027c478bdstevel@tonic-gate	return semval;
2037c478bdstevel@tonic-gate}
204e9af4bcJohn Beck
205e9af4bcJohn Beck/*
206e9af4bcJohn Beck**  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
207e9af4bcJohn Beck**
208e9af4bcJohn Beck**	Parameters:
209e9af4bcJohn Beck**		semid -- id for semaphores.
210e9af4bcJohn Beck**		uid -- uid to use
211e9af4bcJohn Beck**		gid -- gid to use
212e9af4bcJohn Beck**		mode -- mode to use
213e9af4bcJohn Beck**
214e9af4bcJohn Beck**	Returns:
215e9af4bcJohn Beck**		0 on success.
216e9af4bcJohn Beck**		< 0 on failure.
217e9af4bcJohn Beck*/
218e9af4bcJohn Beck
219e9af4bcJohn Beckint
220e9af4bcJohn Becksm_semsetowner(semid, uid, gid, mode)
221e9af4bcJohn Beck	int semid;
222e9af4bcJohn Beck	uid_t uid;
223e9af4bcJohn Beck	gid_t gid;
224e9af4bcJohn Beck	mode_t mode;
225e9af4bcJohn Beck{
226e9af4bcJohn Beck	int r;
227e9af4bcJohn Beck	struct semid_ds	semidds;
228e9af4bcJohn Beck	union semun {
229e9af4bcJohn Beck		int		val;
230e9af4bcJohn Beck		struct semid_ds	*buf;
231e9af4bcJohn Beck		ushort		*array;
232e9af4bcJohn Beck	} arg;
233e9af4bcJohn Beck
234e9af4bcJohn Beck	memset(&semidds, 0, sizeof(semidds));
235e9af4bcJohn Beck	arg.buf = &semidds;
236e9af4bcJohn Beck	if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
237e9af4bcJohn Beck		return r;
238e9af4bcJohn Beck	semidds.sem_perm.uid = uid;
239e9af4bcJohn Beck	semidds.sem_perm.gid = gid;
240e9af4bcJohn Beck	semidds.sem_perm.mode = mode;
241e9af4bcJohn Beck	if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
242e9af4bcJohn Beck		return r;
243e9af4bcJohn Beck	return 0;
244e9af4bcJohn Beck}
2457c478bdstevel@tonic-gate#endif /* SM_CONF_SEM */
246