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