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