22
33#include <errno.h>
44#include <getopt.h>
5+ #include <sys/inotify.h>
6+ #include <ev.h>
57#include <libite/lite.h>
68
79#include "netd.h"
810#include "config.h"
911
1012int debug ;
1113
12- static sig_atomic_t do_reload ;
13- static sig_atomic_t do_shutdown ;
14-
1514static struct route_head active_routes = TAILQ_HEAD_INITIALIZER (active_routes );
1615static struct rip_config active_rip ;
1716
@@ -46,19 +45,7 @@ static int backend_apply(struct route_head *routes, struct rip_config *rip) {
4645}
4746#endif
4847
49- static void sighup_handler (int sig )
50- {
51- (void )sig ;
52-
53- INFO ("Got SIGHUP, reloading ..." );
54- do_reload = 1 ;
55- }
56-
57- static void sigterm_handler (int sig )
58- {
59- (void )sig ;
60- do_shutdown = 1 ;
61- }
48+ static ev_timer retry_w ;
6249
6350static void route_list_free (struct route_head * head )
6451{
@@ -118,7 +105,7 @@ static void rip_config_free(struct rip_config *cfg)
118105 }
119106}
120107
121- static void reload (void )
108+ static void reload (struct ev_loop * loop )
122109{
123110 struct route_head new_routes = TAILQ_HEAD_INITIALIZER (new_routes );
124111 struct rip_redistribute * redist ;
@@ -129,7 +116,7 @@ static void reload(void)
129116 struct route * r ;
130117 int count = 0 ;
131118
132- INFO ("Reloading configuration" );
119+ DEBUG ("Reloading configuration" );
133120
134121 rip_config_init (& new_rip );
135122
@@ -148,11 +135,16 @@ static void reload(void)
148135
149136 /* Apply config via backend */
150137 if (backend_apply (& new_routes , & new_rip )) {
151- ERROR ("Failed applying config via backend" );
138+ ERROR ("Failed applying config via backend, retry in 5s " );
152139 route_list_free (& new_routes );
153140 rip_config_free (& new_rip );
141+ ev_timer_stop (loop , & retry_w );
142+ ev_timer_set (& retry_w , 5. , 0. );
143+ ev_timer_start (loop , & retry_w );
144+ pidfile (NULL );
154145 return ;
155146 }
147+ ev_timer_stop (loop , & retry_w );
156148
157149 route_list_free (& active_routes );
158150 TAILQ_INIT (& active_routes );
@@ -214,49 +206,77 @@ static void reload(void)
214206 }
215207 }
216208
217- INFO ("Configuration reloaded" );
218209 pidfile (NULL );
219210}
220211
212+ static void inotify_cb (struct ev_loop * loop , ev_io * w , int revents )
213+ {
214+ char buf [sizeof (struct inotify_event ) + NAME_MAX + 1 ];
215+
216+ (void )revents ;
217+ while (read (w -> fd , buf , sizeof (buf )) > 0 )
218+ ;
219+ DEBUG ("conf.d changed, triggering reload" );
220+ reload (loop );
221+ }
222+
223+ static void sighup_cb (struct ev_loop * loop , ev_signal * w , int revents )
224+ {
225+ (void )w ; (void )revents ;
226+ INFO ("Got SIGHUP, reloading ..." );
227+ reload (loop );
228+ }
229+
230+ static void sigterm_cb (struct ev_loop * loop , ev_signal * w , int revents )
231+ {
232+ (void )w ; (void )revents ;
233+ ev_break (loop , EVBREAK_ALL );
234+ }
235+
236+ static void retry_cb (struct ev_loop * loop , ev_timer * w , int revents )
237+ {
238+ (void )w ; (void )revents ;
239+ reload (loop );
240+ }
241+
221242static int usage (int rc )
222243{
223244 fprintf (stderr ,
224- "Usage: netd [-dh ]\n"
245+ "Usage: netd [-dhv ]\n"
225246 " -d Enable debug (log to stderr)\n"
226- " -h Show this help text\n" );
247+ " -h Show this help text\n"
248+ " -v Show version and exit\n" );
227249 return rc ;
228250}
229251
230252int main (int argc , char * argv [])
231253{
254+ struct ev_loop * loop = EV_DEFAULT ;
255+ ev_signal sighup_w , sigterm_w , sigint_w ;
256+ ev_io inotify_w ;
232257 int log_opts = LOG_PID | LOG_NDELAY ;
233- struct sigaction sa = { 0 } ;
258+ int ifd = -1 ;
234259 int c ;
235260
236- while ((c = getopt (argc , argv , "dhp: " )) != -1 ) {
261+ while ((c = getopt (argc , argv , "dhv " )) != -1 ) {
237262 switch (c ) {
238263 case 'd' :
239264 log_opts |= LOG_PERROR ;
240265 debug = 1 ;
241266 break ;
242267 case 'h' :
243268 return usage (0 );
269+ case 'v' :
270+ puts ("v" PACKAGE_VERSION );
271+ return 0 ;
244272 default :
245273 return usage (1 );
246274 }
247275 }
248276
249277 openlog ("netd" , log_opts , LOG_DAEMON );
250278 setlogmask (LOG_UPTO (LOG_INFO ));
251- INFO ("starting" );
252-
253- /* Set up signal handlers */
254- sa .sa_handler = sighup_handler ;
255- sigaction (SIGHUP , & sa , NULL );
256-
257- sa .sa_handler = sigterm_handler ;
258- sigaction (SIGTERM , & sa , NULL );
259- sigaction (SIGINT , & sa , NULL );
279+ INFO ("v%s starting" , PACKAGE_VERSION );
260280
261281 if (backend_init ()) {
262282 ERROR ("Failed to initialize backend" );
@@ -267,19 +287,44 @@ int main(int argc, char *argv[])
267287 TAILQ_INIT (& active_routes );
268288 rip_config_init (& active_rip );
269289
290+ /* Signal watchers */
291+ ev_signal_init (& sighup_w , sighup_cb , SIGHUP );
292+ ev_signal_start (loop , & sighup_w );
293+
294+ ev_signal_init (& sigterm_w , sigterm_cb , SIGTERM );
295+ ev_signal_start (loop , & sigterm_w );
296+
297+ ev_signal_init (& sigint_w , sigterm_cb , SIGINT );
298+ ev_signal_start (loop , & sigint_w );
299+
300+ /* Retry timer — one-shot, started only on backend failure */
301+ ev_timer_init (& retry_w , retry_cb , 0. , 0. );
302+
303+ /* Watch conf.d for changes so we don't rely solely on signals */
304+ mkdir (CONF_DIR , 0755 );
305+ ifd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK );
306+ if (ifd < 0 ) {
307+ ERROR ("inotify_init1: %s, falling back to signals only" , strerror (errno ));
308+ } else if (inotify_add_watch (ifd , CONF_DIR ,
309+ IN_CLOSE_WRITE | IN_DELETE |
310+ IN_MOVED_TO | IN_MOVED_FROM ) < 0 ) {
311+ ERROR ("inotify_add_watch %s: %s" , CONF_DIR , strerror (errno ));
312+ close (ifd );
313+ ifd = -1 ;
314+ } else {
315+ ev_io_init (& inotify_w , inotify_cb , ifd , EV_READ );
316+ ev_io_start (loop , & inotify_w );
317+ }
318+
270319 /* Initial load */
271- do_reload = 1 ;
320+ reload ( loop ) ;
272321
273- while (!do_shutdown ) {
274- if (do_reload ) {
275- do_reload = 0 ;
276- reload ();
277- }
278- pause ();
279- }
322+ ev_run (loop , 0 );
280323
281324 INFO ("shutting down" );
282325
326+ if (ifd >= 0 )
327+ close (ifd );
283328 route_list_free (& active_routes );
284329 rip_config_free (& active_rip );
285330 backend_cleanup ();
0 commit comments