]> arthur.barton.de Git - netdata.git/blob - src/daemon.c
layout: remove executable from unrelated files
[netdata.git] / src / daemon.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <pwd.h>
13 #include <pthread.h>
14 #include <sys/wait.h>
15 #include <sys/stat.h>
16
17 #include "common.h"
18 #include "appconfig.h"
19 #include "log.h"
20 #include "web_client.h"
21 #include "plugins_d.h"
22 #include "rrd.h"
23 #include "popen.h"
24 #include "main.h"
25 #include "daemon.h"
26
27 void sig_handler(int signo)
28 {
29         switch(signo) {
30                 case SIGILL:
31                 case SIGABRT:
32                 case SIGFPE:
33                 case SIGSEGV:
34                 case SIGBUS:
35                 case SIGSYS:
36                 case SIGTRAP:
37                 case SIGXCPU:
38                 case SIGXFSZ:
39                         infoerr("Death signaled exit (signal %d).", signo);
40                         signal(signo, SIG_DFL);
41                         break;
42
43                 case SIGKILL:
44                 case SIGTERM:
45                 case SIGQUIT:
46                 case SIGINT:
47                 case SIGHUP:
48                 case SIGUSR1:
49                 case SIGUSR2:
50                         infoerr("Signaled exit (signal %d).", signo);
51                         signal(SIGPIPE, SIG_IGN);
52                         signal(SIGTERM, SIG_IGN);
53                         signal(SIGQUIT, SIG_IGN);
54                         signal(SIGHUP,  SIG_IGN);
55                         signal(SIGINT,  SIG_IGN);
56                         signal(SIGCHLD, SIG_IGN);
57                         netdata_cleanup_and_exit(1);
58                         break;
59
60                 case SIGPIPE:
61                         infoerr("Signaled PIPE (signal %d).", signo);
62                         // this is received when web clients send a reset
63                         // no need to log it.
64                         // infoerr("Ignoring signal %d.", signo);
65                         break;
66
67                 default:
68                         info("Signal %d received. Falling back to default action for it.", signo);
69                         signal(signo, SIG_DFL);
70                         break;
71         }
72 }
73
74 char rundir[FILENAME_MAX + 1] = RUN_DIR;
75 char pidfile[FILENAME_MAX + 1] = "";
76 void prepare_rundir() {
77         if(getuid() != 0) {
78                 mkdir("/run/user", 0775);
79                 snprintf(rundir, FILENAME_MAX, "/run/user/%d", getuid());
80                 mkdir(rundir, 0775);
81                 snprintf(rundir, FILENAME_MAX, "/run/user/%d/netdata", getuid());
82         }
83
84         snprintf(pidfile, FILENAME_MAX, "%s/netdata.pid", rundir);
85
86         if(mkdir(rundir, 0775) != 0) {
87                 if(errno != EEXIST) error("Cannot create directory '%s'.", rundir);
88         }
89 }
90
91 int become_user(const char *username)
92 {
93         struct passwd *pw = getpwnam(username);
94         if(!pw) {
95                 error("User %s is not present.", username);
96                 return -1;
97         }
98
99         if(chown(rundir, pw->pw_uid, pw->pw_gid) != 0) {
100                 error("Cannot chown directory '%s' to user %s.", rundir, username);
101                 return -1;
102         }
103
104         if(setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
105                 error("Cannot switch to user's %s group (gid: %d).", username, pw->pw_gid);
106                 return -1;
107         }
108
109         if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
110                 error("Cannot switch to user %s (uid: %d).", username, pw->pw_uid);
111                 return -1;
112         }
113
114         if(setgid(pw->pw_gid) != 0) {
115                 error("Cannot switch to user's %s group (gid: %d).", username, pw->pw_gid);
116                 return -1;
117         }
118         if(setegid(pw->pw_gid) != 0) {
119                 error("Cannot effectively switch to user's %s group (gid: %d).", username, pw->pw_gid);
120                 return -1;
121         }
122         if(setuid(pw->pw_uid) != 0) {
123                 error("Cannot switch to user %s (uid: %d).", username, pw->pw_uid);
124                 return -1;
125         }
126         if(seteuid(pw->pw_uid) != 0) {
127                 error("Cannot effectively switch to user %s (uid: %d).", username, pw->pw_uid);
128                 return -1;
129         }
130
131         return(0);
132 }
133
134 int become_daemon(int dont_fork, int close_all_files, const char *user, const char *input, const char *output, const char *error, const char *access, int *access_fd, FILE **access_fp)
135 {
136         fflush(NULL);
137
138         // open the files before forking
139         int input_fd = -1, output_fd = -1, error_fd = -1, dev_null;
140
141         if(input && *input) {
142                 if((input_fd = open(input, O_RDONLY, 0666)) == -1) {
143                         error("Cannot open input file '%s'.", input);
144                         return -1;
145                 }
146         }
147
148         if(output && *output) {
149                 if((output_fd = open(output, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
150                         error("Cannot open output log file '%s'", output);
151                         if(input_fd != -1) close(input_fd);
152                         return -1;
153                 }
154         }
155
156         if(error && *error) {
157                 if((error_fd = open(error, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
158                         error("Cannot open error log file '%s'.", error);
159                         if(input_fd != -1) close(input_fd);
160                         if(output_fd != -1) close(output_fd);
161                         return -1;
162                 }
163         }
164
165         if(access && *access && access_fd) {
166                 if((*access_fd = open(access, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
167                         error("Cannot open access log file '%s'", access);
168                         if(input_fd != -1) close(input_fd);
169                         if(output_fd != -1) close(output_fd);
170                         if(error_fd != -1) close(error_fd);
171                         return -1;
172                 }
173
174                 if(access_fp) {
175                         *access_fp = fdopen(*access_fd, "w");
176                         if(!*access_fp) {
177                                 error("Cannot migrate file's '%s' fd %d.", access, *access_fd);
178                                 if(input_fd != -1) close(input_fd);
179                                 if(output_fd != -1) close(output_fd);
180                                 if(error_fd != -1) close(error_fd);
181                                 close(*access_fd);
182                                 *access_fd = -1;
183                                 return -1;
184                         }
185                 }
186         }
187
188         if((dev_null = open("/dev/null", O_RDWR, 0666)) == -1) {
189                 perror("Cannot open /dev/null");
190                 if(input_fd != -1) close(input_fd);
191                 if(output_fd != -1) close(output_fd);
192                 if(error_fd != -1) close(error_fd);
193                 if(access && access_fd && *access_fd != -1) {
194                         close(*access_fd);
195                         *access_fd = -1;
196                         if(access_fp) {
197                                 fclose(*access_fp);
198                                 *access_fp = NULL;
199                         }
200                 }
201                 return -1;
202         }
203
204         // all files opened
205         // lets do it
206
207         if(!dont_fork) {
208                 int i = fork();
209                 if(i == -1) {
210                         perror("cannot fork");
211                         exit(1);
212                 }
213                 if(i != 0) {
214                         exit(0); // the parent
215                 }
216
217                 // become session leader
218                 if (setsid() < 0) {
219                         perror("Cannot become session leader.");
220                         exit(2);
221                 }
222         }
223
224         signal(SIGCHLD,  SIG_IGN);
225         signal(SIGHUP,   SIG_IGN);
226         signal(SIGWINCH, SIG_IGN);
227
228         // fork() again
229         if(!dont_fork) {
230                 int i = fork();
231                 if(i == -1) {
232                         perror("cannot fork");
233                         exit(1);
234                 }
235                 if(i != 0) {
236                         exit(0); // the parent
237                 }
238         }
239
240         // Set new file permissions
241         umask(0);
242
243         // close all files
244         if(close_all_files) {
245                 int i;
246                 for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
247                         if(
248                                 ((access_fd && i != *access_fd) || !access_fd)
249                                 && i != dev_null
250                                 && i != input_fd
251                                 && i != output_fd
252                                 && i != error_fd
253                                 && fd_is_valid(i)
254                                 ) close(i);
255         }
256         else {
257                 close(STDIN_FILENO);
258                 close(STDOUT_FILENO);
259                 close(STDERR_FILENO);
260         }
261
262         // put the opened files
263         // to our standard file descriptors
264         if(input_fd != -1) {
265                 if(input_fd != STDIN_FILENO) {
266                         dup2(input_fd, STDIN_FILENO);
267                         close(input_fd);
268                 }
269                 input_fd = -1;
270         }
271         else dup2(dev_null, STDIN_FILENO);
272
273         if(output_fd != -1) {
274                 if(output_fd != STDOUT_FILENO) {
275                         dup2(output_fd, STDOUT_FILENO);
276                         close(output_fd);
277                 }
278                 output_fd = -1;
279         }
280         else dup2(dev_null, STDOUT_FILENO);
281
282         if(error_fd != -1) {
283                 if(error_fd != STDERR_FILENO) {
284                         dup2(error_fd, STDERR_FILENO);
285                         close(error_fd);
286                 }
287                 error_fd = -1;
288         }
289         else dup2(dev_null, STDERR_FILENO);
290
291         // close /dev/null
292         if(dev_null != STDIN_FILENO && dev_null != STDOUT_FILENO && dev_null != STDERR_FILENO)
293                 close(dev_null);
294
295         // generate our pid file
296         {
297                 unlink(pidfile);
298                 int fd = open(pidfile, O_RDWR | O_CREAT, 0666);
299                 if(fd >= 0) {
300                         char b[100];
301                         sprintf(b, "%d\n", getpid());
302                         ssize_t i = write(fd, b, strlen(b));
303                         if(i <= 0) perror("Cannot write pid to file.");
304                         close(fd);
305                 }
306         }
307
308         if(user && *user) {
309                 if(become_user(user) != 0) {
310                         error("Cannot become user '%s'. Continuing as we are.", user);
311                 }
312                 else info("Successfully became user '%s'.", user);
313         }
314
315         return(0);
316 }