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