root/src/noitd.c

Revision 8c8aea6bc50ed2cc0619d0585a079dc9a4de6a16, 10.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 4 years ago)

lockfile as root node attribute in both noit.conf and stratcon.conf, closes #263

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007-2009, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 #include "noit_defines.h"
33
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <sys/mman.h>
41 #include <signal.h>
42 #ifdef HAVE_SYS_WAIT_H
43 #include <sys/wait.h>
44 #endif
45
46 #include "eventer/eventer.h"
47 #include "utils/noit_log.h"
48 #include "utils/noit_hash.h"
49 #include "utils/noit_security.h"
50 #include "utils/noit_watchdog.h"
51 #include "utils/noit_lockfile.h"
52 #include "noit_listener.h"
53 #include "noit_console.h"
54 #include "noit_jlog_listener.h"
55 #include "noit_rest.h"
56 #include "noit_check_rest.h"
57 #include "noit_livestream_listener.h"
58 #include "noit_capabilities_listener.h"
59 #include "noit_module.h"
60 #include "noit_conf.h"
61 #include "noit_conf_checks.h"
62 #include "noit_filters.h"
63
64 #define APPNAME "noit"
65 #define CHILD_WATCHDOG_TIMEOUT 5 /*seconds*/
66
67 static char *config_file = ETC_DIR "/" APPNAME ".conf";
68 static const char *droptouser = NULL;
69 static const char *droptogroup = NULL;
70 static const char *chrootpath = NULL;
71 static int foreground = 0;
72 static int debug = 0;
73 static int strict_module_load = 0;
74 static char **enable_logs;
75 static int enable_logs_cnt = 0;
76 static char **disable_logs;
77 static int disable_logs_cnt = 0;
78
79 #include "man/noitd.usage.h"
80 static void usage(const char *progname) {
81   printf("Usage for %s:\n", progname);
82 #ifdef NOITD_USAGE
83   assert(write(STDOUT_FILENO,
84                NOITD_USAGE,
85                sizeof(NOITD_USAGE)-1) == sizeof(NOITD_USAGE)-1);
86 #else
87   printf("\nError in usage, build problem.\n");
88 #endif
89   return;
90 }
91
92 void cli_log_switches() {
93   int i;
94   noit_log_stream_t ls;
95   for(i=0; i<enable_logs_cnt; i++) {
96     ls = noit_log_stream_find(enable_logs[i]);
97     if(!ls) noitL(noit_error, "No such log: '%s'\n", enable_logs[i]);
98     if(ls && !ls->enabled) {
99       noitL(noit_error, "Enabling %s\n", enable_logs[i]);
100       ls->enabled = 1;
101     }
102   }
103   for(i=0; i<disable_logs_cnt; i++) {
104     ls = noit_log_stream_find(disable_logs[i]);
105     if(!ls) noitL(noit_error, "No such log: '%s'\n", enable_logs[i]);
106     if(ls && ls->enabled) {
107       noitL(noit_error, "Disabling %s\n", disable_logs[i]);
108       ls->enabled = 0;
109     }
110   }
111 }
112 void parse_clargs(int argc, char **argv) {
113   int c;
114   enable_logs = calloc(argc, sizeof(*enable_logs));
115   disable_logs = calloc(argc, sizeof(*disable_logs));
116   while((c = getopt(argc, argv, "Mhc:dDu:g:t:l:L:")) != EOF) {
117     switch(c) {
118       case 'M':
119         strict_module_load = 1;
120         break;
121       case 'h':
122         usage(argv[0]);
123         exit(1);
124         break;
125       case 'l':
126         enable_logs[enable_logs_cnt++] = strdup(optarg);
127         break;
128       case 'L':
129         disable_logs[disable_logs_cnt++] = strdup(optarg);
130         break;
131       case 'u':
132         droptouser = strdup(optarg);
133         break;
134       case 'g':
135         droptogroup = strdup(optarg);
136         break;
137       case 't':
138         chrootpath = strdup(optarg);
139         break;
140       case 'c':
141         config_file = strdup(optarg);
142         break;
143       case 'D':
144         foreground = 1;
145         break;
146       case 'd':
147         debug++;
148         break;
149       default:
150         break;
151     }
152   }
153 }
154
155 static
156 int configure_eventer() {
157   int rv = 0;
158   noit_hash_table *table;
159   table = noit_conf_get_hash(NULL, "/" APPNAME "/eventer/config");
160   if(table) {
161     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
162     const char *key, *value;
163     int klen;
164     while(noit_hash_next_str(table, &iter, &key, &klen, &value)) {
165       int subrv;
166       if((subrv = eventer_propset(key, value)) != 0)
167         rv = subrv;
168     }
169     noit_hash_destroy(table, free, free);
170     free(table);
171   }
172   return rv;
173 }
174
175 static int __reload_needed = 0;
176 static void request_conf_reload(int sig) {
177   if(sig == SIGHUP) {
178     __reload_needed = 1;
179   }
180 }
181 static int noitice_hup(eventer_t e, int mask, void *unused, struct timeval *now) {
182   if(__reload_needed) {
183     noitL(noit_error, "SIGHUP received, performing reload\n");
184     if(noit_conf_load(config_file) == -1) {
185       noitL(noit_error, "Cannot load config: '%s'\n", config_file);
186       exit(-1);
187     }
188     noit_poller_reload(NULL);
189     __reload_needed = 0;
190   }
191   return 0;
192 }
193 static int child_main() {
194   eventer_t e;
195
196   /* Load our config...
197    * to ensure it is current w.r.t. to this child starting */
198   if(noit_conf_load(config_file) == -1) {
199     noitL(noit_error, "Cannot load config: '%s'\n", config_file);
200     exit(2);
201   }
202
203   noit_log_reopen_all();
204
205   signal(SIGHUP, request_conf_reload);
206
207   /* initialize the eventer */
208   if(eventer_init() == -1) {
209     noitL(noit_stderr, "Cannot initialize eventer\n");
210     exit(-1);
211   }
212
213   /* Setup our heartbeat */
214   noit_watchdog_child_eventer_heartbeat();
215
216   e = eventer_alloc();
217   e->mask = EVENTER_RECURRENT;
218   e->callback = noitice_hup;
219   eventer_add_recurrent(e);
220
221   /* Initialize all of our listeners */
222   noit_console_init(APPNAME);
223   noit_console_conf_init();
224   noit_console_conf_checks_init();
225   noit_capabilities_listener_init();
226   noit_jlog_listener_init();
227   noit_http_rest_init();
228   noit_check_rest_init();
229   noit_filters_rest_init();
230   noit_livestream_listener_init();
231
232   noit_module_init();
233   if(strict_module_load && noit_module_load_failures() > 0) {
234     noitL(noit_stderr, "Failed to load some modules and -M given.\n");
235     exit(2);
236   }
237
238   /* Drop privileges */
239   if(chrootpath && noit_security_chroot(chrootpath)) {
240     noitL(noit_stderr, "Failed to chroot(), exiting.\n");
241     exit(2);
242   }
243   if(noit_security_usergroup(droptouser, droptogroup, noit_false)) {
244     noitL(noit_stderr, "Failed to drop privileges, exiting.\n");
245     exit(2);
246   }
247
248   /* Prepare for launch... */
249   noit_filters_init();
250   noit_poller_init();
251   noit_listener_init(APPNAME);
252
253   /* Write our log out, and setup a watchdog to write it out on change. */
254   noit_conf_write_log(NULL);
255   noit_conf_coalesce_changes(10); /* 10 seconds of no changes before we write */
256   noit_conf_watch_and_journal_watchdog(noit_conf_write_log, NULL);
257
258   eventer_loop();
259   return 0;
260 }
261
262 int main(int argc, char **argv) {
263   int fd;
264   char conf_str[1024];
265   char user[32], group[32];
266
267   parse_clargs(argc, argv);
268
269   /* First initialize logging, so we can log errors */
270   noit_log_init();
271   noit_log_stream_add_stream(noit_debug, noit_stderr);
272   noit_log_stream_add_stream(noit_error, noit_stderr);
273
274   /* Next load the configs */
275   noit_conf_init(APPNAME);
276   if(noit_conf_load(config_file) == -1) {
277     fprintf(stderr, "Cannot load config: '%s'\n", config_file);
278     exit(-1);
279   }
280
281   /* Reinitialize the logging system now that we have a config */
282   snprintf(user, sizeof(user), "%d", getuid());
283   snprintf(group, sizeof(group), "%d", getgid());
284   if(noit_security_usergroup(droptouser, droptogroup, noit_true)) {
285     noitL(noit_stderr, "Failed to drop privileges, exiting.\n");
286     exit(-1);
287   }
288   noit_conf_log_init(APPNAME);
289   cli_log_switches();
290   if(noit_security_usergroup(user, group, noit_true)) {
291     noitL(noit_stderr, "Failed to regain privileges, exiting.\n");
292     exit(-1);
293   }
294   if(debug)
295     noit_debug->enabled = 1;
296
297   /* Lastly, run through all other system inits */
298   if(!noit_conf_get_stringbuf(NULL, "/" APPNAME "/eventer/@implementation",
299                               conf_str, sizeof(conf_str))) {
300     noitL(noit_stderr, "Cannot find '%s' in configuration\n",
301           "/" APPNAME "/eventer/@implementation");
302     exit(-1);
303   }
304   if(eventer_choose(conf_str) == -1) {
305     noitL(noit_stderr, "Cannot choose eventer %s\n", conf_str);
306     exit(-1);
307   }
308   if(configure_eventer() != 0) {
309     noitL(noit_stderr, "Cannot configure eventer\n");
310     exit(-1);
311   }
312
313   noit_watchdog_prefork_init();
314
315   if(chdir("/") != 0) {
316     noitL(noit_stderr, "Failed chdir(\"/\"): %s\n", strerror(errno));
317     exit(-1);
318   }
319
320   /* Acquire the lock so that we can throw an error if it doesn't work.
321    * If we've started -D, we'll have the lock.
322    * If not we will daemon and must reacquire the lock.
323    */
324   if(noit_conf_get_stringbuf(NULL, "/" APPNAME "/@lockfile",
325                              conf_str, sizeof(conf_str))) {
326     if(noit_lockfile_acquire(conf_str) < 0) {
327       noitL(noit_stderr, "Failed to acquire lock: %s\n", conf_str);
328       exit(-1);
329     }
330   }
331
332   if(foreground) return child_main();
333
334   open("/dev/null", O_RDWR);
335   dup2(fd, STDIN_FILENO);
336   dup2(fd, STDOUT_FILENO);
337   dup2(fd, STDERR_FILENO);
338   if(fork()) exit(0);
339   setsid();
340   if(fork()) exit(0);
341
342   /* Reacquire the lock */
343   if(noit_conf_get_stringbuf(NULL, "/" APPNAME "/@lockfile",
344                              conf_str, sizeof(conf_str))) {
345     if(noit_lockfile_acquire(conf_str) < 0) {
346       noitL(noit_stderr, "Failed to acquire lock: %s\n", conf_str);
347       exit(-1);
348     }
349   }
350
351   signal(SIGHUP, SIG_IGN);
352   return noit_watchdog_start_child("noitd", child_main, 0);
353 }
Note: See TracBrowser for help on using the browser.