Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2016 Proofpoint, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 */

#include <sm/gen.h>

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>	/* for memset() */

#include <sm/conf.h>	/* FDSET_CAST */
#include <sm/fdset.h>
#include <sm/assert.h>
#include <sm/notify.h>

#if SM_NOTIFY_DEBUG
#define SM_DBG(p)	fprintf p
#else
#define SM_DBG(p)	
#endif

static int	Notifypipe[2];
#define NotifyRDpipe Notifypipe[0]
#define NotifyWRpipe Notifypipe[1]

#define CLOSEFD(fd) do { \
		if ((fd) != -1) {	\
			(void) close(fd);	\
			fd = - 1;	\
		}	\
	} while (0)	\


/*
**  SM_NOTIFY_INIT -- initialize notify system
**
**	Parameters:
**		flags -- ignored
**
**	Returns:
**		0: success
**		<0: -errno
*/

int
sm_notify_init(flags)
	int flags;
{
	if (pipe(Notifypipe) < 0)
		return -errno;
	return 0;
}

/*
**  SM_NOTIFY_START -- start notify system
**
**	Parameters:
**		owner -- owner.
**		flags -- currently ignored.
**
**	Returns:
**		0: success
**		<0: -errno
*/

int
sm_notify_start(owner, flags)
	bool owner;
	int flags;
{
	int r;

	r = 0;
	if (owner)
		CLOSEFD(NotifyWRpipe);
	else
		CLOSEFD(NotifyRDpipe);
	return r;
}

/*
**  SM_NOTIFY_STOP -- stop notify system
**
**	Parameters:
**		owner -- owner.
**		flags -- currently ignored.
**
**	Returns:
**		0: success
**		<0: -errno
*/

int
sm_notify_stop(owner, flags)
	bool owner;
	int flags;
{
	if (owner)
		CLOSEFD(NotifyRDpipe);
	else
		CLOSEFD(NotifyWRpipe);
	return 0;
}

/*
**  SM_NOTIFY_SND -- send notification
**
**	Parameters:
**		buf -- where to write data
**		buflen -- len of buffer
**
**	Returns:
**		0: success
**		<0: -errno
*/

int
sm_notify_snd(buf, buflen)
	char *buf;
	size_t buflen;
{
	int r;
	int save_errno;

	SM_REQUIRE(buf != NULL);
	SM_REQUIRE(buflen > 0);
	if (NotifyWRpipe < 0)
		return -EINVAL;

	r = write(NotifyWRpipe, buf, buflen);
	save_errno = errno;
	SM_DBG((stderr, "write=%d, fd=%d, e=%d\n", r, NotifyWRpipe, save_errno));
	return r >= 0 ? 0 : -save_errno;
}

/*
**  SM_NOTIFY_RCV -- receive notification
**
**	Parameters:
**		buf -- where to write data
**		buflen -- len of buffer
**		tmo -- timeout
**
**	Returns:
**		0: success
**		<0: -errno
*/

int
sm_notify_rcv(buf, buflen, tmo)
	char *buf;
	size_t buflen;
	int tmo;
{
	int r;
	int save_errno;
	fd_set readfds;
	struct timeval timeout;

	SM_REQUIRE(buf != NULL);
	SM_REQUIRE(buflen > 0);
	if (NotifyRDpipe < 0)
		return -EINVAL;
	FD_ZERO(&readfds);
	SM_FD_SET(NotifyRDpipe, &readfds);
	timeout.tv_sec = tmo;
	timeout.tv_usec = 0;

	do {
		r = select(NotifyRDpipe + 1, FDSET_CAST &readfds, NULL, NULL, &timeout);
		save_errno = errno;
		SM_DBG((stderr, "select=%d, fd=%d, e=%d\n", r, NotifyRDpipe, save_errno));
	} while (r < 0 && save_errno == EINTR);

	if (r <= 0)
	{
		SM_DBG((stderr, "select=%d, e=%d\n", r, save_errno));
		return -ETIMEDOUT;
	}

	/* bogus... need to check again? */
	if (!FD_ISSET(NotifyRDpipe, &readfds))
		return -ETIMEDOUT;

	r = read(NotifyRDpipe, buf, buflen);
	save_errno = errno;
	SM_DBG((stderr, "read=%d, e=%d\n", r, save_errno));
	if (r == 0)
		return -1;	/* ??? */
	if (r < 0)
		return -save_errno;
	return r;
}