]> arthur.barton.de Git - netdata.git/blob - src/daemon.c
Remove warning in signal handler.
[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         if(signo)
34                 netdata_exit = 1;
35 }
36
37 int become_user(const char *username)
38 {
39         struct passwd *pw = getpwnam(username);
40         if(!pw) {
41                 error("User %s is not present.", username);
42                 return -1;
43         }
44
45         uid_t uid = pw->pw_uid;
46         gid_t gid = pw->pw_gid;
47
48         int ngroups =  sysconf(_SC_NGROUPS_MAX);
49         gid_t *supplementary_groups = NULL;
50         if(ngroups) {
51                 supplementary_groups = malloc(sizeof(gid_t) * ngroups);
52                 if(supplementary_groups) {
53                         if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
54                                 error("Cannot get supplementary groups of user '%s'.", username);
55                                 free(supplementary_groups);
56                                 supplementary_groups = NULL;
57                                 ngroups = 0;
58                         }
59                 }
60                 else fatal("Cannot allocate memory for %d supplementary groups", ngroups);
61         }
62
63         if(pidfile[0] && getuid() != uid) {
64                 // we are dropping privileges
65                 if(chown(pidfile, uid, gid) != 0)
66                         error("Cannot chown pidfile '%s' to user '%s'", pidfile, username);
67
68                 else if(pidfd != -1) {
69                         // not need to keep it open
70                         close(pidfd);
71                         pidfd = -1;
72                 }
73         }
74         else if(pidfd != -1) {
75                 // not need to keep it open
76                 close(pidfd);
77                 pidfd = -1;
78         }
79
80         if(supplementary_groups && ngroups) {
81                 if(setgroups(ngroups, supplementary_groups) == -1)
82                         error("Cannot set supplementary groups for user '%s'", username);
83
84                 free(supplementary_groups);
85                 supplementary_groups = NULL;
86                 ngroups = 0;
87         }
88
89         if(setresgid(gid, gid, gid) != 0) {
90                 error("Cannot switch to user's %s group (gid: %d).", username, gid);
91                 return -1;
92         }
93
94         if(setresuid(uid, uid, uid) != 0) {
95                 error("Cannot switch to user %s (uid: %d).", username, uid);
96                 return -1;
97         }
98
99         if(setgid(gid) != 0) {
100                 error("Cannot switch to user's %s group (gid: %d).", username, gid);
101                 return -1;
102         }
103         if(setegid(gid) != 0) {
104                 error("Cannot effectively switch to user's %s group (gid: %d).", username, gid);
105                 return -1;
106         }
107         if(setuid(uid) != 0) {
108                 error("Cannot switch to user %s (uid: %d).", username, uid);
109                 return -1;
110         }
111         if(seteuid(uid) != 0) {
112                 error("Cannot effectively switch to user %s (uid: %d).", username, uid);
113                 return -1;
114         }
115
116         return(0);
117 }
118
119 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)
120 {
121         fflush(NULL);
122
123         // open the files before forking
124         int input_fd = -1, output_fd = -1, error_fd = -1, dev_null;
125
126         if(input && *input) {
127                 if((input_fd = open(input, O_RDONLY, 0666)) == -1) {
128                         error("Cannot open input file '%s'.", input);
129                         return -1;
130                 }
131         }
132
133         if(output && *output) {
134                 if((output_fd = open(output, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
135                         error("Cannot open output log file '%s'", output);
136                         if(input_fd != -1) close(input_fd);
137                         return -1;
138                 }
139         }
140
141         if(error && *error) {
142                 if((error_fd = open(error, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
143                         error("Cannot open error log file '%s'.", error);
144                         if(input_fd != -1) close(input_fd);
145                         if(output_fd != -1) close(output_fd);
146                         return -1;
147                 }
148         }
149
150         if(access && *access && access_fd) {
151                 if((*access_fd = open(access, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) {
152                         error("Cannot open access log file '%s'", access);
153                         if(input_fd != -1) close(input_fd);
154                         if(output_fd != -1) close(output_fd);
155                         if(error_fd != -1) close(error_fd);
156                         return -1;
157                 }
158
159                 if(access_fp) {
160                         *access_fp = fdopen(*access_fd, "w");
161                         if(!*access_fp) {
162                                 error("Cannot migrate file's '%s' fd %d.", access, *access_fd);
163                                 if(input_fd != -1) close(input_fd);
164                                 if(output_fd != -1) close(output_fd);
165                                 if(error_fd != -1) close(error_fd);
166                                 close(*access_fd);
167                                 *access_fd = -1;
168                                 return -1;
169                         }
170                 }
171         }
172
173         if((dev_null = open("/dev/null", O_RDWR, 0666)) == -1) {
174                 perror("Cannot open /dev/null");
175                 if(input_fd != -1) close(input_fd);
176                 if(output_fd != -1) close(output_fd);
177                 if(error_fd != -1) close(error_fd);
178                 if(access && access_fd && *access_fd != -1) {
179                         close(*access_fd);
180                         *access_fd = -1;
181                         if(access_fp) {
182                                 fclose(*access_fp);
183                                 *access_fp = NULL;
184                         }
185                 }
186                 return -1;
187         }
188
189         // all files opened
190         // lets do it
191
192         if(!dont_fork) {
193                 int i = fork();
194                 if(i == -1) {
195                         perror("cannot fork");
196                         exit(1);
197                 }
198                 if(i != 0) {
199                         exit(0); // the parent
200                 }
201
202                 // become session leader
203                 if (setsid() < 0) {
204                         perror("Cannot become session leader.");
205                         exit(2);
206                 }
207         }
208
209         // fork() again
210         if(!dont_fork) {
211                 int i = fork();
212                 if(i == -1) {
213                         perror("cannot fork");
214                         exit(1);
215                 }
216                 if(i != 0) {
217                         exit(0); // the parent
218                 }
219         }
220
221         // Set new file permissions
222         umask(0);
223
224         // close all files
225         if(close_all_files) {
226                 int i;
227                 for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
228                         if(
229                                 ((access_fd && i != *access_fd) || !access_fd)
230                                 && i != dev_null
231                                 && i != input_fd
232                                 && i != output_fd
233                                 && i != error_fd
234                                 && fd_is_valid(i)
235                                 ) close(i);
236         }
237         else {
238                 close(STDIN_FILENO);
239                 close(STDOUT_FILENO);
240                 close(STDERR_FILENO);
241         }
242
243         // put the opened files
244         // to our standard file descriptors
245         if(input_fd != -1) {
246                 if(input_fd != STDIN_FILENO) {
247                         dup2(input_fd, STDIN_FILENO);
248                         close(input_fd);
249                 }
250                 input_fd = -1;
251         }
252         else dup2(dev_null, STDIN_FILENO);
253
254         if(output_fd != -1) {
255                 if(output_fd != STDOUT_FILENO) {
256                         dup2(output_fd, STDOUT_FILENO);
257                         close(output_fd);
258                 }
259                 output_fd = -1;
260         }
261         else dup2(dev_null, STDOUT_FILENO);
262
263         if(error_fd != -1) {
264                 if(error_fd != STDERR_FILENO) {
265                         dup2(error_fd, STDERR_FILENO);
266                         close(error_fd);
267                 }
268                 error_fd = -1;
269         }
270         else dup2(dev_null, STDERR_FILENO);
271
272         // close /dev/null
273         if(dev_null != STDIN_FILENO && dev_null != STDOUT_FILENO && dev_null != STDERR_FILENO)
274                 close(dev_null);
275
276         // generate our pid file
277         if(pidfile[0]) {
278                 pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
279                 if(pidfd >= 0) {
280                         if(ftruncate(pidfd, 0) != 0)
281                                 error("Cannot truncate pidfile '%s'.", pidfile);
282
283                         char b[100];
284                         sprintf(b, "%d\n", getpid());
285                         ssize_t i = write(pidfd, b, strlen(b));
286                         if(i <= 0)
287                                 error("Cannot write pidfile '%s'.", pidfile);
288
289                         // don't close it, we might need it at exit
290                         // close(pidfd);
291                 }
292                 else error("Failed to open pidfile '%s'.", pidfile);
293         }
294
295         if(user && *user) {
296                 if(become_user(user) != 0) {
297                         error("Cannot become user '%s'. Continuing as we are.", user);
298                 }
299                 else info("Successfully became user '%s'.", user);
300         }
301         else if(pidfd != -1)
302                 close(pidfd);
303
304         return(0);
305 }