root/src/noitd.c

Revision 21b0c6c1011f78327925b8a1914d98cdd5cd43d5, 7.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

first whack at feeding actual data. refs #71

  • Property mode set to 100644
Line 
1 #include "noit_defines.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <sys/ioctl.h>
8 #include <fcntl.h>
9 #include <sys/mman.h>
10 #include <signal.h>
11 #ifdef HAVE_SYS_WAIT_H
12 #include <sys/wait.h>
13 #endif
14
15 #include "eventer/eventer.h"
16 #include "utils/noit_log.h"
17 #include "utils/noit_hash.h"
18 #include "utils/noit_security.h"
19 #include "noit_listener.h"
20 #include "noit_console.h"
21 #include "noit_jlog_listener.h"
22 #include "noit_livestream_listener.h"
23 #include "noit_module.h"
24 #include "noit_conf.h"
25 #include "noit_conf_checks.h"
26 #include "noit_filters.h"
27
28 #define APPNAME "noit"
29 #define CHILD_WATCHDOG_TIMEOUT 5 /*seconds*/
30
31 static char *config_file = ETC_DIR "/" APPNAME ".conf";
32 static const char *droptouser = NULL;
33 static const char *droptogroup = NULL;
34 static const char *chrootpath = NULL;
35 static int foreground = 0;
36 static int debug = 0;
37
38 #include "man/noitd.usage.h"
39 static void usage(const char *progname) {
40   printf("Usage for %s:\n", progname);
41 #ifdef NOITD_USAGE
42   write(STDOUT_FILENO, NOITD_USAGE, sizeof(NOITD_USAGE)-1);
43 #else
44   printf("\nError in usage, build problem.\n");
45 #endif
46   return;
47 }
48 void parse_clargs(int argc, char **argv) {
49   int c;
50   while((c = getopt(argc, argv, "hc:dDu:g:t:")) != EOF) {
51     switch(c) {
52       case 'h':
53         usage(argv[0]);
54         exit(1);
55         break;
56       case 'u':
57         droptouser = strdup(optarg);
58         break;
59       case 'g':
60         droptogroup = strdup(optarg);
61         break;
62       case 't':
63         chrootpath = strdup(optarg);
64         break;
65       case 'c':
66         config_file = strdup(optarg);
67         break;
68       case 'D':
69         foreground = 1;
70         break;
71       case 'd':
72         debug++;
73         break;
74       default:
75         break;
76     }
77   }
78 }
79
80 static
81 int configure_eventer() {
82   int rv = 0;
83   noit_hash_table *table;
84   table = noit_conf_get_hash(NULL, "/" APPNAME "/eventer/config");
85   if(table) {
86     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
87     const char *key, *value;
88     int klen;
89     while(noit_hash_next(table, &iter, &key, &klen, (void **)&value)) {
90       int subrv;
91       if((subrv = eventer_propset(key, value)) != 0)
92         rv = subrv;
93     }
94     noit_hash_destroy(table, free, free);
95     free(table);
96   }
97   return rv;
98 }
99
100 /* Watchdog stuff */
101 static int *lifeline = NULL;
102 static unsigned long last_tick_time() {
103   static struct timeval lastchange = { 0, 0 };
104   static int lastcheck = 0;
105   struct timeval now, diff;
106
107   gettimeofday(&now, NULL);
108   if(lastcheck != *lifeline) {
109     lastcheck = *lifeline;
110     memcpy(&lastchange, &now, sizeof(lastchange));
111   }
112   sub_timeval(now, lastchange, &diff);
113   return (unsigned long)diff.tv_sec;
114 }
115 static void it_ticks() {
116   (*lifeline)++;
117 }
118 static void setup_mmap() {
119   lifeline = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE,
120                   MAP_SHARED|MAP_ANON, -1, 0);
121   if(lifeline == (void *)-1) {
122     noitL(noit_error, "Failed to mmap anon for watchdog\n");
123     exit(-1);
124   }
125 }
126
127 static int watch_over_child(int (*func)()) {
128   int child_pid;
129   while(1) {
130     child_pid = fork();
131     if(child_pid == -1) {
132       noitL(noit_error, "fork failed: %s\n", strerror(errno));
133       exit(-1);
134     }
135     if(child_pid == 0) {
136       /* This sets up things so we start alive */
137       it_ticks();
138       /* run the program */
139       exit(func());
140     }
141     else {
142       int sig = -1, exit_val = -1;
143       while(1) {
144         unsigned long ltt;
145         int status, rv;
146         sleep(1); /* Just check child status every second */
147         rv = waitpid(child_pid, &status, WNOHANG);
148         if(rv == 0) {
149           /* Nothing */
150         }
151         else if (rv == child_pid) {
152           /* We died!... we need to relaunch, unless the status was a requested exit (2) */
153           sig = WTERMSIG(status);
154           exit_val = WEXITSTATUS(status);
155           if(sig == SIGINT || sig == SIGQUIT ||
156              (sig == 0 && (exit_val == 2 || exit_val < 0))) {
157             noitL(noit_error, "noitd shutdown acknowledged.\n");
158             exit(0);
159           }
160           break;
161         }
162         else {
163           noitL(noit_error, "Unexpected return from waitpid: %d\n", rv);
164           exit(-1);
165         }
166         /* Now check out timeout */
167         if((ltt = last_tick_time()) > CHILD_WATCHDOG_TIMEOUT) {
168           noitL(noit_error,
169                 "Watchdog timeout (%lu s)... terminating child\n",
170                 ltt);
171           kill(child_pid, SIGKILL);
172         }
173       }
174       noitL(noit_error, "noitd child died [%d/%d], restarting.\n", exit_val, sig);
175     }
176   }
177 }
178
179 static int watchdog_tick(eventer_t e, int mask, void *unused, struct timeval *now) {
180   it_ticks();
181   return 0;
182 }
183 static int child_main() {
184   eventer_t e;
185
186   /* Load our config...
187    * to ensure it is current w.r.t. to this child starting */
188   if(noit_conf_load(config_file) == -1) {
189     noitL(noit_error, "Cannot load config: '%s'\n", config_file);
190     exit(-1);
191   }
192
193   /* initialize the eventer */
194   if(eventer_init() == -1) {
195     noitL(noit_stderr, "Cannot initialize eventer\n");
196     exit(-1);
197   }
198
199   /* Setup our hearbeat */
200   e = eventer_alloc();
201   e->mask = EVENTER_RECURRENT;
202   e->callback = watchdog_tick;
203   eventer_add_recurrent(e);
204
205   /* Initialize all of our listeners */
206   noit_console_init();
207   noit_jlog_listener_init();
208   noit_livestream_listener_init();
209
210   noit_module_init();
211
212   /* Drop privileges */
213   if(chrootpath && noit_security_chroot(chrootpath)) {
214     noitL(noit_stderr, "Failed to chroot(), exiting.\n");
215     exit(-1);
216   }
217   if(noit_security_usergroup(droptouser, droptogroup)) {
218     noitL(noit_stderr, "Failed to drop privileges, exiting.\n");
219     exit(-1);
220   }
221
222   /* Prepare for launch... */
223   noit_filters_init();
224   noit_poller_init();
225   noit_listener_init(APPNAME);
226
227   /* Write our log out, and setup a watchdog to write it out on change. */
228   noit_conf_write_log(NULL);
229   noit_conf_coalesce_changes(10); /* 10 seconds of no changes before we write */
230   noit_conf_watch_and_journal_watchdog(noit_conf_write_log, NULL);
231
232   eventer_loop();
233   return 0;
234 }
235
236 int main(int argc, char **argv) {
237   char conf_str[1024];
238
239   parse_clargs(argc, argv);
240
241   /* First initialize logging, so we can log errors */
242   noit_log_init();
243   noit_log_stream_add_stream(noit_debug, noit_stderr);
244   noit_log_stream_add_stream(noit_error, noit_stderr);
245
246   /* Next load the configs */
247   noit_conf_init(APPNAME);
248   noit_conf_checks_init(APPNAME);
249   if(noit_conf_load(config_file) == -1) {
250     fprintf(stderr, "Cannot load config: '%s'\n", config_file);
251   }
252
253   /* Reinitialize the logging system now that we have a config */
254   noit_conf_log_init(APPNAME);
255   if(debug)
256     noit_debug->enabled = 1;
257
258   /* Lastly, run through all other system inits */
259   if(!noit_conf_get_stringbuf(NULL, "/" APPNAME "/eventer/@implementation",
260                               conf_str, sizeof(conf_str))) {
261     noitL(noit_stderr, "Cannot find '%s' in configuration\n",
262           "/" APPNAME "/eventer/@implementation");
263     exit(-1);
264   }
265   if(eventer_choose(conf_str) == -1) {
266     noitL(noit_stderr, "Cannot choose eventer %s\n", conf_str);
267     exit(-1);
268   }
269   if(configure_eventer() != 0) {
270     noitL(noit_stderr, "Cannot configure eventer\n");
271     exit(-1);
272   }
273
274   setup_mmap();
275
276   chdir("/");
277   if(foreground) return child_main();
278
279   close(STDIN_FILENO);
280   close(STDOUT_FILENO);
281   close(STDERR_FILENO);
282   if(fork()) exit(0);
283   setsid();
284   if(fork()) exit(0);
285
286   return watch_over_child(child_main);
287 }
Note: See TracBrowser for help on using the browser.