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