[Dev] HOWTO write a daemon

David A. Cafaro dev@trilug.org
23 May 2002 21:06:26 -0400


Just curious but what is wrong with just writing a program that doesn't
put out any text to the console and starting it with a script with a
command like this:

mydaemon&

Besides the fact that it's a little less elegant?

It's been a long long time since I did C/C++ coding and righting
daemons.  I'm planning on writing up a little tcp/ip daemon for my
Zaurus.  Thanks for any input.

-David

On Thu, 2002-05-23 at 19:13, M. Mueller wrote:
> On Thursday 23 May 2002 06:40 pm, Peter Long reputedly wrote:
> 
> > Hi all,
> >
> > I have a console application that I want to turn into a daemon. Does anyone
> > know where I can find documentation on how to do that.
> >
> > Thanks in advance.
> 
> 
> Here's my daemon launcher.  It is more than a basic daemon launcher because I 
> have N daemons that all talk to each other.  Furthermore, I don't want any 
> daemons to start doing business until all the other daemons are ready.
> 
> -- 
> Mike Mueller
> www.ss7box.com
> ----
> 

> #include	<sys/stat.h>
> #include	<sys/msg.h>
> #include	<fcntl.h>
> #include	<syslog.h>
> #include	<stdio.h>
> #include	<unistd.h>
> #include	<errno.h>
> #include	"ipc_mq.h"
> 
> #define		MAX_DAEMONS	5
> #define		DAEMON_PATH	"usr/local/ss7t/bin/"
> 
> char		*env_init[] = {"USER=mtp3d", "PATH=/tmp", NULL};
> char		*daemon_names[][MAX_DAEMONS] = {
> 			"mtp3_d",
> 			"tali_d",
> //			"sctp_d",
> 			"oam_d",
> 			"mr_d",
> 			"ps_d"
> 		};
> 
> int			sockfd;
> struct sockaddr_in	myaddr, peeraddr;
> t_ipc_mqbuf		mb;
> socklen_t		sockaddrlen;
> 
> void get_busy (unsigned int daemon_id)
> /******************************************************************************
> ******************************************************************************/
> {
> int	r;
> 
> 	bzero(&peeraddr, sizeof(peeraddr));
> 	peeraddr.sin_family = AF_INET;
> 	peeraddr.sin_port = htons(daemon_id);
> 	r = inet_pton(AF_INET, IPC_ADDR_STR, &peeraddr.sin_addr.s_addr);
> 	if (r == -1)
> 		{
> 		syslog (LOG_INFO, "F:daemon_launcher:get_busy:inet_pton failed:%s",
> 				strerror(errno));
> 		exit (-1);
> 		}
> 
> 	bzero (&mb, sizeof(mb));
> 	mb.mhdr.s_id = DLAUNCH_ID; // this is the letter sender
> 	mb.mhdr.mcode = IPC_PROCEED; 
> 	mb.mhdr.mlen = sizeof(t_ipc_mb_hdr);
> 
> 	r = sendto (sockfd, &mb, mb.mhdr.mlen, NOFLAGS, 
> 			&peeraddr, sizeof (peeraddr));
> 	if (r == -1)
> 		{
> 		syslog (LOG_INFO, "F:get busy:sendto failed:cause %s target: %s", 
> 				strerror(errno), daemon_id);
> 		exit (-1);
> 		}
> }
> 
> int daemon_init(char *p_daemon_fname)
> /******************************************************************************
> ******************************************************************************/
> {
> char	daemon_pathname [128];
> 	pid_t	pid;
> 
> 	if ( (pid = fork()) < 0)
> 		return(-1);
> 	else if (pid != 0)
> 		return (0);	/* the parent process returns from this function here */
> 
> // the child process continues here
> 
> 	setsid();		/* become session leader */
> 	chdir("/");		/* change working directory */
> 	umask(0);		/* clear our file mode creation mask */
> 
> 	if ((strlen (p_daemon_fname) + strlen (DAEMON_PATH)+ 1) > sizeof (daemon_pathname))
> 		{
> 		syslog (LOG_INFO, "daemon pathname too long");
> 		exit (-1);
> 		}
> 
> // exec the daemon in the child process 
> 
> 	execl 	(
> 		strcat (strcpy (daemon_pathname,DAEMON_PATH), p_daemon_fname), 
> 		p_daemon_fname,
> 		(char *) 0
> 		);
> 	
> // should never reach this statement
> 
> 	exit(0);
> }
> 
> int daemon_comm_ready (void)
> /******************************************************************************
> ******************************************************************************/
> {
> ssize_t	bw;
> u_long	daemons_ready;
> 
> 	daemons_ready = 0;
> 
> 	for (;;)
> 		{
> // blocking read; wait for a daemon to report for duty; if this becomes
> // a block-forever condition, then one must resort to killing process
> // use "ps -axj" as superuser to find the processes to be killed
> 
> 		bw = recvfrom (sockfd, &mb, sizeof (mb), NOFLAGS, 
> 			&peeraddr, &sockaddrlen);
> 		if (bw == -1)
> 			{
> 			syslog (LOG_INFO, "F:daemon_comm_ready:recvfrom failed");
> 			exit (-1);
> 			}
> 
> // show who's ready for duty; add a string termination
> 
> 		//mb.mdata[mb.mhdr.mlen - sizeof(t_ipc_mb_hdr)] = '\0';
> 		syslog (LOG_INFO, "I:mb contents:s_id %d daemon on duty: %s", 
> 				mb.mhdr.s_id, 
> 				&mb.mdata);
> 		
> 		daemons_ready = daemons_ready | mb.mhdr.s_id;
> 		if (daemons_ready == ALL_DAEMONS_READY)
> 			{
> 			syslog (LOG_INFO, "I:daemon_comm_ready:all daemons ready");
> 			break;
> 			}
> 		} // end of for loop
> 
> // tell the daemons that IPC may proceed
> 
> 	get_busy (MTP3_PORT);
> 	get_busy (TALI_PORT);
> //	get_busy (SCTP_IPC_PORT);
> 	get_busy (OAM_PORT);
> 	get_busy (MR_PORT);
> 	get_busy (PS_PORT);
> }
> 
> int	configure_dl()
> /******************************************************************************
> ******************************************************************************/
> {
> 	//dlConf = new c_confReader("dl");
> 	//delete dlConf
> }
> 
> int main (int argc, char **argv)
> /******************************************************************************
> ******************************************************************************/
> {
> int	d;
> int	r;
> 
> 	openlog ("daemon_init" ,LOG_PID, LOG_USER);
> 	syslog (LOG_INFO ,"Daemon launcher starting");
> 
> // read daemon launcher conf file
> 	
> 	configure_dl();
> 	
> 	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
> 	if (sockfd == -1)
> 		{
> 		syslog (LOG_INFO, "socket failed");
> 		exit (-1);
> 		}
> 
> // create an Internet Protocol address
> 
> 	bzero(&myaddr, sizeof(myaddr));
> 	myaddr.sin_family = AF_INET;
> 	myaddr.sin_port = htons(DLAUNCH_PORT);
> 	r = inet_pton(AF_INET, IPC_ADDR_STR, &myaddr.sin_addr.s_addr);
> 	if (r == -1)
> 		{
> 		syslog (LOG_INFO, "I:daemon_launcher:main:inet_pton failed:%s",
> 				strerror(errno));
> 		exit (-1);
> 		}
> 
> 	r = bind (sockfd, (const struct sockaddr *) &myaddr, sizeof(myaddr));
> 	if (r == -1)
> 		{
> 		syslog (LOG_INFO, "bind failed");
> 		exit (-1);
> 		}
> 
> 	for (d = 0; d < MAX_DAEMONS; d++) 
> 		{
> 		if (daemon_init (daemon_names [0][d]) == -1)
> 			{
> 			syslog (LOG_INFO, "fork failed; daemon ID: %s\n", daemon_names[d]);
> 			return (-1);
> 			}
> 		}
> 
> 	if (daemon_comm_ready () == -1)
> 		{
> 		}
> 	return (0);
> }