1 /*
2  * Copyright (C) Tildeslash Ltd. All rights reserved.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Affero General Public License version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU Affero General Public License
13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
14  *
15  * In addition, as a special exception, the copyright holders give
16  * permission to link the code of portions of this program with the
17  * OpenSSL library under certain conditions as described in each
18  * individual source file, and distribute linked combinations
19  * including the two.
20  *
21  * You must obey the GNU Affero General Public License in all respects
22  * for all of the code used other than OpenSSL.
23  */
24 
25 
26 #include "config.h"
27 
28 #ifdef HAVE_STDIO_H
29 #include <stdio.h>
30 #endif
31 
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 
36 #ifdef HAVE_ERRNO_H
37 #include <errno.h>
38 #endif
39 
40 #ifdef HAVE_SIGNAL_H
41 #include <signal.h>
42 #endif
43 
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 
48 #ifdef HAVE_SYS_TYPES_H
49 #include <sys/types.h>
50 #endif
51 
52 #ifdef HAVE_SYS_STAT_H
53 #include <sys/stat.h>
54 #endif
55 
56 #ifdef HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif
59 
60 #ifdef HAVE_STRING_H
61 #include <string.h>
62 #endif
63 
64 #include "monit.h"
65 
66 
67 /**
68  *  Transform this program into a daemon and provide methods for
69  *  managing the daemon.
70  *
71  *  @file
72  */
73 
74 
75 /* ------------------------------------------------------------------ Public */
76 
77 
78 /**
79  * Transform a program into a daemon. Inspired by code from Stephen
80  * A. Rago's book, Unix System V Network Programming.
81  */
daemonize()82 void daemonize() {
83         pid_t pid;
84         /*
85          * Become a session leader to lose our controlling terminal
86          */
87         if ((pid = fork ()) < 0) {
88                 Log_error("Cannot fork a new process\n");
89                 exit (1);
90         } else if (pid != 0) {
91                 _exit(0);
92         }
93         setsid();
94         if ((pid = fork ()) < 0) {
95                 Log_error("Cannot fork a new process\n");
96                 exit (1);
97         } else if (pid != 0) {
98                 _exit(0);
99         }
100         /*
101          * Change current directory to the root so that other file systems can be unmounted while we're running
102          */
103         if (chdir("/") < 0) {
104                 Log_error("Cannot chdir to / -- %s\n", STRERROR);
105                 exit(1);
106         }
107         /*
108          * Attach standard descriptors to /dev/null. Other descriptors should be closed in env.c
109          */
110         Util_redirectStdFds();
111 }
112 
113 
114 /**
115  * Send signal to a daemon process
116  * @param sig Signal to send daemon to
117  * @return true if signal was send, otherwise false
118  */
kill_daemon(int sig)119 bool kill_daemon(int sig) {
120         pid_t pid;
121         if ((pid = exist_daemon()) > 0) {
122                 if (kill(pid, sig) < 0) {
123                         Log_error("Cannot signal the monit daemon process -- %s\n", STRERROR);
124                         return false;
125                 }
126         } else {
127                 Log_info("Monit daemon is not running\n");
128                 return true;
129         }
130         if (sig == SIGTERM) {
131                 fprintf(stdout, "Monit daemon with pid [%d] killed\n", (int)pid);
132                 fflush(stdout);
133         }
134         return true;
135 }
136 
137 
138 /**
139  * @return true (i.e. the daemons pid) if a daemon process is running,
140  * otherwise false
141  */
exist_daemon()142 int exist_daemon() {
143         errno = 0;
144         pid_t pid;
145         if ((pid = Util_getPid(Run.files.pid)) && (getpgid(pid) > -1 || errno == EPERM))
146                 return (int)pid;
147         return 0;
148 }
149 
150