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