Subject: [Dev] HOWTO write a daemon

From: "Peter Long" <[email-masked]>
Date: Thu, 23 May 2002 18:40:09 -0400 (EDT)

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.

-- 
Peter Long

---

From: "M. Mueller" <[email-masked]>
Date: Thu, 23 May 2002 19:13:23 -0400

> know where I can find documentation on how to do that.

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

---

From: "M. Mueller" <[email-masked]>
Date: Thu, 23 May 2002 19:15:18 -0400

> know where I can find documentation on how to do that.

BTW, check out Richard Stevens texts. http://www.kohala.com/start/#books

-- 
Mike Mueller
www.ss7box.com

---

From: "Peter Long" <[email-masked]>
Date: Thu, 23 May 2002 19:39:58 -0400 (EDT)

>> 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.
> 

Thanks! 

That link and your daemon launcher should get me on the right track.

-- 
Peter Long
mailto:[email-masked]

---

From: "David A. Cafaro" <[email-masked]>
Date: 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:
> ----

> #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);
> }

---

From: "Paul D. Boyle" <[email-masked]>
Date: Thu, 23 May 2002 21:56:38 -0400 (EDT)

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

What distinguishes a daemon from a "regular" process (either foreground
or background) is that the process becomes (according to Stevens) a
session leader of a new session, it becomes a process group leader of
a new process group, and it has no controlling terminal.  In addition,
very often daemon change their current working directory to a specific
directory (often, but not always, "/"), so that filesystems can be
unmounted while the daemon is running (did you ever try to unmount a
file system and got a 'device busy' message?).  

Under Unix (Linux) all processes automatically open three I/O streams,
stdin, stdout, stderr, these are often closed in a daemon process.

Paul

-- 
Paul D. Boyle			    |	[email-masked]
Director, X-ray Structural Facility |	phone: (919) 515-7362
Department of Chemistry - Box 8204  |	FAX:   (919) 515-5079
North Carolina State University     | 
Raleigh, NC, 27695-8204
http://laue.chem.ncsu.edu/web/xray.welcome.html

---

From: "M. Mueller" <[email-masked]>
Date: Thu, 23 May 2002 23:46:14 -0400

> stdin, stdout, stderr, these are often closed in a daemon process.

So, you need alternatives to these services.

I make great use of the syslogger daemon.  I had to become aware of the 
klogger, or kernel logger daemon because it would generate useful information 
for me.  This led to needing an awareness of the logrotate function which led 
to needing an awareness of cron from a system point of view.  I "tail -f" the 
/var/log/messages file for long periods of time and found that logrotate 
changes the file handles so that the "tail -f" goes dead so to speak.  I've 
hacked a script that lets me quickly manage the tail function (script 
attached). I eventually learned how to manage the /etc/syslog.conf and syslog 
calls to define new log files associated with new facilities.  
Another capability that I think Brent Verner brought to my attention, and 
that I have not investigated yet, is the FIFO abilities of the Linux 
syslogger.  More at "man syslogd".

My daemons use AF_INET sockets for interprocess communication.  I tried 
several flavors of IPC (SystemV, AF_UNIX sockets).  And there are more IPC 
methods I did not try.  I've seen code that used disk files for IPC.  The 
Stevens book, "UNIX Network Programming, Volume 2, Second Edition: 
Interprocess Communications, Prentice Hall, 1999" was my primary resource. I 
use Python to write shell to daemon "communicators". 

My intent here is to dump a bunch of ideas to the list that you can pick 
through.  If there is further interest, I can provide code detail and system 
configuration detail as requested.

-- 
Mike Mueller
www.ss7box.com

---

From: "Andrew C. Oliver" <[email-masked]>
Date: Fri, 24 May 2002 08:14:09 -0400

just make sure you start it as some other user than root.

David A. Cafaro wrote:

>_______________________________________________
>Dev mailing list
>[email-masked]
>http://www.trilug.org/mailman/listinfo/dev
>
>  
>