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