root/src/noitd.c

Revision 9a2ae90d6f6b00326969b67ef9abb7b3edf3b59d, 5.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

OpenBSD... refs #48

  • 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 "noit_listener.h"
19 #include "noit_console.h"
20 #include "noit_jlog_listener.h"
21 #include "noit_module.h"
22 #include "noit_conf.h"
23 #include "noit_conf_checks.h"
24 #include "noit_filters.h"
25
26 #define APPNAME "noit"
27 #define CHILD_WATCHDOG_TIMEOUT 5 /*seconds*/
28
29 static char *config_file = ETC_DIR "/" APPNAME ".conf";
30 static int debug = 0;
31
32 void parse_clargs(int argc, char **argv) {
33   int c;
34   while((c = getopt(argc, argv, "c:d")) != EOF) {
35     switch(c) {
36       case 'c':
37         config_file = strdup(optarg);
38         break;
39       case 'd':
40         debug++;
41         break;
42       default:
43         break;
44     }
45   }
46 }
47
48 static
49 int configure_eventer() {
50   int rv = 0;
51   noit_hash_table *table;
52   table = noit_conf_get_hash(NULL, "/" APPNAME "/eventer/config");
53   if(table) {
54     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
55     const char *key, *value;
56     int klen;
57     while(noit_hash_next(table, &iter, &key, &klen, (void **)&value)) {
58       int subrv;
59       if((subrv = eventer_propset(key, value)) != 0)
60         rv = subrv;
61     }
62     noit_hash_destroy(table, free, free);
63     free(table);
64   }
65   return rv;
66 }
67
68 /* Watchdog stuff */
69 static int *lifeline = NULL;
70 static unsigned long last_tick_time() {
71   static struct timeval lastchange = { 0, 0 };
72   static int lastcheck = 0;
73   struct timeval now, diff;
74
75   gettimeofday(&now, NULL);
76   if(lastcheck != *lifeline) {
77     lastcheck = *lifeline;
78     memcpy(&lastchange, &now, sizeof(lastchange));
79   }
80   sub_timeval(now, lastchange, &diff);
81   return (unsigned long)diff.tv_sec;
82 }
83 static void it_ticks() {
84   (*lifeline)++;
85 }
86 static void setup_mmap() {
87   lifeline = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE,
88                   MAP_SHARED|MAP_ANON, -1, 0);
89   if(lifeline == (void *)-1) {
90     noitL(noit_error, "Failed to mmap anon for watchdog\n");
91     exit(-1);
92   }
93 }
94
95 static int watch_over_child(int (*func)()) {
96   int child_pid;
97   setup_mmap();
98   while(1) {
99     child_pid = fork();
100     if(child_pid == -1) {
101       noitL(noit_error, "fork failed: %s\n", strerror(errno));
102       exit(-1);
103     }
104     if(child_pid == 0) {
105       /* This sets up things so we start alive */
106       it_ticks();
107       /* run the program */
108       exit(func());
109     }
110     else {
111       int sig = -1, exit_val = -1;
112       while(1) {
113         unsigned long ltt;
114         int status, rv;
115         sleep(1); /* Just check child status every second */
116         rv = waitpid(child_pid, &status, WNOHANG);
117         if(rv == 0) {
118           /* Nothing */
119         }
120         else if (rv == child_pid) {
121           /* We died!... we need to relaunch, unless the status was a requested exit (2) */
122           sig = WTERMSIG(status);
123           exit_val = WEXITSTATUS(status);
124           if(sig == SIGINT || sig == SIGQUIT ||
125              (sig == 0 && (exit_val == 2 || exit_val < 0))) {
126             noitL(noit_error, "noitd shutdown acknowledged.\n");
127             exit(0);
128           }
129           break;
130         }
131         else {
132           noitL(noit_error, "Unexpected return from waitpid: %d\n", rv);
133           exit(-1);
134         }
135         /* Now check out timeout */
136         if((ltt = last_tick_time()) > CHILD_WATCHDOG_TIMEOUT) {
137           noitL(noit_error,
138                 "Watchdog timeout (%lu s)... terminating child\n",
139                 ltt);
140           kill(child_pid, SIGKILL);
141         }
142       }
143       noitL(noit_error, "noitd child died [%d/%d], restarting.\n", exit_val, sig);
144     }
145   }
146 }
147
148 static int watchdog_tick(eventer_t e, int mask, void *unused, struct timeval *now) {
149   it_ticks();
150   return 0;
151 }
152 static int child_main() {
153   eventer_t e;
154
155   /* Load our config...
156    * to ensure it is current w.r.t. to this child starting */
157   if(noit_conf_load(config_file) == -1) {
158     noitL(noit_error, "Cannot load config: '%s'\n", config_file);
159   }
160
161   /* initialize the eventer */
162   if(eventer_init() == -1) {
163     noitL(noit_stderr, "Cannot initialize eventer\n");
164     exit(-1);
165   }
166
167   /* Setup our hearbeat */
168   e = eventer_alloc();
169   e->mask = EVENTER_RECURRENT;
170   e->callback = watchdog_tick;
171   eventer_add_recurrent(e);
172
173   /* Initialize all of our listeners */
174   noit_console_init();
175   noit_jlog_listener_init();
176
177   noit_module_init();
178   noit_filters_init();
179   noit_poller_init();
180   noit_listener_init(APPNAME);
181
182   /* Write our log out, and setup a watchdog to write it out on change. */
183   noit_conf_write_log(NULL);
184   noit_conf_coalesce_changes(10); /* 10 seconds of no changes before we write */
185   noit_conf_watch_and_journal_watchdog(noit_conf_write_log, NULL);
186
187   eventer_loop();
188   return 0;
189 }
190
191 int main(int argc, char **argv) {
192   char conf_str[1024];
193
194   parse_clargs(argc, argv);
195
196   /* First initialize logging, so we can log errors */
197   noit_log_init();
198   noit_log_stream_add_stream(noit_debug, noit_stderr);
199   noit_log_stream_add_stream(noit_error, noit_stderr);
200
201   /* Next load the configs */
202   noit_conf_init(APPNAME);
203   noit_conf_checks_init(APPNAME);
204   if(noit_conf_load(config_file) == -1) {
205     fprintf(stderr, "Cannot load config: '%s'\n", config_file);
206   }
207
208   /* Reinitialize the logging system now that we have a config */
209   noit_conf_log_init(APPNAME);
210   if(debug)
211     noit_debug->enabled = 1;
212
213   /* Lastly, run through all other system inits */
214   if(!noit_conf_get_stringbuf(NULL, "/" APPNAME "/eventer/@implementation",
215                               conf_str, sizeof(conf_str))) {
216     noitL(noit_stderr, "Cannot find '%s' in configuration\n",
217           "/" APPNAME "/eventer/@implementation");
218     exit(-1);
219   }
220   if(eventer_choose(conf_str) == -1) {
221     noitL(noit_stderr, "Cannot choose eventer %s\n", conf_str);
222     exit(-1);
223   }
224   if(configure_eventer() != 0) {
225     noitL(noit_stderr, "Cannot configure eventer\n");
226     exit(-1);
227   }
228
229   return watch_over_child(child_main);
230 }
Note: See TracBrowser for help on using the browser.