1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * This code is mainly taken from Doug Potter's page
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * I contacted him 2007-04-16 about the license for the original code,
7d4afb5ceSopenharmony_ci * he replied it is Public Domain.  Use the URL above to get the original
8d4afb5ceSopenharmony_ci * Public Domain version if you want it.
9d4afb5ceSopenharmony_ci *
10d4afb5ceSopenharmony_ci * This version is MIT like the rest of libwebsockets and is
11d4afb5ceSopenharmony_ci * Copyright (c)2006 - 2013 Andy Green <andy@warmcat.com>
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci *
14d4afb5ceSopenharmony_ci * You're much better advised to use systemd to daemonize stuff without needing
15d4afb5ceSopenharmony_ci * this kind of support in the app itself.
16d4afb5ceSopenharmony_ci */
17d4afb5ceSopenharmony_ci
18d4afb5ceSopenharmony_ci#include <stdlib.h>
19d4afb5ceSopenharmony_ci#include <string.h>
20d4afb5ceSopenharmony_ci#include <stdio.h>
21d4afb5ceSopenharmony_ci#include <signal.h>
22d4afb5ceSopenharmony_ci#include <sys/types.h>
23d4afb5ceSopenharmony_ci#include <sys/stat.h>
24d4afb5ceSopenharmony_ci#include <fcntl.h>
25d4afb5ceSopenharmony_ci#include <limits.h>
26d4afb5ceSopenharmony_ci#include <unistd.h>
27d4afb5ceSopenharmony_ci#include <errno.h>
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_ci#include <libwebsockets.h>
30d4afb5ceSopenharmony_ci#include "private-lib-core.h"
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_cipid_t pid_daemon;
33d4afb5ceSopenharmony_cistatic char *lock_path;
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_cipid_t get_daemonize_pid()
36d4afb5ceSopenharmony_ci{
37d4afb5ceSopenharmony_ci	return pid_daemon;
38d4afb5ceSopenharmony_ci}
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_cistatic void
41d4afb5ceSopenharmony_cichild_handler(int signum)
42d4afb5ceSopenharmony_ci{
43d4afb5ceSopenharmony_ci	int len, sent, fd;
44d4afb5ceSopenharmony_ci	char sz[20];
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	switch (signum) {
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ci	case SIGALRM: /* timed out daemonizing */
49d4afb5ceSopenharmony_ci		exit(0);
50d4afb5ceSopenharmony_ci		break;
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_ci	case SIGUSR1: /* positive confirmation we daemonized well */
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci		if (!lock_path)
55d4afb5ceSopenharmony_ci			exit(0);
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci		/* Create the lock file as the current user */
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_ci		fd = lws_open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640);
60d4afb5ceSopenharmony_ci		if (fd < 0) {
61d4afb5ceSopenharmony_ci			fprintf(stderr,
62d4afb5ceSopenharmony_ci			   "unable to create lock file %s, code=%d (%s)\n",
63d4afb5ceSopenharmony_ci				lock_path, errno, strerror(errno));
64d4afb5ceSopenharmony_ci			exit(0);
65d4afb5ceSopenharmony_ci		}
66d4afb5ceSopenharmony_ci		len = sprintf(sz, "%u", (unsigned int)pid_daemon);
67d4afb5ceSopenharmony_ci		sent = (int)write(fd, sz, (size_t)len);
68d4afb5ceSopenharmony_ci		if (sent != len)
69d4afb5ceSopenharmony_ci			fprintf(stderr,
70d4afb5ceSopenharmony_ci			  "unable to write pid to lock file %s, code=%d (%s)\n",
71d4afb5ceSopenharmony_ci					     lock_path, errno, strerror(errno));
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci		close(fd);
74d4afb5ceSopenharmony_ci
75d4afb5ceSopenharmony_ci		exit(0);
76d4afb5ceSopenharmony_ci		//!!(sent == len));
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	case SIGCHLD: /* daemonization failed */
79d4afb5ceSopenharmony_ci		exit(0);
80d4afb5ceSopenharmony_ci		break;
81d4afb5ceSopenharmony_ci	}
82d4afb5ceSopenharmony_ci}
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_cistatic void lws_daemon_closing(int sigact)
85d4afb5ceSopenharmony_ci{
86d4afb5ceSopenharmony_ci	if (getpid() == pid_daemon)
87d4afb5ceSopenharmony_ci		if (lock_path) {
88d4afb5ceSopenharmony_ci			unlink(lock_path);
89d4afb5ceSopenharmony_ci			lws_free_set_NULL(lock_path);
90d4afb5ceSopenharmony_ci		}
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci	kill(getpid(), SIGKILL);
93d4afb5ceSopenharmony_ci}
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_ci/*
96d4afb5ceSopenharmony_ci * You just need to call this from your main(), when it
97d4afb5ceSopenharmony_ci * returns you are all set "in the background" decoupled
98d4afb5ceSopenharmony_ci * from the console you were started from.
99d4afb5ceSopenharmony_ci *
100d4afb5ceSopenharmony_ci * The process context you called from has been terminated then.
101d4afb5ceSopenharmony_ci */
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ciint
104d4afb5ceSopenharmony_cilws_daemonize(const char *_lock_path)
105d4afb5ceSopenharmony_ci{
106d4afb5ceSopenharmony_ci	struct sigaction act;
107d4afb5ceSopenharmony_ci	pid_t sid, parent;
108d4afb5ceSopenharmony_ci
109d4afb5ceSopenharmony_ci	/* already a daemon */
110d4afb5ceSopenharmony_ci//	if (getppid() == 1)
111d4afb5ceSopenharmony_ci//		return 1;
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_ci	if (_lock_path) {
114d4afb5ceSopenharmony_ci		int n;
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci		int fd = lws_open(_lock_path, O_RDONLY);
117d4afb5ceSopenharmony_ci		if (fd >= 0) {
118d4afb5ceSopenharmony_ci			char buf[10];
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci			n = (int)read(fd, buf, sizeof(buf));
121d4afb5ceSopenharmony_ci			close(fd);
122d4afb5ceSopenharmony_ci			if (n) {
123d4afb5ceSopenharmony_ci				int ret;
124d4afb5ceSopenharmony_ci				n = atoi(buf);
125d4afb5ceSopenharmony_ci				ret = kill(n, 0);
126d4afb5ceSopenharmony_ci				if (ret >= 0) {
127d4afb5ceSopenharmony_ci					fprintf(stderr,
128d4afb5ceSopenharmony_ci					     "Daemon already running pid %d\n",
129d4afb5ceSopenharmony_ci					     n);
130d4afb5ceSopenharmony_ci					exit(1);
131d4afb5ceSopenharmony_ci				}
132d4afb5ceSopenharmony_ci				fprintf(stderr,
133d4afb5ceSopenharmony_ci				    "Removing stale lock %s from dead pid %d\n",
134d4afb5ceSopenharmony_ci							_lock_path, n);
135d4afb5ceSopenharmony_ci				unlink(lock_path);
136d4afb5ceSopenharmony_ci			}
137d4afb5ceSopenharmony_ci		}
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci		n = (int)strlen(_lock_path) + 1;
140d4afb5ceSopenharmony_ci		lock_path = lws_malloc((unsigned int)n, "daemonize lock");
141d4afb5ceSopenharmony_ci		if (!lock_path) {
142d4afb5ceSopenharmony_ci			fprintf(stderr, "Out of mem in lws_daemonize\n");
143d4afb5ceSopenharmony_ci			return 1;
144d4afb5ceSopenharmony_ci		}
145d4afb5ceSopenharmony_ci		strcpy(lock_path, _lock_path);
146d4afb5ceSopenharmony_ci	}
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci	/* Trap signals that we expect to receive */
149d4afb5ceSopenharmony_ci	signal(SIGCHLD, child_handler);	/* died */
150d4afb5ceSopenharmony_ci	signal(SIGUSR1, child_handler); /* was happy */
151d4afb5ceSopenharmony_ci	signal(SIGALRM, child_handler); /* timeout daemonizing */
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	/* Fork off the parent process */
154d4afb5ceSopenharmony_ci	pid_daemon = fork();
155d4afb5ceSopenharmony_ci	if ((int)pid_daemon < 0) {
156d4afb5ceSopenharmony_ci		fprintf(stderr, "unable to fork daemon, code=%d (%s)",
157d4afb5ceSopenharmony_ci		    errno, strerror(errno));
158d4afb5ceSopenharmony_ci		exit(9);
159d4afb5ceSopenharmony_ci	}
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci        /* If we got a good PID, then we can exit the parent process. */
162d4afb5ceSopenharmony_ci	if (pid_daemon > 0) {
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci               /*
165d4afb5ceSopenharmony_ci                * Wait for confirmation signal from the child via
166d4afb5ceSopenharmony_ci                * SIGCHILD / USR1, or for two seconds to elapse
167d4afb5ceSopenharmony_ci                * (SIGALRM).  pause() should not return.
168d4afb5ceSopenharmony_ci                */
169d4afb5ceSopenharmony_ci               alarm(2);
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci               pause();
172d4afb5ceSopenharmony_ci               /* should not be reachable */
173d4afb5ceSopenharmony_ci               exit(1);
174d4afb5ceSopenharmony_ci       }
175d4afb5ceSopenharmony_ci
176d4afb5ceSopenharmony_ci	/* At this point we are executing as the child process */
177d4afb5ceSopenharmony_ci	parent = getppid();
178d4afb5ceSopenharmony_ci	pid_daemon = getpid();
179d4afb5ceSopenharmony_ci
180d4afb5ceSopenharmony_ci	/* Cancel certain signals */
181d4afb5ceSopenharmony_ci	signal(SIGCHLD, SIG_DFL); /* A child process dies */
182d4afb5ceSopenharmony_ci	signal(SIGTSTP, SIG_IGN); /* Various TTY signals */
183d4afb5ceSopenharmony_ci	signal(SIGTTOU, SIG_IGN);
184d4afb5ceSopenharmony_ci	signal(SIGTTIN, SIG_IGN);
185d4afb5ceSopenharmony_ci	signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci	/* Change the file mode mask */
188d4afb5ceSopenharmony_ci	umask(0);
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	/* Create a new SID for the child process */
191d4afb5ceSopenharmony_ci	sid = setsid();
192d4afb5ceSopenharmony_ci	if (sid < 0) {
193d4afb5ceSopenharmony_ci		fprintf(stderr,
194d4afb5ceSopenharmony_ci			"unable to create a new session, code %d (%s)",
195d4afb5ceSopenharmony_ci			errno, strerror(errno));
196d4afb5ceSopenharmony_ci		exit(2);
197d4afb5ceSopenharmony_ci	}
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci	/*
200d4afb5ceSopenharmony_ci	 * Change the current working directory.  This prevents the current
201d4afb5ceSopenharmony_ci	 * directory from being locked; hence not being able to remove it.
202d4afb5ceSopenharmony_ci	 */
203d4afb5ceSopenharmony_ci	if (chdir("/tmp") < 0) {
204d4afb5ceSopenharmony_ci		fprintf(stderr,
205d4afb5ceSopenharmony_ci			"unable to change directory to %s, code %d (%s)",
206d4afb5ceSopenharmony_ci			"/", errno, strerror(errno));
207d4afb5ceSopenharmony_ci		exit(3);
208d4afb5ceSopenharmony_ci	}
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci	/* Redirect standard files to /dev/null */
211d4afb5ceSopenharmony_ci	if (!freopen("/dev/null", "r", stdin))
212d4afb5ceSopenharmony_ci		fprintf(stderr, "unable to freopen() stdin, code %d (%s)",
213d4afb5ceSopenharmony_ci						       errno, strerror(errno));
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci	if (!freopen("/dev/null", "w", stdout))
216d4afb5ceSopenharmony_ci		fprintf(stderr, "unable to freopen() stdout, code %d (%s)",
217d4afb5ceSopenharmony_ci						       errno, strerror(errno));
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	if (!freopen("/dev/null", "w", stderr))
220d4afb5ceSopenharmony_ci		fprintf(stderr, "unable to freopen() stderr, code %d (%s)",
221d4afb5ceSopenharmony_ci						       errno, strerror(errno));
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	/* Tell the parent process that we are A-okay */
224d4afb5ceSopenharmony_ci	kill(parent, SIGUSR1);
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	act.sa_handler = lws_daemon_closing;
227d4afb5ceSopenharmony_ci	sigemptyset(&act.sa_mask);
228d4afb5ceSopenharmony_ci	act.sa_flags = 0;
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci	sigaction(SIGTERM, &act, NULL);
231d4afb5ceSopenharmony_ci
232d4afb5ceSopenharmony_ci	/* return to continue what is now "the daemon" */
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	return 0;
235d4afb5ceSopenharmony_ci}
236d4afb5ceSopenharmony_ci
237