]> arthur.barton.de Git - netdata.git/blob - src/daemon.c
less INFO messages - they are now DEBUG; fixes #459
[netdata.git] / src / daemon.c
1 #include "common.h"
2 #include <sched.h>
3
4 char pidfile[FILENAME_MAX + 1] = "";
5
6 void sig_handler_exit(int signo)
7 {
8     if(signo) {
9         error_log_limit_unlimited();
10         error("Received signal %d. Exiting...", signo);
11         netdata_exit = 1;
12     }
13 }
14
15 void sig_handler_logrotate(int signo)
16 {
17     if(signo) {
18         error_log_limit_unlimited();
19         info("Received signal %d to re-open the log files", signo);
20         reopen_all_log_files();
21         error_log_limit_reset();
22     }
23 }
24
25 void sig_handler_save(int signo)
26 {
27     if(signo) {
28         error_log_limit_unlimited();
29         info("Received signal %d to save the database...", signo);
30         rrdset_save_all();
31         error_log_limit_reset();
32     }
33 }
34
35 void sig_handler_reload_health(int signo)
36 {
37     if(signo) {
38         error_log_limit_unlimited();
39         info("Received signal %d to reload health configuration...", signo);
40         health_reload();
41         error_log_limit_reset();
42     }
43 }
44
45 static void chown_open_file(int fd, uid_t uid, gid_t gid) {
46     if(fd == -1) return;
47
48     struct stat buf;
49
50     if(fstat(fd, &buf) == -1) {
51         error("Cannot fstat() fd %d", fd);
52         return;
53     }
54
55     if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
56         if(fchown(fd, uid, gid) == -1)
57             error("Cannot fchown() fd %d.", fd);
58     }
59 }
60
61 int become_user(const char *username, int pid_fd)
62 {
63     struct passwd *pw = getpwnam(username);
64     if(!pw) {
65         error("User %s is not present.", username);
66         return -1;
67     }
68
69     uid_t uid = pw->pw_uid;
70     gid_t gid = pw->pw_gid;
71
72     int ngroups = (int)sysconf(_SC_NGROUPS_MAX);
73     gid_t *supplementary_groups = NULL;
74     if(ngroups) {
75         supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
76         if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
77             error("Cannot get supplementary groups of user '%s'.", username);
78             freez(supplementary_groups);
79             supplementary_groups = NULL;
80             ngroups = 0;
81         }
82     }
83
84     chown_open_file(STDOUT_FILENO, uid, gid);
85     chown_open_file(STDERR_FILENO, uid, gid);
86     chown_open_file(stdaccess_fd, uid, gid);
87     chown_open_file(pid_fd, uid, gid);
88
89     if(supplementary_groups && ngroups) {
90         if(setgroups(ngroups, supplementary_groups) == -1)
91             error("Cannot set supplementary groups for user '%s'", username);
92
93         freez(supplementary_groups);
94         supplementary_groups = NULL;
95         ngroups = 0;
96     }
97
98     if(setresgid(gid, gid, gid) != 0) {
99         error("Cannot switch to user's %s group (gid: %u).", username, gid);
100         return -1;
101     }
102
103     if(setresuid(uid, uid, uid) != 0) {
104         error("Cannot switch to user %s (uid: %u).", username, uid);
105         return -1;
106     }
107
108     if(setgid(gid) != 0) {
109         error("Cannot switch to user's %s group (gid: %u).", username, gid);
110         return -1;
111     }
112     if(setegid(gid) != 0) {
113         error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
114         return -1;
115     }
116     if(setuid(uid) != 0) {
117         error("Cannot switch to user %s (uid: %u).", username, uid);
118         return -1;
119     }
120     if(seteuid(uid) != 0) {
121         error("Cannot effectively switch to user %s (uid: %u).", username, uid);
122         return -1;
123     }
124
125     return(0);
126 }
127
128 void oom_score_adj(int score) {
129     int done = 0;
130     int fd = open("/proc/self/oom_score_adj", O_WRONLY);
131     if(fd != -1) {
132         char buf[10 + 1];
133         ssize_t len = snprintfz(buf, 10, "%d", score);
134         if(write(fd, buf, len) == len) done = 1;
135         close(fd);
136     }
137
138     if(!done)
139         error("Cannot adjust my Out-Of-Memory score to %d.", score);
140     else
141         debug(D_SYSTEM, "Adjusted my Out-Of-Memory score to %d.", score);
142 }
143
144 int sched_setscheduler_idle(void) {
145 #ifdef SCHED_IDLE
146     const struct sched_param param = {
147         .sched_priority = 0
148     };
149
150     int i = sched_setscheduler(0, SCHED_IDLE, &param);
151     if(i != 0)
152         error("Cannot adjust my scheduling priority to IDLE.");
153     else
154         debug(D_SYSTEM, "Adjusted my scheduling priority to IDLE.");
155
156     return i;
157 #else
158     return -1;
159 #endif
160 }
161
162 int become_daemon(int dont_fork, const char *user)
163 {
164     if(!dont_fork) {
165         int i = fork();
166         if(i == -1) {
167             perror("cannot fork");
168             exit(1);
169         }
170         if(i != 0) {
171             exit(0); // the parent
172         }
173
174         // become session leader
175         if (setsid() < 0) {
176             perror("Cannot become session leader.");
177             exit(2);
178         }
179
180         // fork() again
181         i = fork();
182         if(i == -1) {
183             perror("cannot fork");
184             exit(1);
185         }
186         if(i != 0) {
187             exit(0); // the parent
188         }
189     }
190
191     // generate our pid file
192     int pidfd = -1;
193     if(pidfile[0]) {
194         pidfd = open(pidfile, O_WRONLY | O_CREAT, 0644);
195         if(pidfd >= 0) {
196             if(ftruncate(pidfd, 0) != 0)
197                 error("Cannot truncate pidfile '%s'.", pidfile);
198
199             char b[100];
200             sprintf(b, "%d\n", getpid());
201             ssize_t i = write(pidfd, b, strlen(b));
202             if(i <= 0)
203                 error("Cannot write pidfile '%s'.", pidfile);
204         }
205         else error("Failed to open pidfile '%s'.", pidfile);
206     }
207
208     // Set new file permissions
209     umask(0002);
210
211     // adjust my Out-Of-Memory score
212     oom_score_adj(1000);
213
214     // never become a problem
215     if(sched_setscheduler_idle() != 0) {
216         if(nice(19) == -1) error("Cannot lower my CPU priority.");
217         else debug(D_SYSTEM, "Set my nice value to 19.");
218     }
219
220     if(user && *user) {
221         if(become_user(user, pidfd) != 0) {
222             error("Cannot become user '%s'. Continuing as we are.", user);
223         }
224         else debug(D_SYSTEM, "Successfully became user '%s'.", user);
225     }
226
227     if(pidfd != -1) {
228         close(pidfd);
229         pidfd = -1;
230     }
231
232     return(0);
233 }