]> arthur.barton.de Git - netdata.git/blob - src/daemon.c
enable line buffering on all log 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 <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                         if(setvbuf(*access_fp, NULL, _IOLBF, 0) != 0)
212                                 error("Cannot set line buffering on access.log");
213                 }
214         }
215
216         if((dev_null = open("/dev/null", O_RDWR, 0666)) == -1) {
217                 perror("Cannot open /dev/null");
218                 if(input_fd != -1) close(input_fd);
219                 if(output_fd != -1) close(output_fd);
220                 if(error_fd != -1) close(error_fd);
221                 if(access && access_fd && *access_fd != -1) {
222                         close(*access_fd);
223                         *access_fd = -1;
224                         if(access_fp) {
225                                 fclose(*access_fp);
226                                 *access_fp = NULL;
227                         }
228                 }
229                 return -1;
230         }
231
232         // all files opened
233         // lets do it
234
235         if(!dont_fork) {
236                 int i = fork();
237                 if(i == -1) {
238                         perror("cannot fork");
239                         exit(1);
240                 }
241                 if(i != 0) {
242                         exit(0); // the parent
243                 }
244
245                 // become session leader
246                 if (setsid() < 0) {
247                         perror("Cannot become session leader.");
248                         exit(2);
249                 }
250         }
251
252         signal(SIGCHLD,  SIG_IGN);
253         signal(SIGHUP,   SIG_IGN);
254         signal(SIGWINCH, SIG_IGN);
255
256         // fork() again
257         if(!dont_fork) {
258                 int i = fork();
259                 if(i == -1) {
260                         perror("cannot fork");
261                         exit(1);
262                 }
263                 if(i != 0) {
264                         exit(0); // the parent
265                 }
266         }
267
268         // Set new file permissions
269         umask(0);
270
271         // close all files
272         if(close_all_files) {
273                 int i;
274                 for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
275                         if(
276                                 ((access_fd && i != *access_fd) || !access_fd)
277                                 && i != dev_null
278                                 && i != input_fd
279                                 && i != output_fd
280                                 && i != error_fd
281                                 && fd_is_valid(i)
282                                 ) close(i);
283         }
284         else {
285                 close(STDIN_FILENO);
286                 close(STDOUT_FILENO);
287                 close(STDERR_FILENO);
288         }
289
290         // put the opened files
291         // to our standard file descriptors
292         if(input_fd != -1) {
293                 if(input_fd != STDIN_FILENO) {
294                         dup2(input_fd, STDIN_FILENO);
295                         close(input_fd);
296                 }
297                 input_fd = -1;
298         }
299         else dup2(dev_null, STDIN_FILENO);
300
301         if(output_fd != -1) {
302                 if(output_fd != STDOUT_FILENO) {
303                         dup2(output_fd, STDOUT_FILENO);
304                         close(output_fd);
305                 }
306
307                 if(setvbuf(stdout, NULL, _IOLBF, 0) != 0)
308                         error("Cannot set line buffering on debug.log");
309
310                 output_fd = -1;
311         }
312         else dup2(dev_null, STDOUT_FILENO);
313
314         if(error_fd != -1) {
315                 if(error_fd != STDERR_FILENO) {
316                         dup2(error_fd, STDERR_FILENO);
317                         close(error_fd);
318                 }
319
320                 if(setvbuf(stderr, NULL, _IOLBF, 0) != 0)
321                         error("Cannot set line buffering on error.log");
322
323                 error_fd = -1;
324         }
325         else dup2(dev_null, STDERR_FILENO);
326
327         // close /dev/null
328         if(dev_null != STDIN_FILENO && dev_null != STDOUT_FILENO && dev_null != STDERR_FILENO)
329                 close(dev_null);
330
331         // generate our pid file
332         if(pidfile[0]) {
333                 pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
334                 if(pidfd >= 0) {
335                         if(ftruncate(pidfd, 0) != 0)
336                                 error("Cannot truncate pidfile '%s'.", pidfile);
337
338                         char b[100];
339                         sprintf(b, "%d\n", getpid());
340                         ssize_t i = write(pidfd, b, strlen(b));
341                         if(i <= 0)
342                                 error("Cannot write pidfile '%s'.", pidfile);
343
344                         // don't close it, we might need it at exit
345                         // close(pidfd);
346                 }
347                 else error("Failed to open pidfile '%s'.", pidfile);
348         }
349
350         if(user && *user) {
351                 if(become_user(user) != 0) {
352                         error("Cannot become user '%s'. Continuing as we are.", user);
353                 }
354                 else info("Successfully became user '%s'.", user);
355         }
356         else if(pidfd != -1)
357                 close(pidfd);
358
359         return(0);
360 }