
1) This makes lwsws run a parent process with the original permissions. But this process is only able to respond to SIGHUP, it doesn't do anything else. 2) You can send this parent process a SIGHUP now to cause it to - close listening sockets in existing lwsws processes - mark those processes as to exit when the number of active connections on the falls to zero - spawn a fresh child process from scratch, using latest configuration file content, latest plugins, etc. It can now reopen listening sockets if it chooses to, or open different listen ports or whatever. Notes: 1) lws_context_destroy() has been split into two pieces... the reason for the split is the first part closes the per-vhost protocols, but since they may have created libuv objects in the per-vhost protocol storage, these cannot be freed until after the loop has been run. That's the purpose of the second part of the context destruction, lws_context_destroy2(). For compatibility, if you are not using libuv, the first part calls the second part. However if you are using libuv, you must now call the second part from your own main.c after the first part.
225 lines
5.2 KiB
C
225 lines
5.2 KiB
C
/*
|
|
* This code is mainly taken from Doug Potter's page
|
|
*
|
|
* http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize
|
|
*
|
|
* I contacted him 2007-04-16 about the license for the original code,
|
|
* he replied it is Public Domain. Use the URL above to get the original
|
|
* Public Domain version if you want it.
|
|
*
|
|
* This version is LGPL2.1+SLE like the rest of libwebsockets and is
|
|
* Copyright (c)2006 - 2013 Andy Green <andy@warmcat.com>
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include "private-libwebsockets.h"
|
|
|
|
int pid_daemon;
|
|
static char *lock_path;
|
|
|
|
int get_daemonize_pid()
|
|
{
|
|
return pid_daemon;
|
|
}
|
|
|
|
static void
|
|
child_handler(int signum)
|
|
{
|
|
int fd, len, sent;
|
|
char sz[20];
|
|
|
|
switch (signum) {
|
|
|
|
case SIGALRM: /* timed out daemonizing */
|
|
exit(0);
|
|
break;
|
|
|
|
case SIGUSR1: /* positive confirmation we daemonized well */
|
|
|
|
if (lock_path) {
|
|
/* Create the lock file as the current user */
|
|
|
|
fd = open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640);
|
|
if (fd < 0) {
|
|
fprintf(stderr,
|
|
"unable to create lock file %s, code=%d (%s)\n",
|
|
lock_path, errno, strerror(errno));
|
|
exit(0);
|
|
}
|
|
len = sprintf(sz, "%u", pid_daemon);
|
|
sent = write(fd, sz, len);
|
|
if (sent != len)
|
|
fprintf(stderr,
|
|
"unable to write pid to lock file %s, code=%d (%s)\n",
|
|
lock_path, errno, strerror(errno));
|
|
|
|
close(fd);
|
|
}
|
|
exit(0);
|
|
//!!(sent == len));
|
|
|
|
case SIGCHLD: /* daemonization failed */
|
|
exit(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void lws_daemon_closing(int sigact)
|
|
{
|
|
if (getpid() == pid_daemon)
|
|
if (lock_path) {
|
|
unlink(lock_path);
|
|
lws_free_set_NULL(lock_path);
|
|
}
|
|
|
|
kill(getpid(), SIGKILL);
|
|
}
|
|
|
|
/*
|
|
* You just need to call this from your main(), when it
|
|
* returns you are all set "in the background" decoupled
|
|
* from the console you were started from.
|
|
*
|
|
* The process context you called from has been terminated then.
|
|
*/
|
|
|
|
LWS_VISIBLE int
|
|
lws_daemonize(const char *_lock_path)
|
|
{
|
|
struct sigaction act;
|
|
pid_t sid, parent;
|
|
int n, fd, ret;
|
|
char buf[10];
|
|
|
|
/* already a daemon */
|
|
// if (getppid() == 1)
|
|
// return 1;
|
|
|
|
if (_lock_path) {
|
|
fd = open(_lock_path, O_RDONLY);
|
|
if (fd >= 0) {
|
|
n = read(fd, buf, sizeof(buf));
|
|
close(fd);
|
|
if (n) {
|
|
n = atoi(buf);
|
|
ret = kill(n, 0);
|
|
if (ret >= 0) {
|
|
fprintf(stderr,
|
|
"Daemon already running from pid %d\n", n);
|
|
exit(1);
|
|
}
|
|
fprintf(stderr,
|
|
"Removing stale lock file %s from dead pid %d\n",
|
|
_lock_path, n);
|
|
unlink(lock_path);
|
|
}
|
|
}
|
|
|
|
n = strlen(_lock_path) + 1;
|
|
lock_path = lws_malloc(n);
|
|
if (!lock_path) {
|
|
fprintf(stderr, "Out of mem in lws_daemonize\n");
|
|
return 1;
|
|
}
|
|
strcpy(lock_path, _lock_path);
|
|
}
|
|
|
|
/* Trap signals that we expect to receive */
|
|
signal(SIGCHLD, child_handler); /* died */
|
|
signal(SIGUSR1, child_handler); /* was happy */
|
|
signal(SIGALRM, child_handler); /* timeout daemonizing */
|
|
|
|
/* Fork off the parent process */
|
|
pid_daemon = fork();
|
|
if (pid_daemon < 0) {
|
|
fprintf(stderr, "unable to fork daemon, code=%d (%s)",
|
|
errno, strerror(errno));
|
|
exit(9);
|
|
}
|
|
|
|
/* If we got a good PID, then we can exit the parent process. */
|
|
if (pid_daemon > 0) {
|
|
|
|
/*
|
|
* Wait for confirmation signal from the child via
|
|
* SIGCHILD / USR1, or for two seconds to elapse
|
|
* (SIGALRM). pause() should not return.
|
|
*/
|
|
alarm(2);
|
|
|
|
pause();
|
|
/* should not be reachable */
|
|
exit(1);
|
|
}
|
|
|
|
/* At this point we are executing as the child process */
|
|
parent = getppid();
|
|
pid_daemon = getpid();
|
|
|
|
/* Cancel certain signals */
|
|
signal(SIGCHLD, SIG_DFL); /* A child process dies */
|
|
signal(SIGTSTP, SIG_IGN); /* Various TTY signals */
|
|
signal(SIGTTOU, SIG_IGN);
|
|
signal(SIGTTIN, SIG_IGN);
|
|
signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
|
|
|
|
/* Change the file mode mask */
|
|
umask(0);
|
|
|
|
/* Create a new SID for the child process */
|
|
sid = setsid();
|
|
if (sid < 0) {
|
|
fprintf(stderr,
|
|
"unable to create a new session, code %d (%s)",
|
|
errno, strerror(errno));
|
|
exit(2);
|
|
}
|
|
|
|
/*
|
|
* Change the current working directory. This prevents the current
|
|
* directory from being locked; hence not being able to remove it.
|
|
*/
|
|
if (chdir("/tmp") < 0) {
|
|
fprintf(stderr,
|
|
"unable to change directory to %s, code %d (%s)",
|
|
"/", errno, strerror(errno));
|
|
exit(3);
|
|
}
|
|
|
|
/* Redirect standard files to /dev/null */
|
|
if (!freopen("/dev/null", "r", stdin))
|
|
fprintf(stderr, "unable to freopen() stdin, code %d (%s)",
|
|
errno, strerror(errno));
|
|
|
|
if (!freopen("/dev/null", "w", stdout))
|
|
fprintf(stderr, "unable to freopen() stdout, code %d (%s)",
|
|
errno, strerror(errno));
|
|
|
|
if (!freopen("/dev/null", "w", stderr))
|
|
fprintf(stderr, "unable to freopen() stderr, code %d (%s)",
|
|
errno, strerror(errno));
|
|
|
|
/* Tell the parent process that we are A-okay */
|
|
kill(parent, SIGUSR1);
|
|
|
|
act.sa_handler = lws_daemon_closing;
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_flags = 0;
|
|
|
|
sigaction(SIGTERM, &act, NULL);
|
|
|
|
/* return to continue what is now "the daemon" */
|
|
|
|
return 0;
|
|
}
|
|
|