blob: e16b9c25c026be5c7c6bcc48c62ba1229bfe321d [file] [log] [blame]
ajs8b886ca2004-12-22 02:56:38 +00001/*
ajs16f65112004-12-22 15:37:44 +00002 $Id: watchquagga.c,v 1.3 2004/12/22 15:37:44 ajs Exp $
ajs8b886ca2004-12-22 02:56:38 +00003
4 Monitor status of quagga daemons and restart if necessary.
5
6 Copyright (C) 2004 Andrew J. Schorr
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23/* System headers: */
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/un.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <signal.h>
31#include <fcntl.h>
32#include <errno.h>
33#include <time.h>
34#include <sys/time.h>
35#include <sys/wait.h>
36
37/* Quagga headers: */
ajs6028df52004-12-22 14:08:13 +000038#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
ajs8b886ca2004-12-22 02:56:38 +000042#include <thread.h>
43#include <log.h>
44#include <sigevent.h>
45#include <version.h>
46
47#ifndef MIN
48#define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y))
49#endif
50
51/* Macros to help randomize timers. */
52#define JITTER(X) ((random() % ((X)+1))-((X)/2))
53#define FUZZY(X) ((X)+JITTER((X)/20))
54
55#define DEFAULT_PERIOD 5
56#define DEFAULT_TIMEOUT 10
57#define DEFAULT_RESTART_TIMEOUT 20
58#define DEFAULT_LOGLEVEL LOG_INFO
59#define DEFAULT_MIN_RESTART 60
60#define DEFAULT_MAX_RESTART 600
ajs6028df52004-12-22 14:08:13 +000061#ifdef PATH_WATCHQUAGGA_PID
62#define DEFAULT_PIDFILE PATH_WATCHQUAGGA_PID
63#else
ajs8b886ca2004-12-22 02:56:38 +000064#define DEFAULT_PIDFILE STATEDIR "/watchquagga.pid"
ajs6028df52004-12-22 14:08:13 +000065#endif
ajs16f65112004-12-22 15:37:44 +000066#ifdef DAEMON_VTY_DIR
67#define VTYDIR DAEMON_VTY_DIR
68#else
69#define VTYDIR STATEDIR
70#endif
ajs8b886ca2004-12-22 02:56:38 +000071
72#define PING_TOKEN "PING"
73
74/* Needs to be global, referenced somewhere inside libzebra. */
75struct thread_master *master;
76
77typedef enum
78{
79 MODE_MONITOR = 0,
80 MODE_GLOBAL_RESTART,
81 MODE_SEPARATE_RESTART,
82 MODE_PHASED_ZEBRA_RESTART,
83 MODE_PHASED_ALL_RESTART
84} watch_mode_t;
85
86static const char *mode_str[] =
87{
88 "monitor",
89 "global restart",
90 "individual daemon restart",
91 "phased zebra restart",
92 "phased global restart for any failure",
93};
94
95typedef enum
96{
97 PHASE_NONE = 0,
98 PHASE_STOPS_PENDING,
99 PHASE_WAITING_DOWN,
100 PHASE_ZEBRA_RESTART_PENDING,
101 PHASE_WAITING_ZEBRA_UP
102} restart_phase_t;
103
104static const char *phase_str[] =
105{
106 "None",
107 "Stop jobs running",
108 "Waiting for other daemons to come down",
109 "Zebra restart job running",
110 "Waiting for zebra to come up",
111 "Start jobs running",
112};
113
114#define PHASE_TIMEOUT (3*gs.restart_timeout)
115
116static struct global_state {
117 watch_mode_t mode;
118 restart_phase_t phase;
119 struct thread *t_phase_hanging;
120 const char *vtydir;
121 long period;
122 long timeout;
123 long restart_timeout;
124 long min_restart_interval;
125 long max_restart_interval;
126 int do_ping;
127 struct daemon *daemons;
128 const char *restart_command;
129 const char *start_command;
130 const char *stop_command;
131 struct restart_info
132 {
133 const char *name;
134 const char *what;
135 pid_t pid;
136 struct timeval time;
137 long interval;
138 struct thread *t_kill;
139 int kills;
140 } restart;
141 int unresponsive_restart;
142 int loglevel;
143 struct daemon *special; /* points to zebra when doing phased restart */
144 int numdaemons;
145 int numpids;
146 int numdown; /* # of daemons that are not UP or UNRESPONSIVE */
147} gs = {
148 .mode = MODE_MONITOR,
149 .phase = PHASE_NONE,
ajs16f65112004-12-22 15:37:44 +0000150 .vtydir = VTYDIR,
ajs8b886ca2004-12-22 02:56:38 +0000151 .period = 1000*DEFAULT_PERIOD,
152 .timeout = DEFAULT_TIMEOUT,
153 .restart_timeout = DEFAULT_RESTART_TIMEOUT,
154 .loglevel = DEFAULT_LOGLEVEL,
155 .min_restart_interval = DEFAULT_MIN_RESTART,
156 .max_restart_interval = DEFAULT_MAX_RESTART,
157 .do_ping = 1,
158 .restart.name = "all",
159};
160
161typedef enum
162{
163 DAEMON_INIT,
164 DAEMON_DOWN,
165 DAEMON_CONNECTING,
166 DAEMON_UP,
167 DAEMON_UNRESPONSIVE
168} daemon_state_t;
169
170#define IS_UP(DMN) \
171 (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE))
172
173static const char *state_str[] =
174{
175 "Init",
176 "Down",
177 "Connecting",
178 "Up",
179 "Unresponsive",
180};
181
182struct daemon {
183 const char *name;
184 daemon_state_t state;
185 int fd;
186 struct timeval echo_sent;
187 u_int connect_tries;
188 struct thread *t_wakeup;
189 struct thread *t_read;
190 struct thread *t_write;
191 struct daemon *next;
192 struct restart_info restart;
193};
194
195static const struct option longopts[] =
196{
197 { "daemon", no_argument, NULL, 'd'},
198 { "statedir", required_argument, NULL, 'S'},
199 { "no-echo", no_argument, NULL, 'e'},
200 { "loglevel", required_argument, NULL, 'l'},
201 { "interval", required_argument, NULL, 'i'},
202 { "timeout", required_argument, NULL, 't'},
203 { "restart-timeout", required_argument, NULL, 'T'},
204 { "restart", required_argument, NULL, 'r'},
205 { "start-command", required_argument, NULL, 's'},
206 { "kill-command", required_argument, NULL, 'k'},
207 { "restart-all", required_argument, NULL, 'R'},
208 { "all-restart", no_argument, NULL, 'a'},
209 { "always-all-restart", no_argument, NULL, 'A'},
210 { "unresponsive-restart", no_argument, NULL, 'z'},
211 { "min-restart-interval", required_argument, NULL, 'm'},
212 { "max-restart-interval", required_argument, NULL, 'M'},
213 { "pid-file", required_argument, NULL, 'p'},
214 { "help", no_argument, NULL, 'h'},
215 { "version", no_argument, NULL, 'v'},
216 { NULL, 0, NULL, 0 }
217};
218
219static int try_connect(struct daemon *dmn);
220static int wakeup_send_echo(struct thread *t_wakeup);
221static void try_restart(struct daemon *dmn);
222static void phase_check(void);
223
224static int
225usage(const char *progname, int status)
226{
227 if (status != 0)
228 fprintf(stderr, "Try `%s --help' for more information.\n", progname);
229 else
230 printf("Usage : %s [OPTION...] <daemon name> ...\n\n\
231Watchdog program to monitor status of quagga daemons and try to restart\n\
232them if they are down or unresponsive. It determines whether a daemon is\n\
233up based on whether it can connect to the daemon's vty unix stream socket.\n\
234It then repeatedly sends echo commands over that socket to determine whether\n\
235the daemon is responsive. If the daemon crashes, we will receive an EOF\n\
236on the socket connection and know immediately that the daemon is down.\n\n\
237The daemons to be monitored should be listed on the command line.\n\n\
238This program can run in one of 5 modes:\n\n\
2390. Mode: %s.\n\
240 Just monitor and report on status changes. Example:\n\
241 %s -d zebra ospfd bgpd\n\n\
2421. Mode: %s.\n\
243 Whenever any daemon hangs or crashes, use the given command to restart\n\
244 them all. Example:\n\
245 %s -dz \\\n\
246 -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\
247 zebra ospfd\n\n\
2482. Mode: %s.\n\
249 When any single daemon hangs or crashes, restart only the daemon that's\n\
250 in trouble using the supplied restart command. Example:\n\
251 %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\
2523. Mode: %s.\n\
253 The same as the previous mode, except that there is special treatment when\n\
254 the zebra daemon is in trouble. In that case, a phased restart approach\n\
255 is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\
256 daemons. Example:\n\
257 %s -adz -r '/sbin/service %%s restart' \\\n\
258 -s '/sbin/service %%s start' \\\n\
259 -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\
2604. Mode: %s.\n\
261 This is the same as the previous mode, except that the phased restart\n\
262 procedure is used whenever any of the daemons hangs or crashes. Example:\n\
263 %s -Adz -r '/sbin/service %%s restart' \\\n\
264 -s '/sbin/service %%s start' \\\n\
265 -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\
266As of this writing, it is believed that mode 2 [%s]\n\
267is not safe, and mode 3 [%s] may not be safe with some of the\n\
268routing daemons.\n\n\
269In order to avoid attempting to restart the daemons in a fast loop,\n\
270the -m and -M options allow you to control the minimum delay between\n\
271restart commands. The minimum restart delay is recalculated each time\n\
272a restart is attempted: if the time since the last restart attempt exceeds\n\
273twice the -M value, then the restart delay is set to the -m value.\n\
274Otherwise, the interval is doubled (but capped at the -M value).\n\n\
275Options:\n\
276-d, --daemon Run in daemon mode. In this mode, error messages are sent\n\
277 to syslog instead of stdout.\n\
278-S, --statedir Set the vty socket directory (default is %s)\n\
279-e, --no-echo Do not ping the daemons to test responsiveness (this\n\
280 option is necessary if the daemons do not support the\n\
281 echo command)\n\
282-l, --loglevel Set the logging level (default is %d).\n\
283 The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\
284 but it can be set higher than %d if extra-verbose debugging\n\
285 messages are desired.\n\
286-m, --min-restart-interval\n\
287 Set the minimum seconds to wait between invocations of daemon\n\
288 restart commands (default is %d).\n\
289-M, --max-restart-interval\n\
290 Set the maximum seconds to wait between invocations of daemon\n\
291 restart commands (default is %d).\n\
292-i, --interval Set the status polling interval in seconds (default is %d)\n\
293-t, --timeout Set the unresponsiveness timeout in seconds (default is %d)\n\
294-T, --restart-timeout\n\
295 Set the restart (kill) timeout in seconds (default is %d).\n\
296 If any background jobs are still running after this much\n\
297 time has elapsed, they will be killed.\n\
298-r, --restart Supply a Bourne shell command to use to restart a single\n\
299 daemon. The command string should include '%%s' where the\n\
300 name of the daemon should be substituted.\n\
301 Note that -r and -R are incompatible.\n\
302-s, --start-command\n\
303 Supply a Bourne shell to command to use to start a single\n\
304 daemon. The command string should include '%%s' where the\n\
305 name of the daemon should be substituted.\n\
306-k, --kill-command\n\
307 Supply a Bourne shell to command to use to stop a single\n\
308 daemon. The command string should include '%%s' where the\n\
309 name of the daemon should be substituted.\n\
310-R, --restart-all\n\
311 When one or more daemons is down, try to restart everything\n\
312 using the Bourne shell command supplied as the argument.\n\
313 Note that -r and -R are incompatible.\n\
314-z, --unresponsive-restart\n\
315 When a daemon is unresponsive, treat it as being down for\n\
316 restart purposes.\n\
317-a, --all-restart\n\
318 When zebra hangs or crashes, restart all daemons using\n\
319 this phased approach: 1. stop all other daemons; 2. restart\n\
320 zebra; 3. start other daemons. Requires -r, -s, and -k.\n\
321-A, --always-all-restart\n\
322 When any daemon (not just zebra) hangs or crashes, use the\n\
323 same phased restart mechanism described above for -a.\n\
324 Requires -r, -s, and -k.\n\
325-p, --pid-file Set process identifier file name\n\
326 (default is %s).\n\
327-v, --version Print program version\n\
328-h, --help Display this help and exit\n\
329", progname,mode_str[0],progname,mode_str[1],progname,mode_str[2],
330progname,mode_str[3],progname,mode_str[4],progname,mode_str[2],mode_str[3],
ajs16f65112004-12-22 15:37:44 +0000331VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG,
ajs8b886ca2004-12-22 02:56:38 +0000332DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART,
333DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT,DEFAULT_PIDFILE);
334
335 return status;
336}
337
338static pid_t
339run_background(const char *shell_cmd)
340{
341 pid_t child;
342
343 switch (child = fork())
344 {
345 case -1:
346 zlog_err("fork failed, cannot run command [%s]: %s",
347 shell_cmd,safe_strerror(errno));
348 return -1;
349 case 0:
350 /* Child process. */
351 /* Use separate process group so child processes can be killed easily. */
352 if (setpgid(0,0) < 0)
353 zlog_warn("warning: setpgid(0,0) failed: %s",safe_strerror(errno));
354 {
355 const char *argv[4] = { "sh", "-c", shell_cmd, NULL};
356 execv("/bin/sh",(char *const *)argv);
357 zlog_err("execv(/bin/sh -c '%s') failed: %s",
358 shell_cmd,safe_strerror(errno));
359 _exit(127);
360 }
361 default:
362 /* Parent process: we will reap the child later. */
363 zlog_err("Forked background command [pid %d]: %s",child,shell_cmd);
364 return child;
365 }
366}
367
368static struct timeval *
369time_elapsed(struct timeval *result, const struct timeval *start_time)
370{
371 gettimeofday(result,NULL);
372 result->tv_sec -= start_time->tv_sec;
373 result->tv_usec -= start_time->tv_usec;
374 while (result->tv_usec < 0)
375 {
376 result->tv_usec += 1000000L;
377 result->tv_sec--;
378 }
379 return result;
380}
381
382static int
383restart_kill(struct thread *t_kill)
384{
385 struct restart_info *restart = THREAD_ARG(t_kill);
386 struct timeval delay;
387
388 time_elapsed(&delay,&restart->time);
389 zlog_warn("Warning: %s %s child process %d still running after "
390 "%ld seconds, sending signal %d",
391 restart->what,restart->name,restart->pid,delay.tv_sec,
392 (restart->kills ? SIGKILL : SIGTERM));
393 kill(-restart->pid,(restart->kills ? SIGKILL : SIGTERM));
394 restart->kills++;
395 restart->t_kill = thread_add_timer(master,restart_kill,restart,
396 gs.restart_timeout);
397 return 0;
398}
399
400static struct restart_info *
401find_child(pid_t child)
402{
403 if (gs.mode == MODE_GLOBAL_RESTART)
404 {
405 if (gs.restart.pid == child)
406 return &gs.restart;
407 }
408 else
409 {
410 struct daemon *dmn;
411 for (dmn = gs.daemons; dmn; dmn = dmn->next)
412 {
413 if (dmn->restart.pid == child)
414 return &dmn->restart;
415 }
416 }
417 return NULL;
418}
419
420static void
421sigchild(void)
422{
423 pid_t child;
424 int status;
425 const char *name;
426 const char *what;
427 struct restart_info *restart;
428
429 switch (child = waitpid(-1,&status,WNOHANG))
430 {
431 case -1:
432 zlog_err("waitpid failed: %s",safe_strerror(errno));
433 return;
434 case 0:
435 zlog_warn("SIGCHLD received, but waitpid did not reap a child");
436 return;
437 }
438
439 if ((restart = find_child(child)) != NULL)
440 {
441 name = restart->name;
442 what = restart->what;
443 restart->pid = 0;
444 gs.numpids--;
445 thread_cancel(restart->t_kill);
446 restart->t_kill = NULL;
447 /* Update restart time to reflect the time the command completed. */
448 gettimeofday(&restart->time,NULL);
449 }
450 else
451 {
452 zlog_err("waitpid returned status for an unknown child process %d",
453 child);
454 name = "(unknown)";
455 what = "background";
456 }
457 if (WIFSTOPPED(status))
458 zlog_warn("warning: %s %s process %d is stopped",
459 what,name,child);
460 else if (WIFSIGNALED(status))
461 zlog_warn("%s %s process %d terminated due to signal %d",
462 what,name,child,WTERMSIG(status));
463 else if (WIFEXITED(status))
464 {
465 if (WEXITSTATUS(status) != 0)
466 zlog_warn("%s %s process %d exited with non-zero status %d",
467 what,name,child,WEXITSTATUS(status));
468 else
469 zlog_debug("%s %s process %d exited normally",what,name,child);
470 }
471 else
472 zlog_err("cannot interpret %s %s process %d wait status 0x%x",
473 what,name,child,status);
474 phase_check();
475}
476
477static int
478run_job(struct restart_info *restart, const char *cmdtype, const char *command,
479 int force, int update_interval)
480{
481 struct timeval delay;
482
483 if (gs.loglevel > LOG_DEBUG+1)
484 zlog_debug("attempting to %s %s",cmdtype,restart->name);
485
486 if (restart->pid)
487 {
488 if (gs.loglevel > LOG_DEBUG+1)
489 zlog_debug("cannot %s %s, previous pid %d still running",
490 cmdtype,restart->name,restart->pid);
491 return -1;
492 }
493
494 if (!force &&
495 (time_elapsed(&delay,&restart->time)->tv_sec < restart->interval))
496 {
497 if (gs.loglevel > LOG_DEBUG+1)
498 zlog_debug("postponing %s %s: "
499 "elapsed time %ld < retry interval %ld",
500 cmdtype,restart->name,(long)delay.tv_sec,restart->interval);
501 return -1;
502 }
503
504 gettimeofday(&restart->time,NULL);
505 restart->kills = 0;
506 {
507 char cmd[strlen(command)+strlen(restart->name)+1];
508 snprintf(cmd,sizeof(cmd),command,restart->name);
509 if ((restart->pid = run_background(cmd)) > 0)
510 {
511 restart->t_kill = thread_add_timer(master,restart_kill,restart,
512 gs.restart_timeout);
513 restart->what = cmdtype;
514 gs.numpids++;
515 }
516 else
517 restart->pid = 0;
518 }
519
520 /* Calculate the new restart interval. */
521 if (update_interval)
522 {
523 if (delay.tv_sec > 2*gs.max_restart_interval)
524 restart->interval = gs.min_restart_interval;
525 else if ((restart->interval *= 2) > gs.max_restart_interval)
526 restart->interval = gs.max_restart_interval;
527 if (gs.loglevel > LOG_DEBUG+1)
528 zlog_debug("restart %s interval is now %ld",
529 restart->name,restart->interval);
530 }
531 return restart->pid;
532}
533
534#define SET_READ_HANDLER(DMN) \
535 (DMN)->t_read = thread_add_read(master,handle_read,(DMN),(DMN)->fd)
536
537#define SET_WAKEUP_DOWN(DMN) \
538 (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_down,(DMN), \
539 FUZZY(gs.period))
540
541#define SET_WAKEUP_UNRESPONSIVE(DMN) \
542 (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_unresponsive,(DMN), \
543 FUZZY(gs.period))
544
545#define SET_WAKEUP_ECHO(DMN) \
546 (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_send_echo,(DMN), \
547 FUZZY(gs.period))
548
549static int
550wakeup_down(struct thread *t_wakeup)
551{
552 struct daemon *dmn = THREAD_ARG(t_wakeup);
553
554 dmn->t_wakeup = NULL;
555 if (try_connect(dmn) < 0)
556 SET_WAKEUP_DOWN(dmn);
557 if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP))
558 try_restart(dmn);
559 return 0;
560}
561
562static int
563wakeup_init(struct thread *t_wakeup)
564{
565 struct daemon *dmn = THREAD_ARG(t_wakeup);
566
567 dmn->t_wakeup = NULL;
568 if (try_connect(dmn) < 0)
569 {
570 SET_WAKEUP_DOWN(dmn);
571 zlog_err("%s state -> down : initial connection attempt failed",
572 dmn->name);
573 dmn->state = DAEMON_DOWN;
574 }
575 return 0;
576}
577
578static void
579daemon_down(struct daemon *dmn, const char *why)
580{
581 if (IS_UP(dmn) || (dmn->state == DAEMON_INIT))
582 zlog_err("%s state -> down : %s",dmn->name,why);
583 else if (gs.loglevel > LOG_DEBUG)
584 zlog_debug("%s still down : %s",dmn->name,why);
585 if (IS_UP(dmn))
586 gs.numdown++;
587 dmn->state = DAEMON_DOWN;
588 if (dmn->fd >= 0)
589 {
590 close(dmn->fd);
591 dmn->fd = -1;
592 }
593 THREAD_OFF(dmn->t_read);
594 THREAD_OFF(dmn->t_write);
595 THREAD_OFF(dmn->t_wakeup);
596 if (try_connect(dmn) < 0)
597 SET_WAKEUP_DOWN(dmn);
598 phase_check();
599}
600
601static int
602handle_read(struct thread *t_read)
603{
604 struct daemon *dmn = THREAD_ARG(t_read);
605 static const char resp[sizeof(PING_TOKEN)+4] = PING_TOKEN "\n";
606 char buf[sizeof(resp)+100];
607 ssize_t rc;
608 struct timeval delay;
609
610 dmn->t_read = NULL;
611 if ((rc = read(dmn->fd,buf,sizeof(buf))) < 0)
612 {
613 char why[100];
614
615 if ((errno == EINTR) || (errno == EAGAIN))
616 {
617 /* Pretend it never happened. */
618 SET_READ_HANDLER(dmn);
619 return 0;
620 }
621 snprintf(why,sizeof(why),"unexpected read error: %s",
622 safe_strerror(errno));
623 daemon_down(dmn,why);
624 return 0;
625 }
626 if (rc == 0)
627 {
628 daemon_down(dmn,"read returned EOF");
629 return 0;
630 }
631 if (!dmn->echo_sent.tv_sec)
632 {
633 char why[sizeof(buf)+100];
634 snprintf(why,sizeof(why),"unexpected read returns %zd bytes: %.*s",
635 rc,rc,buf);
636 daemon_down(dmn,why);
637 return 0;
638 }
639
640 /* We are expecting an echo response: is there any chance that the
641 response would not be returned entirely in the first read? That
642 seems inconceivable... */
643 if ((rc != sizeof(resp)) || memcmp(buf,resp,sizeof(resp)))
644 {
645 char why[100+sizeof(buf)];
646 snprintf(why,sizeof(why),"read returned bad echo response of %zd bytes "
647 "(expecting %zu): %.*s",
648 rc,sizeof(resp),rc,buf);
649 daemon_down(dmn,why);
650 return 0;
651 }
652
653 time_elapsed(&delay,&dmn->echo_sent);
654 dmn->echo_sent.tv_sec = 0;
655 if (dmn->state == DAEMON_UNRESPONSIVE)
656 {
657 if (delay.tv_sec < gs.timeout)
658 {
659 dmn->state = DAEMON_UP;
660 zlog_warn("%s state -> up : echo response received after %ld.%06ld "
661 "seconds", dmn->name,delay.tv_sec,delay.tv_usec);
662 }
663 else
664 zlog_warn("%s: slow echo response finally received after %ld.%06ld "
665 "seconds", dmn->name,delay.tv_sec,delay.tv_usec);
666 }
667 else if (gs.loglevel > LOG_DEBUG+1)
668 zlog_debug("%s: echo response received after %ld.%06ld seconds",
669 dmn->name,delay.tv_sec,delay.tv_usec);
670
671 SET_READ_HANDLER(dmn);
672 if (dmn->t_wakeup)
673 thread_cancel(dmn->t_wakeup);
674 SET_WAKEUP_ECHO(dmn);
675
676 return 0;
677}
678
679static void
680daemon_up(struct daemon *dmn, const char *why)
681{
682 dmn->state = DAEMON_UP;
683 gs.numdown--;
684 dmn->connect_tries = 0;
685 zlog_notice("%s state -> up : %s",dmn->name,why);
686 if (gs.do_ping)
687 SET_WAKEUP_ECHO(dmn);
688 phase_check();
689}
690
691static int
692check_connect(struct thread *t_write)
693{
694 struct daemon *dmn = THREAD_ARG(t_write);
695 int sockerr;
696 socklen_t reslen = sizeof(sockerr);
697
698 dmn->t_write = NULL;
699 if (getsockopt(dmn->fd,SOL_SOCKET,SO_ERROR,(char *)&sockerr,&reslen) < 0)
700 {
701 zlog_warn("%s: check_connect: getsockopt failed: %s",
702 dmn->name,safe_strerror(errno));
703 daemon_down(dmn,"getsockopt failed checking connection success");
704 return 0;
705 }
706 if ((reslen == sizeof(sockerr)) && sockerr)
707 {
708 char why[100];
709 snprintf(why,sizeof(why),
710 "getsockopt reports that connection attempt failed: %s",
711 safe_strerror(sockerr));
712 daemon_down(dmn,why);
713 return 0;
714 }
715
716 daemon_up(dmn,"delayed connect succeeded");
717 return 0;
718}
719
720static int
721wakeup_connect_hanging(struct thread *t_wakeup)
722{
723 struct daemon *dmn = THREAD_ARG(t_wakeup);
724 char why[100];
725
726 dmn->t_wakeup = NULL;
727 snprintf(why,sizeof(why),"connection attempt timed out after %ld seconds",
728 gs.timeout);
729 daemon_down(dmn,why);
730 return 0;
731}
732
733/* Making connection to protocol daemon. */
734static int
735try_connect(struct daemon *dmn)
736{
737 int sock;
738 struct sockaddr_un addr;
739 socklen_t len;
740 int flags;
741
742 if (gs.loglevel > LOG_DEBUG+1)
743 zlog_debug("%s: attempting to connect",dmn->name);
744 dmn->connect_tries++;
745
746 memset (&addr, 0, sizeof (struct sockaddr_un));
747 addr.sun_family = AF_UNIX;
748 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s.vty",
749 gs.vtydir,dmn->name);
750#ifdef HAVE_SUN_LEN
751 len = addr.sun_len = SUN_LEN(&addr);
752#else
753 len = sizeof (addr.sun_family) + strlen (addr.sun_path);
754#endif /* HAVE_SUN_LEN */
755
756 /* Quick check to see if we might succeed before we go to the trouble
757 of creating a socket. */
758 if (access(addr.sun_path, W_OK) < 0)
759 {
760 if (errno != ENOENT)
761 zlog_err("%s: access to socket %s denied: %s",
762 dmn->name,addr.sun_path,safe_strerror(errno));
763 return -1;
764 }
765
766 if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
767 {
768 zlog_err("%s(%s): cannot make socket: %s",
769 __func__,addr.sun_path, safe_strerror(errno));
770 return -1;
771 }
772
773 /* Set non-blocking. */
774 if ((flags = fcntl(sock, F_GETFL, 0)) < 0)
775 {
776 zlog_err("%s(%s): fcntl(F_GETFL) failed: %s",
777 __func__,addr.sun_path, safe_strerror(errno));
778 close(sock);
779 return -1;
780 }
781 if (fcntl(sock, F_SETFL, (flags|O_NONBLOCK)) < 0)
782 {
783 zlog_err("%s(%s): fcntl(F_SETFL,O_NONBLOCK) failed: %s",
784 __func__,addr.sun_path, safe_strerror(errno));
785 close(sock);
786 return -1;
787 }
788
789 if (connect (sock, (struct sockaddr *) &addr, len) < 0)
790 {
791 if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK))
792 {
793 if (gs.loglevel > LOG_DEBUG)
794 zlog_debug("%s(%s): connect failed: %s",
795 __func__,addr.sun_path, safe_strerror(errno));
796 close (sock);
797 return -1;
798 }
799 if (gs.loglevel > LOG_DEBUG)
800 zlog_debug("%s: connection in progress",dmn->name);
801 dmn->state = DAEMON_CONNECTING;
802 dmn->fd = sock;
803 dmn->t_write = thread_add_write(master,check_connect,dmn,dmn->fd);
804 dmn->t_wakeup = thread_add_timer(master,wakeup_connect_hanging,dmn,
805 gs.timeout);
806 SET_READ_HANDLER(dmn);
807 return 0;
808 }
809
810 dmn->fd = sock;
811 SET_READ_HANDLER(dmn);
812 daemon_up(dmn,"connect succeeded");
813 return 1;
814}
815
816static int
817phase_hanging(struct thread *t_hanging)
818{
819 gs.t_phase_hanging = NULL;
820 zlog_err("Phase [%s] hanging for %ld seconds, aborting phased restart",
821 phase_str[gs.phase],PHASE_TIMEOUT);
822 gs.phase = PHASE_NONE;
823 return 0;
824}
825
826static void
827set_phase(restart_phase_t new_phase)
828{
829 gs.phase = new_phase;
830 if (gs.t_phase_hanging)
831 thread_cancel(gs.t_phase_hanging);
832 gs.t_phase_hanging = thread_add_timer(master,phase_hanging,NULL,
833 PHASE_TIMEOUT);
834}
835
836static void
837phase_check(void)
838{
839 switch (gs.phase)
840 {
841 case PHASE_NONE:
842 break;
843 case PHASE_STOPS_PENDING:
844 if (gs.numpids)
845 break;
846 zlog_info("Phased restart: all routing daemon stop jobs have completed.");
847 set_phase(PHASE_WAITING_DOWN);
848 /*FALLTHRU*/
849 case PHASE_WAITING_DOWN:
850 if (gs.numdown+IS_UP(gs.special) < gs.numdaemons)
851 break;
852 zlog_info("Phased restart: all routing daemons now down.");
853 run_job(&gs.special->restart,"restart",gs.restart_command,1,1);
854 set_phase(PHASE_ZEBRA_RESTART_PENDING);
855 /*FALLTHRU*/
856 case PHASE_ZEBRA_RESTART_PENDING:
857 if (gs.special->restart.pid)
858 break;
859 zlog_info("Phased restart: %s restart job completed.",gs.special->name);
860 set_phase(PHASE_WAITING_ZEBRA_UP);
861 /*FALLTHRU*/
862 case PHASE_WAITING_ZEBRA_UP:
863 if (!IS_UP(gs.special))
864 break;
865 zlog_info("Phased restart: %s is now up.",gs.special->name);
866 {
867 struct daemon *dmn;
868 for (dmn = gs.daemons; dmn; dmn = dmn->next)
869 {
870 if (dmn != gs.special)
871 run_job(&dmn->restart,"start",gs.start_command,1,1);
872 }
873 }
874 gs.phase = PHASE_NONE;
875 THREAD_OFF(gs.t_phase_hanging);
876 zlog_notice("Phased global restart has completed.");
877 break;
878 }
879}
880
881static void
882try_restart(struct daemon *dmn)
883{
884 switch (gs.mode)
885 {
886 case MODE_MONITOR:
887 return;
888 case MODE_GLOBAL_RESTART:
889 run_job(&gs.restart,"restart",gs.restart_command,0,1);
890 break;
891 case MODE_SEPARATE_RESTART:
892 run_job(&dmn->restart,"restart",gs.restart_command,0,1);
893 break;
894 case MODE_PHASED_ZEBRA_RESTART:
895 if (dmn != gs.special)
896 {
897 if ((gs.special->state == DAEMON_UP) && (gs.phase == PHASE_NONE))
898 run_job(&dmn->restart,"restart",gs.restart_command,0,1);
899 else
900 zlog_debug("%s: postponing restart attempt because master %s daemon "
901 "not up [%s], or phased restart in progress",
902 dmn->name,gs.special->name,state_str[gs.special->state]);
903 break;
904 }
905 /*FALLTHRU*/
906 case MODE_PHASED_ALL_RESTART:
907 if ((gs.phase != PHASE_NONE) || gs.numpids)
908 {
909 if (gs.loglevel > LOG_DEBUG+1)
910 zlog_debug("postponing phased global restart: restart already in "
911 "progress [%s], or outstanding child processes [%d]",
912 phase_str[gs.phase],gs.numpids);
913 break;
914 }
915 /* Is it too soon for a restart? */
916 {
917 struct timeval delay;
918 if (time_elapsed(&delay,&gs.special->restart.time)->tv_sec <
919 gs.special->restart.interval)
920 {
921 if (gs.loglevel > LOG_DEBUG+1)
922 zlog_debug("postponing phased global restart: "
923 "elapsed time %ld < retry interval %ld",
924 (long)delay.tv_sec,gs.special->restart.interval);
925 break;
926 }
927 }
928 zlog_info("Phased restart: stopping all routing daemons.");
929 /* First step: stop all other daemons. */
930 for (dmn = gs.daemons; dmn; dmn = dmn->next)
931 {
932 if (dmn != gs.special)
933 run_job(&dmn->restart,"stop",gs.stop_command,1,0);
934 }
935 set_phase(PHASE_STOPS_PENDING);
936 break;
937 default:
938 zlog_err("error: unknown restart mode %d",gs.mode);
939 break;
940 }
941}
942
943static int
944wakeup_unresponsive(struct thread *t_wakeup)
945{
946 struct daemon *dmn = THREAD_ARG(t_wakeup);
947
948 dmn->t_wakeup = NULL;
949 if (dmn->state != DAEMON_UNRESPONSIVE)
950 zlog_err("%s: no longer unresponsive (now %s), "
951 "wakeup should have been cancelled!",
952 dmn->name,state_str[dmn->state]);
953 else
954 {
955 SET_WAKEUP_UNRESPONSIVE(dmn);
956 try_restart(dmn);
957 }
958 return 0;
959}
960
961static int
962wakeup_no_answer(struct thread *t_wakeup)
963{
964 struct daemon *dmn = THREAD_ARG(t_wakeup);
965
966 dmn->t_wakeup = NULL;
967 dmn->state = DAEMON_UNRESPONSIVE;
968 zlog_err("%s state -> unresponsive : no response yet to ping "
969 "sent %ld seconds ago",dmn->name,gs.timeout);
970 if (gs.unresponsive_restart)
971 {
972 SET_WAKEUP_UNRESPONSIVE(dmn);
973 try_restart(dmn);
974 }
975 return 0;
976}
977
978static int
979wakeup_send_echo(struct thread *t_wakeup)
980{
981 static const char echocmd[] = "echo " PING_TOKEN;
982 ssize_t rc;
983 struct daemon *dmn = THREAD_ARG(t_wakeup);
984
985 dmn->t_wakeup = NULL;
986 if (((rc = write(dmn->fd,echocmd,sizeof(echocmd))) < 0) ||
987 ((size_t)rc != sizeof(echocmd)))
988 {
989 char why[100+sizeof(echocmd)];
990 snprintf(why,sizeof(why),"write '%s' returned %zd instead of %zu",
991 echocmd,rc,sizeof(echocmd));
992 daemon_down(dmn,why);
993 }
994 else
995 {
996 gettimeofday(&dmn->echo_sent,NULL);
997 dmn->t_wakeup = thread_add_timer(master,wakeup_no_answer,dmn,gs.timeout);
998 }
999 return 0;
1000}
1001
1002static void
1003sigint(void)
1004{
1005 zlog_notice("Terminating on signal");
1006 exit(0);
1007}
1008
1009static int
1010valid_command(const char *cmd)
1011{
1012 char *p;
1013
1014 return ((p = strchr(cmd,'%')) != NULL) && (*(p+1) == 's') && !strchr(p+1,'%');
1015}
1016
1017int
1018main(int argc, char **argv)
1019{
1020 const char *progname;
1021 int opt;
1022 int daemon_mode = 0;
1023 const char *pidfile = DEFAULT_PIDFILE;
1024 const char *special = "zebra";
1025 static struct quagga_signal_t my_signals[] =
1026 {
1027 {
1028 .signal = SIGINT,
1029 .handler = sigint,
1030 },
1031 {
1032 .signal = SIGTERM,
1033 .handler = sigint,
1034 },
1035 {
1036 .signal = SIGCHLD,
1037 .handler = sigchild,
1038 },
1039 };
1040
1041 if ((progname = strrchr (argv[0], '/')) != NULL)
1042 progname++;
1043 else
1044 progname = argv[0];
1045
1046 while ((opt = getopt_long(argc, argv, "aAdek:l:m:M:i:p:r:R:S:s:t:T:zvh",
1047 longopts, 0)) != EOF)
1048 {
1049 switch (opt)
1050 {
1051 case 0:
1052 break;
1053 case 'a':
1054 if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART))
1055 {
1056 fputs("Ambiguous operating mode selected.\n",stderr);
1057 return usage(progname,1);
1058 }
1059 gs.mode = MODE_PHASED_ZEBRA_RESTART;
1060 break;
1061 case 'A':
1062 if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART))
1063 {
1064 fputs("Ambiguous operating mode selected.\n",stderr);
1065 return usage(progname,1);
1066 }
1067 gs.mode = MODE_PHASED_ALL_RESTART;
1068 break;
1069 case 'd':
1070 daemon_mode = 1;
1071 break;
1072 case 'e':
1073 gs.do_ping = 0;
1074 break;
1075 case 'k':
1076 if (!valid_command(optarg))
1077 {
1078 fprintf(stderr,"Invalid kill command, must contain '%%s': %s\n",
1079 optarg);
1080 return usage(progname,1);
1081 }
1082 gs.stop_command = optarg;
1083 break;
1084 case 'l':
1085 {
1086 char garbage[3];
1087 if ((sscanf(optarg,"%d%1s",&gs.loglevel,garbage) != 1) ||
1088 (gs.loglevel < LOG_EMERG))
1089 {
1090 fprintf(stderr,"Invalid loglevel argument: %s\n",optarg);
1091 return usage(progname,1);
1092 }
1093 }
1094 break;
1095 case 'm':
1096 {
1097 char garbage[3];
1098 if ((sscanf(optarg,"%ld%1s",
1099 &gs.min_restart_interval,garbage) != 1) ||
1100 (gs.min_restart_interval < 0))
1101 {
1102 fprintf(stderr,"Invalid min_restart_interval argument: %s\n",
1103 optarg);
1104 return usage(progname,1);
1105 }
1106 }
1107 break;
1108 case 'M':
1109 {
1110 char garbage[3];
1111 if ((sscanf(optarg,"%ld%1s",
1112 &gs.max_restart_interval,garbage) != 1) ||
1113 (gs.max_restart_interval < 0))
1114 {
1115 fprintf(stderr,"Invalid max_restart_interval argument: %s\n",
1116 optarg);
1117 return usage(progname,1);
1118 }
1119 }
1120 break;
1121 case 'i':
1122 {
1123 char garbage[3];
1124 int period;
1125 if ((sscanf(optarg,"%d%1s",&period,garbage) != 1) ||
1126 (gs.period < 1))
1127 {
1128 fprintf(stderr,"Invalid interval argument: %s\n",optarg);
1129 return usage(progname,1);
1130 }
1131 gs.period = 1000*period;
1132 }
1133 break;
1134 case 'p':
1135 pidfile = optarg;
1136 break;
1137 case 'r':
1138 if ((gs.mode == MODE_GLOBAL_RESTART) ||
1139 (gs.mode == MODE_SEPARATE_RESTART))
1140 {
1141 fputs("Ambiguous operating mode selected.\n",stderr);
1142 return usage(progname,1);
1143 }
1144 if (!valid_command(optarg))
1145 {
1146 fprintf(stderr,
1147 "Invalid restart command, must contain '%%s': %s\n",
1148 optarg);
1149 return usage(progname,1);
1150 }
1151 gs.restart_command = optarg;
1152 if (gs.mode == MODE_MONITOR)
1153 gs.mode = MODE_SEPARATE_RESTART;
1154 break;
1155 case 'R':
1156 if (gs.mode != MODE_MONITOR)
1157 {
1158 fputs("Ambiguous operating mode selected.\n",stderr);
1159 return usage(progname,1);
1160 }
1161 if (strchr(optarg,'%'))
1162 {
1163 fprintf(stderr,
1164 "Invalid restart-all arg, must not contain '%%s': %s\n",
1165 optarg);
1166 return usage(progname,1);
1167 }
1168 gs.restart_command = optarg;
1169 gs.mode = MODE_GLOBAL_RESTART;
1170 break;
1171 case 's':
1172 if (!valid_command(optarg))
1173 {
1174 fprintf(stderr,"Invalid start command, must contain '%%s': %s\n",
1175 optarg);
1176 return usage(progname,1);
1177 }
1178 gs.start_command = optarg;
1179 break;
1180 case 'S':
1181 gs.vtydir = optarg;
1182 break;
1183 case 't':
1184 {
1185 char garbage[3];
1186 if ((sscanf(optarg,"%ld%1s",&gs.timeout,garbage) != 1) ||
1187 (gs.timeout < 1))
1188 {
1189 fprintf(stderr,"Invalid timeout argument: %s\n",optarg);
1190 return usage(progname,1);
1191 }
1192 }
1193 break;
1194 case 'T':
1195 {
1196 char garbage[3];
1197 if ((sscanf(optarg,"%ld%1s",&gs.restart_timeout,garbage) != 1) ||
1198 (gs.restart_timeout < 1))
1199 {
1200 fprintf(stderr,"Invalid restart timeout argument: %s\n",optarg);
1201 return usage(progname,1);
1202 }
1203 }
1204 break;
1205 case 'z':
1206 gs.unresponsive_restart = 1;
1207 break;
1208 case 'v':
1209 printf ("%s version %s\n", progname, QUAGGA_VERSION);
1210 puts("Copyright 2004 Andrew J. Schorr");
1211 return 0;
1212 case 'h':
1213 return usage(progname,0);
1214 default:
1215 fputs("Invalid option.\n",stderr);
1216 return usage(progname,1);
1217 }
1218 }
1219
1220 if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR))
1221 {
1222 fputs("Option -z requires a -r or -R restart option.\n",stderr);
1223 return usage(progname,1);
1224 }
1225 switch (gs.mode)
1226 {
1227 case MODE_MONITOR:
1228 if (gs.restart_command || gs.start_command || gs.stop_command)
1229 {
1230 fprintf(stderr,"No kill/(re)start commands needed for %s mode.\n",
1231 mode_str[gs.mode]);
1232 return usage(progname,1);
1233 }
1234 break;
1235 case MODE_GLOBAL_RESTART:
1236 case MODE_SEPARATE_RESTART:
1237 if (!gs.restart_command || gs.start_command || gs.stop_command)
1238 {
1239 fprintf(stderr,"No start/kill commands needed in [%s] mode.\n",
1240 mode_str[gs.mode]);
1241 return usage(progname,1);
1242 }
1243 break;
1244 case MODE_PHASED_ZEBRA_RESTART:
1245 case MODE_PHASED_ALL_RESTART:
1246 if (!gs.restart_command || !gs.start_command || !gs.stop_command)
1247 {
1248 fprintf(stderr,
1249 "Need start, kill, and restart commands in [%s] mode.\n",
1250 mode_str[gs.mode]);
1251 return usage(progname,1);
1252 }
1253 break;
1254 }
1255
1256 gs.restart.interval = gs.min_restart_interval;
1257 master = thread_master_create();
1258 signal_init (master, Q_SIGC(my_signals), my_signals);
1259 srandom(time(NULL));
1260
1261 {
1262 int i;
1263 struct daemon *tail = NULL;
1264
1265 for (i = optind; i < argc; i++)
1266 {
1267 struct daemon *dmn;
1268
1269 if (!(dmn = (struct daemon *)calloc(1,sizeof(*dmn))))
1270 {
1271 fprintf(stderr,"calloc(1,%zu) failed: %s\n",
1272 sizeof(*dmn), safe_strerror(errno));
1273 return 1;
1274 }
1275 dmn->name = dmn->restart.name = argv[i];
1276 dmn->state = DAEMON_INIT;
1277 gs.numdaemons++;
1278 gs.numdown++;
1279 dmn->fd = -1;
1280 dmn->t_wakeup = thread_add_timer_msec(master,wakeup_init,dmn,
1281 100+(random() % 900));
1282 dmn->restart.interval = gs.min_restart_interval;
1283 if (tail)
1284 tail->next = dmn;
1285 else
1286 gs.daemons = dmn;
1287 tail = dmn;
1288
1289 if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) ||
1290 (gs.mode == MODE_PHASED_ALL_RESTART)) &&
1291 !strcmp(dmn->name,special))
1292 gs.special = dmn;
1293 }
1294 }
1295 if (!gs.daemons)
1296 {
1297 fputs("Must specify one or more daemons to monitor.\n",stderr);
1298 return usage(progname,1);
1299 }
1300 if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) ||
1301 (gs.mode == MODE_PHASED_ALL_RESTART)) && !gs.special)
1302 {
1303 fprintf(stderr,"In mode [%s], but cannot find master daemon %s\n",
1304 mode_str[gs.mode],special);
1305 return usage(progname,1);
1306 }
1307 if (gs.special && (gs.numdaemons < 2))
1308 {
1309 fprintf(stderr,"Mode [%s] does not make sense with only 1 daemon "
1310 "to watch.\n",mode_str[gs.mode]);
1311 return usage(progname,1);
1312 }
1313
1314 zlog_default = openzlog(progname, ZLOG_NONE,
1315 LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
1316 zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
1317 if (daemon_mode)
1318 {
1319 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, MIN(gs.loglevel,LOG_DEBUG));
1320 daemon(0, 0);
1321 }
1322 else
1323 zlog_set_level(NULL, ZLOG_DEST_STDOUT, MIN(gs.loglevel,LOG_DEBUG));
1324
1325 /* Make sure we're not already running. */
1326 pid_output (pidfile);
1327
1328 /* Announce which daemons are being monitored. */
1329 {
1330 struct daemon *dmn;
1331 size_t len = 0;
1332
1333 for (dmn = gs.daemons; dmn; dmn = dmn->next)
1334 len += strlen(dmn->name)+1;
1335
1336 {
1337 char buf[len+1];
1338 char *p = buf;
1339
1340 for (dmn = gs.daemons; dmn; dmn = dmn->next)
1341 {
1342 if (p != buf)
1343 *p++ = ' ';
1344 strcpy(p,dmn->name);
1345 p += strlen(p);
1346 }
1347 zlog_notice("%s %s watching [%s], mode [%s]",
1348 progname, QUAGGA_VERSION, buf, mode_str[gs.mode]);
1349 }
1350 }
1351
1352 {
1353 struct thread thread;
1354
1355 while (thread_fetch (master, &thread))
1356 thread_call (&thread);
1357 }
1358
1359 /* Not reached. */
1360 return 0;
1361}