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