📄 watchdog.c
字号:
/* $Header: /cvsroot/watchdog/watchdog/src/watchdog.c,v 1.4 2007/08/17 09:24:54 meskes Exp $ *//*************************************************************//* Original version was an example in the kernel source tree *//* *//* Most of the rest was written by me, Michael Meskes *//* meskes@debian.org *//* *//*************************************************************/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "extern.h"#include <errno.h>#include <fcntl.h>#include <getopt.h>#include <netdb.h>#include <sched.h>#include <signal.h>#include <stdlib.h>#include <arpa/inet.h>#include <sys/mman.h>#include <sys/wait.h>#define __USE_GNU#include <string.h>#if !defined(__GLIBC__) /* __GLIBC__ */extern char *basename(const char *);#endif /* __GLIBC__ */#include <unistd.h>#include "watch_err.h"#if USE_SYSLOG#include <syslog.h>#endif /* USE_SYSLOG */static int no_act = FALSE;#if USE_SYSLOGint verbose = FALSE;#endif /* USE_SYSLOG */#define ADMIN "admin"#define CHANGE "change"#define DEVICE "watchdog-device"#define FILENAME "file"#define INTERFACE "interface"#define INTERVAL "interval"#define LOGTICK "logtick"#define MAXLOAD1 "max-load-1"#define MAXLOAD5 "max-load-5"#define MAXLOAD15 "max-load-15"#define MAXTEMP "max-temperature"#define MINMEM "min-memory"#define SERVERPIDFILE "pidfile"#define PING "ping"#define PINGCOUNT "ping-count"#define PRIORITY "priority"#define REALTIME "realtime"#define REPAIRBIN "repair-binary"#define TEMP "temperature-device"#define TESTBIN "test-binary"#define TESTTIMEOUT "test-timeout"#define HEARTBEAT "heartbeat-file"#define HBSTAMPS "heartbeat-stamps"pid_t pid;int softboot = FALSE, watchdog = -1, load = -1, mem = -1, temp = -1;int tint = 10, logtick = 1, ticker = 1, schedprio = 1;int maxload1 = 0, maxload5 = 0, maxload15 = 0, minpages = 0;int maxtemp = 120, hbstamps = 300, lastts, nrts;int pingcount = 3;char *tempname = NULL, *devname = NULL, *admin = "root", *progname;char *timestamps, *heartbeat;time_t timeout = 0;FILE *hb;#if defined(_POSIX_MEMLOCK)int mlocked = FALSE, realtime = FALSE;#endifstatic void usage(void){ fprintf(stderr, "%s version %d.%d, usage:\n", progname, MAJOR_VERSION, MINOR_VERSION);#if USE_SYSLOG fprintf(stderr, "%s [-i <interval> [-f]] [-l <max load avg>] [-v] [-s] [-b] [-m <max temperature>]\n", progname);#else /* USE_SYSLOG */ fprintf(stderr, "%s [-i <interval> [-f]] [-l <max load avg>] [-v] [-b] [-m <max temperature>]\n", progname);#endif /* USE_SYSLOG */ exit(1);}/* Try to sync */static int sync_system(int sync_it){ if (sync_it) { sync(); sync(); } return (0);}/* execute repair binary */static int repair(char *rbinary, int result){ pid_t child_pid; char parm[5]; int ret; /* no binary given, we have to reboot */ if (rbinary == NULL) return (result); sprintf(parm, "%d", result); child_pid = fork(); if (!child_pid) { /* Don't want the stdin and stdout of our test program * to cause trouble * So make stdout and stderr go to their respective files */ if (!freopen("/var/log/watchdog/repair-bin.stdout", "a+", stdout)) exit (errno); if (!freopen("/var/log/watchdog/repair-bin.stderr", "a+", stderr)) exit (errno); /* else start binary */ execl(rbinary, rbinary, parm, NULL); /* execl should only return in case of an error */ /* so we return the reboot code */ return (errno); } else if (child_pid < 0) { /* fork failed */ int err = errno; if (errno == EAGAIN) { /* process table full */#if USE_SYSLOG syslog(LOG_ERR, "process table is full!");#endif /* USE_SYSLOG */ return (EREBOOT); } else if (softboot) return (err); else return (ENOERR); } if (waitpid(child_pid, &result, 0) != child_pid) { int err = errno;#if USE_SYSLOG syslog(LOG_ERR, "child %d does not exist (errno = %d = '%m')", child_pid, err);#else /* USE_SYSLOG */ perror(progname);#endif /* USE_SYSLOG */ if (softboot) return (err); } /* check result */ ret = WEXITSTATUS(result); if (ret != 0) {#if USE_SYSLOG syslog(LOG_ERR, "repair binary returned %d", ret);#endif /* USE_SYSLOG */ if (ret == ERESET) /* repair script says force hard reset, we give it a try */ sleep(TIMER_MARGIN * 4); /* for all other errors or if we still live, we let shutdown handle it */ return (ret); } return (ENOERR);}static void wd_action(int result, char *rbinary){ /* if no-action flag set, do nothing */ /* no error, keep on working */ if (result == ENOERR || no_act == TRUE) return; /* error that might be repairable */ if (result != EREBOOT) result = repair(rbinary, result); /* if still error, reboot */ if (result != ENOERR) do_shutdown(result);}static void do_check(int res, char *rbinary){ wd_action(res, rbinary); wd_action(keep_alive(), rbinary);}struct list *file = NULL, *target = NULL, *pidfile = NULL, *iface = NULL;char *tbinary, *rbinary, *admin;static void add_list(struct list **list, char *name){ struct list *new, *act; if ((new = (struct list *) calloc(1, sizeof(struct list))) == NULL) { fprintf(stderr, "%s: out of memory\n", progname); exit(1); } new->name = name; memset((char *) (&(new->parameter)), '\0', sizeof(union wdog_options)); if (*list == NULL) *list = new; else { for (act = *list; act->next != NULL; act = act->next); act->next = new; }}static int spool(char *line, int *i, int offset){ for ((*i) += offset; line[*i] == ' ' || line[*i] == '\t'; (*i)++); if (line[*i] == '=') (*i)++; for (; line[*i] == ' ' || line[*i] == '\t'; (*i)++); if (line[*i] == '\0') return(1); else return(0);}static void read_config(char *filename, char *progname){ FILE *wc; int gotload5 = FALSE, gotload15 = FALSE; if ((wc = fopen(filename, "r")) == NULL) { perror(progname); exit(1); } while (!feof(wc)) { char line[CONFIG_LINE_LEN]; if (fgets(line, CONFIG_LINE_LEN, wc) == NULL) { if (!ferror(wc)) break; else { perror(progname); exit(1); } } else { int i, j; /* scan the actual line for an option */ /* first remove the leading blanks */ for (i = 0; line[i] == ' ' || line[i] == '\t'; i++); /* if the next sign is a '#' we have a comment */ if (line[i] == '#') continue; /* also remove the trailing blanks and the \n */ for (j = strlen(line) - 1; line[j] == ' ' || line[j] == '\t' || line[j] == '\n'; j--); line[j + 1] = '\0'; /* if the line is empty now, we don't have to parse it */ if (strlen(line + i) == 0) continue; /* now check for an option */ if (strncmp(line + i, FILENAME, strlen(FILENAME)) == 0) { if (spool(line, &i, strlen(FILENAME))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else add_list(&file, strdup(line + i)); } else if (strncmp(line + i, CHANGE, strlen(CHANGE)) == 0) { struct list *ptr; if (spool(line, &i, strlen(CHANGE))) continue; if (!file) { /* no file entered yet */ fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); continue; } for (ptr = file; ptr->next != NULL; ptr = ptr->next); if (ptr->parameter.file.mtime != 0) fprintf(stderr, "Duplicate change interval option in config file. Ignoring first entry.\n"); ptr->parameter.file.mtime = atoi(line + i); } else if (strncmp(line + i, SERVERPIDFILE, strlen(SERVERPIDFILE)) == 0) { if (spool(line, &i, strlen(SERVERPIDFILE))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else add_list(&pidfile, strdup(line + i)); } else if (strncmp(line + i, PINGCOUNT, strlen(PINGCOUNT)) == 0) { if (spool(line, &i, strlen(PINGCOUNT))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else pingcount = atol(line + i); } else if (strncmp(line + i, PING, strlen(PING)) == 0) { if (spool(line, &i, strlen(PING))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else add_list(&target, strdup(line + i)); } else if (strncmp(line + i, INTERFACE, strlen(INTERFACE)) == 0) { if (spool(line, &i, strlen(INTERFACE))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else add_list(&iface, strdup(line + i)); } else if (strncmp(line + i, REALTIME, strlen(REALTIME)) == 0) { (void)spool(line, &i, strlen(REALTIME)); realtime = (strncmp(line + i, "yes", 3) == 0) ? TRUE : FALSE; } else if (strncmp(line + i, PRIORITY, strlen(PRIORITY)) == 0) { if (spool(line, &i, strlen(PRIORITY))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else schedprio = atol(line + i); } else if (strncmp(line + i, REPAIRBIN, strlen(REPAIRBIN)) == 0) { if (spool(line, &i, strlen(REPAIRBIN))) rbinary = NULL; else rbinary = strdup(line + i); } else if (strncmp(line + i, TESTBIN, strlen(TESTBIN)) == 0) { if (spool(line, &i, strlen(TESTBIN))) tbinary = NULL; else tbinary = strdup(line + i); } else if (strncmp(line + i, TESTTIMEOUT, strlen(TESTTIMEOUT)) == 0) { if (spool(line, &i, strlen(TESTTIMEOUT))) timeout = 0; else timeout = atol(line + i); } else if (strncmp(line + i, HEARTBEAT, strlen(HEARTBEAT)) == 0) { if (spool(line, &i, strlen(HEARTBEAT))) heartbeat = NULL; else heartbeat = strdup(line + i); } else if (strncmp(line + i, HBSTAMPS, strlen(HBSTAMPS)) == 0) { if (spool(line, &i, strlen(HBSTAMPS))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else hbstamps = atol(line + i); } else if (strncmp(line + i, ADMIN, strlen(ADMIN)) == 0) { if (spool(line, &i, strlen(ADMIN))) admin = NULL; else admin = strdup(line + i); } else if (strncmp(line + i, INTERVAL, strlen(INTERVAL)) == 0) { if (spool(line, &i, strlen(INTERVAL))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else tint = atol(line + i); } else if (strncmp(line + i, LOGTICK, strlen(LOGTICK)) == 0) { if (spool(line, &i, strlen(LOGTICK))) logtick = ticker = 1; else logtick = ticker = atol(line + i); } else if (strncmp(line + i, DEVICE, strlen(DEVICE)) == 0) { if (spool(line, &i, strlen(DEVICE))) devname = NULL; else devname = strdup(line + i); } else if (strncmp(line + i, TEMP, strlen(TEMP)) == 0) { if (spool(line, &i, strlen(TEMP))) tempname = NULL; else tempname = strdup(line + i); } else if (strncmp(line + i, MAXTEMP, strlen(MAXTEMP)) == 0) { if (spool(line, &i, strlen(MAXTEMP))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else maxtemp = atol(line + i); } else if (strncmp(line + i, MAXLOAD15, strlen(MAXLOAD15)) == 0) { if (spool(line, &i, strlen(MAXLOAD15))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else { maxload15 = atol(line + i); gotload15 = TRUE; } } else if (strncmp(line + i, MAXLOAD1, strlen(MAXLOAD1)) == 0) { if (spool(line, &i, strlen(MAXLOAD1))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else { maxload1 = atol(line + i); if (!gotload5) maxload5 = maxload1 * 3 / 4; if (!gotload15) maxload15 = maxload1 / 2; } } else if (strncmp(line + i, MAXLOAD5, strlen(MAXLOAD5)) == 0) { if (spool(line, &i, strlen(MAXLOAD5))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else { maxload5 = atol(line + i); gotload5 = TRUE; } } else if (strncmp(line + i, MINMEM, strlen(MINMEM)) == 0) { if (spool(line, &i, strlen(MINMEM))) fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); else { minpages = atol(line + i); } } else { fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line); } } } if (fclose(wc) != 0) { perror(progname); exit(1); }}static void old_option(int c, char *filename){ fprintf(stderr, "Option -%c is no longer valid, please specify it in %s.\n", c, filename); usage();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -