[KIRKROERIG]


article unix linux system fork daemon service

Creating a Unix Daemon

To quote Wikipedia,

In multitasking computer operating systems, a daemon (/ˈdiːmən/ or /ˈdeɪmən/)[1] is a computer program that runs as a background process, rather than being under the direct control of an interactive user.

In practice daemons are used any time a service needs to be accessible at a moment's notice. A good example would be a server applicaion. A server spends most of it's time sitting, waiting, for a request or connection that could come at any time; then honoring that request as quickly as possible.

Recently I created my first daemon, a TCP server for uploading gps data to the computer on a robot. So I wanted to document what I learned.

Here's how to create a minimal Unix daemon in C.

#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main()
{
	// When you start the daemon initially the process that is spawned
	// is attached to the user's current session. So the first a child
	// process is spawned. fork() accomplishes this. From this point on you
	// can think of your program now existing as two processes, both of which
	// just finished executing the line below. One of these processes is the
	// parent, the other is the child
	pid_t pid = fork();

	if(pid > 0){
		printf("parent: the daemon's pid is %d\n", pid);
		return -1; // the parent has nothing else to do, simply exit
	}
	else if(pid < 0){
		// if the pid returned is -1, then the fork() failed.
		printf("parent: and the daemon failed to start (%d).\n", errno);
		return -2;
	}

	// if the pid is 0 then this process is the child
	// setsid() makes the process the leader of a new session. This is the
	// reason we had to fork() above. Since the parent was already the process
	// group leader creating another session would fail.
	if(setsid() < 0){
		printf("daemon: I failed to create a new session.\n");
		return -3;
	}

	// when the child is spawned all its' properties are inherited from
	// the parent including the working directory as shown below
	char workingDirectory[256];
	char* wd = getwd(workingDirectory);
	printf("daemon: current working directory is '%s'\n", wd);

	// change the working directory appropriately. (to root for example)
	chdir("/");
	wd = getwd(workingDirectory);
	printf("daemon: new current working directory is '%s'\n", wd);

	// close whatever file descriptors might have been
	// inherited from the parent, such as stdin stdout
	for(int i = sysconf(_SC_OPEN_MAX); i--;){
		close(i);
	}

	// stdio is closed, you won't hear anything more from the daemon
	printf("daemon: now I'm silent!\n");

	// like everything else, file permissions are also inherited from the
	// parent process. This is an octal number which follows the chmod
	// pattern. The default value is 022. (write access for owner only)
	umask(022);

	// keep the daemon alive for 10 seconds.
	// here is where you would actually do some work :)
	sleep(10);

	return 0;
}
article unix linux system fork socket udp 0 fd file file descriptor network

Duplicated File Descriptors and system()

For the last month or so I've been pretty heavily invested in building and programming an autonomous R/C car for Sparkfun's AVC. I decided to use a Raspberry Pi Model A+ as my embedded platform with an Arch Arm distro installed on it. All had been going quite well until I started working on the control software.

The Problem

Some time ago I stumbled across a fantastic driver written by richardghirst for the Raspberry Pi called servoblaster. Essentially, this driver enables the configuration and use of the Pi's GPIO header pins as PWM outputs. In other words, it allows you to easily drive R/C servos from the Pi with no additional hardware! This was exactly what I was looking for. There were two implementations of the driver, one kernel level, and another user level. richardghirst recommended the user level, so I decided to heed his suggestion.

At this time I began working on a simple UDP server that would run on the Pi. The server would allow me to control the car remotely over WiFi. This is what the beginning of that server looked like.

int main(int argc, char* argv[])
{
	// open socket, setup sockaddr_in structure
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	struct sockaddr_in addr = { };
	addr.sin_family      = AF_INET;
	addr.sin_port        = htons(atoi(argv[1]));
	addr.sin_addr.s_addr = INADDR_ANY;

	printf("Setup using port %d\n", ntohs(addr.sin_port)); // say what port

	assert(sock > 0); // sanity check

	// bind the process to the desired port
	int res = bind(sock, (const struct sockaddr*)&addr, sizeof(addr));
	assert(res >= 0); // sanity check

	// start up the control module, and servoblaster
	assert(!conInit());

	// ...

In the function call conInit() the driver daemon is started with the following calls.

	// does the servo blaster device exist? (is the driver running?)
	if(!stat("/dev/servoblaster", &buf)){
		fprintf(stderr, "Servo driver already running\n");
	}
	// execute the servo blaster daemon
	else if(system("servod --p1pins=37,38")){
		fprintf(stderr, "Failed to start servo driver\n");
		return -1;
	}

Here, the program first looks to see if the driver has been started. It assumes if the device file exists, then the driver is live. Otherwise it attempts to start it with the call system("servod --p1pins=37,38").

This is where the problem was. If the driver isn't running and system("servod --p1pins=37,38") is called it forks a new child process. When that occurs all open file descriptors in the host process are automatically inherited by the child. So that means...

	int sock = socket(AF_INET, SOCK_DGRAM, 0);

is thus inherited by the child process, which in this case is the servo driver. But because the driver is a daemon it will keep running after the UDP server has shut down. This means, the servo driver will keep sock open and bound to the port specified above. Which will result in an EADDRINUSE errno if a bind() to that port is attempted again.

The Solution

After some searching I found that luckily this was a very easy fix. It came down entirely to adding one function call shortly after opening the socket.

	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);

The fcntl function is used to get and set properties of file descriptors. The current flags of sock are retrieved with the fcntl(sock, F_GETFD) call. Those flags are then or'ed together with the flag FD_CLOEXEC. Here's what the man pages say about that flag.

	FD_CLOEXEC   
				Close-on-exec; the given file descriptor will be auto-
				matically closed in the successor process image when
				one of the execv(2) or posix_spawn(2) family of system
				calls is invoked.

Perfect! That was exactly the behavior that I had needed. And sure enough the server worked as intended. So much so that I could drive my car around from my laptop :)

A video posted by Kirk Roerig (@mrpossoms) on