root/src/noitd.c

Revision 0b1d2f2e094f32ac6912ecb9d3d2189fe811c7da, 7.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

addresses a lot of warnings. gcc still complains about stuff in xpath stuff, doesn't look like our code though, refs #34

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