1 /*
2  *   Copyright (c) 2013 Ralph Irving
3  *
4  *   daemonize.c is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   daemonize.c is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with SlimProtoLib; if not, write to the Free Software
16  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #include "squeezelite.h"
20 
21 #include <syslog.h>
22 #include <sys/stat.h>
23 
fork_child_handler(int signum)24 void fork_child_handler(int signum)
25 {
26 	switch(signum) {
27 	case SIGALRM: exit(EXIT_FAILURE); break;
28 	case SIGUSR1: exit(EXIT_SUCCESS); break;
29 	case SIGCHLD: exit(EXIT_FAILURE); break;
30 	}
31 }
32 
33 pid_t parent;
init_daemonize()34 void init_daemonize()
35 {
36 	pid_t pid, sid;
37 
38 	/* already a daemon */
39 	if ( getppid() == 1 ) return;
40 
41 	/* Trap signals that we expect to recieve */
42 	signal(SIGCHLD,fork_child_handler);
43 	signal(SIGUSR1,fork_child_handler);
44 	signal(SIGALRM,fork_child_handler);
45 
46 	/* Fork off the parent process */
47 	pid = fork();
48 	if (pid < 0) {
49 		syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)",
50 				errno, strerror(errno) );
51 		exit(EXIT_FAILURE);
52 	}
53 
54 	/* If we got a good PID, then we can exit the parent process. */
55 	if (pid > 0) {
56 
57 		/* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
58 		   for two seconds to elapse (SIGALRM).  pause() should not return. */
59 		alarm(2);
60 		pause();
61 
62 		exit(EXIT_FAILURE);
63 	}
64 
65 	/* At this point we are executing as the child process */
66 	parent = getppid();
67 
68 	/* Cancel certain signals */
69 	signal(SIGCHLD,SIG_DFL); /* A child process dies */
70 	signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
71 	signal(SIGTTOU,SIG_IGN);
72 	signal(SIGTTIN,SIG_IGN);
73 	signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
74 	signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
75 
76 	/* Change the file mode mask */
77 	umask(0);
78 
79 	/* Create a new SID for the child process */
80 	sid = setsid();
81 	if (sid < 0) {
82 		syslog( LOG_ERR, "unable to create a new session, code %d (%s)",
83 				errno, strerror(errno) );
84 		exit(EXIT_FAILURE);
85 	}
86 
87 	/* Change the current working directory.  This prevents the current
88 	   directory from being locked; hence not being able to remove it. */
89 	if ((chdir("/")) < 0) {
90 		syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)",
91 				"/", errno, strerror(errno) );
92 		exit(EXIT_FAILURE);
93 	}
94 }
95 
daemon(int nochdir,int noclose)96 int daemon( int nochdir, int noclose ) {
97 
98 	if ( ! noclose )
99 	{
100 		/* Redirect standard files to /dev/null */
101 		freopen( "/dev/null", "r", stdin);
102 		freopen( "/dev/null", "w", stdout);
103 		freopen( "/dev/null", "w", stderr);
104 	}
105 
106 	/* Tell the parent process that we are A-okay */
107 	kill( parent, SIGUSR1 );
108 
109 	return 0;
110 }
111