root/src/noitd.c

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

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