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