2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 * Copyright (C) 2009 Jo-Philipp Wich <jow@openwrt.org>
21 /* Global watchdog fd, required by signal handler */
24 /* Handle finished children */
25 static void sigchld_handler(int sig)
29 while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 )
30 syslog(LOG_INFO, "Child returned (pid %d)", pid);
33 /* Watchdog shutdown helper */
34 static void shutdown_watchdog(int sig)
36 static const char wshutdown = WATCH_SHUTDOWN;
40 syslog(LOG_INFO, "Stopping watchdog timer");
41 write(wdfd, &wshutdown, 1);
49 /* Get BSSID of given interface */
50 static int iw_get_bssid(int iwfd, const char *ifname, char *bssid)
54 if( iw_ioctl(iwfd, ifname, SIOCGIWAP, &iwrq) >= 0 )
56 unsigned char *addr = (unsigned char *)iwrq.u.ap_addr.sa_data;
58 sprintf(bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
59 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
67 /* Get channel of given interface */
68 static int iw_get_channel(int iwfd, const char *ifname, int *channel)
71 char buffer[sizeof(struct iw_range)];
72 double cur_freq, cmp_freq;
74 struct iw_range *range;
76 memset(buffer, 0, sizeof(buffer));
78 iwrq.u.data.pointer = (char *)buffer;
79 iwrq.u.data.length = sizeof(buffer);
80 iwrq.u.data.flags = 0;
82 if( iw_ioctl(iwfd, ifname, SIOCGIWRANGE, &iwrq) < 0)
88 range = (struct iw_range *)buffer;
90 if( iw_ioctl(iwfd, ifname, SIOCGIWFREQ, &iwrq) >= 0 )
92 cur_freq = ((double)iwrq.u.freq.m) * pow(10, iwrq.u.freq.e);
93 if( cur_freq < 1000.00 )
95 *channel = (int)cur_freq;
99 for(i = 0; i < range->num_frequency; i++)
101 cmp_freq = ((double)range->freq[i].m) * pow(10, range->freq[i].e);
102 if( cmp_freq == cur_freq )
104 *channel = (int)range->freq[i].i;
114 /* Get the (first) pid of given process name */
115 static int find_process(const char *name)
122 struct dirent *entry;
124 if( (dir = opendir("/proc")) != NULL )
126 snprintf(cmpname, sizeof(cmpname), "Name:\t%s\n", name);
128 while( (entry = readdir(dir)) != NULL )
130 if( !strcmp(entry->d_name, "..") || !isdigit(*entry->d_name) )
133 sprintf(buffer, "/proc/%s/status", entry->d_name);
134 if( (file = open(buffer, O_RDONLY)) > -1 )
136 read(file, buffer, sizeof(buffer));
139 if( strstr(buffer, cmpname) == buffer )
141 pid = atoi(entry->d_name);
143 /* Skip myself ... */
144 if( pid == getpid() )
156 syslog(LOG_CRIT, "Unable to open /proc: %s",
162 /* Get the 5 minute load average */
163 static double find_loadavg(void)
169 if( (fd = open("/proc/loadavg", O_RDONLY)) > -1 )
171 if( read(fd, buffer, sizeof(buffer)) == sizeof(buffer) )
172 load = atof(&buffer[5]);
180 /* Check if given uci file was updated */
181 static int check_uci_update(const char *config, time_t *mtime)
186 snprintf(path, sizeof(path), "/var/state/%s", config);
187 if( stat(path, &s) > -1 )
189 if( (*mtime == 0) || (s.st_mtime > *mtime) )
200 static void load_wifi_uci_add_iface(const char *section, struct uci_wifi_iface_itr_ctx *itr)
206 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "mode");
207 if( ucitmp && !strncmp(ucitmp, "adhoc", 5) )
209 if( (t = (wifi_tuple_t *)malloc(sizeof(wifi_tuple_t))) != NULL )
211 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "ifname");
214 strncpy(t->ifname, ucitmp, sizeof(t->ifname));
218 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "bssid");
221 strncpy(t->bssid, ucitmp, sizeof(t->bssid));
225 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "device");
228 ucitmp = ucix_get_option(itr->ctx, "wireless", ucitmp, "channel");
231 t->channel = atoi(ucitmp);
238 syslog(LOG_INFO, "Monitoring %s: bssid=%s channel=%d",
239 t->ifname, t->bssid, t->channel);
253 static wifi_tuple_t * load_wifi_uci(wifi_tuple_t *ifs, time_t *modtime)
255 struct uci_context *ctx;
256 struct uci_wifi_iface_itr_ctx itr;
257 wifi_tuple_t *cur, *next;
259 if( check_uci_update("wireless", modtime) )
261 syslog(LOG_INFO, "Wireless config changed, reloading");
263 if( (ctx = ucix_init("wireless")) != NULL )
267 for(cur = ifs; cur; cur = next)
277 ucix_for_each_section_type(ctx, "wireless", "wifi-iface",
278 (void *)load_wifi_uci_add_iface, &itr);
288 static void load_watchdog_uci_add_process(const char *section, struct uci_process_itr_ctx *itr)
294 if( (t = (process_tuple_t *)malloc(sizeof(process_tuple_t))) != NULL )
298 ucitmp = ucix_get_option(itr->ctx, "freifunk-watchdog", section, "process");
301 strncpy(t->process, ucitmp, sizeof(t->process));
305 ucitmp = ucix_get_option(itr->ctx, "freifunk-watchdog", section, "initscript");
308 strncpy(t->initscript, ucitmp, sizeof(t->initscript));
314 syslog(LOG_INFO, "Monitoring %s: initscript=%s",
315 t->process, t->initscript);
328 static process_tuple_t * load_watchdog_uci(process_tuple_t *procs)
330 struct uci_context *ctx;
331 struct uci_process_itr_ctx itr;
332 process_tuple_t *cur, *next;
334 syslog(LOG_INFO, "Loading watchdog config");
336 if( (ctx = ucix_init("freifunk-watchdog")) != NULL )
340 for(cur = procs; cur; cur = next)
350 ucix_for_each_section_type(ctx, "freifunk-watchdog", "process",
351 (void *)load_watchdog_uci_add_process, &itr);
359 /* Daemon implementation */
360 static int do_daemon(void)
362 static int wdtrigger = 1;
363 static int wdtimeout = BASE_INTERVAL * 2;
364 static const char wdkeepalive = WATCH_KEEPALIVE;
371 wifi_tuple_t *ifs = NULL, *curr_if;
372 process_tuple_t *procs = NULL, *curr_proc;
373 time_t wireless_modtime = 0;
376 int restart_wifi = 0;
377 int loadavg_panic = 0;
379 openlog(SYSLOG_IDENT, 0, LOG_DAEMON);
380 memset(&sa, 0, sizeof(sa));
382 if( (iwfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 )
384 syslog(LOG_ERR, "Can not open wireless control socket: %s",
390 if( (wdfd = open(WATCH_DEVICE, O_WRONLY)) > -1 )
392 syslog(LOG_INFO, "Opened %s - polling every %i seconds",
393 WATCH_DEVICE, BASE_INTERVAL);
395 /* Install signal handler to halt watchdog on shutdown */
396 sa.sa_handler = shutdown_watchdog;
397 sa.sa_flags = SA_NOCLDWAIT | SA_RESTART;
398 sigaction(SIGHUP, &sa, NULL);
399 sigaction(SIGINT, &sa, NULL);
400 sigaction(SIGPIPE, &sa, NULL);
401 sigaction(SIGTERM, &sa, NULL);
402 sigaction(SIGUSR1, &sa, NULL);
403 sigaction(SIGUSR2, &sa, NULL);
405 /* Set watchdog timeout to twice the interval */
406 ioctl(wdfd, WDIOC_SETTIMEOUT, &wdtimeout);
409 /* Install signal handler to reap children */
410 sa.sa_handler = sigchld_handler;
412 sigaction(SIGCHLD, &sa, NULL);
414 /* Load watchdog configuration only once */
415 procs = load_watchdog_uci(procs);
419 /* Check/increment action interval */
420 if( ++action_intv >= ACTION_INTERVAL )
422 /* Reset action interval */
425 /* Check average load */
426 if( find_loadavg() >= LOAD_TRESHOLD )
431 /* Check wireless interfaces */
432 ifs = load_wifi_uci(ifs, &wireless_modtime);
433 for( curr_if = ifs; curr_if; curr_if = curr_if->next )
435 /* Get current channel and bssid */
436 if( (iw_get_bssid(iwfd, curr_if->ifname, bssid) == 0) &&
437 (iw_get_channel(iwfd, curr_if->ifname, &channel) == 0) )
440 if( strcasecmp(bssid, curr_if->bssid) != 0 )
442 syslog(LOG_WARNING, "BSSID mismatch on %s: current=%s wanted=%s",
443 curr_if->ifname, bssid, curr_if->bssid);
449 else if( channel != curr_if->channel )
451 syslog(LOG_WARNING, "Channel mismatch on %s: current=%d wanted=%d",
452 curr_if->ifname, channel, curr_if->channel);
459 syslog(LOG_WARNING, "Requested interface %s not present", curr_if->ifname);
463 /* Check processes */
464 for( curr_proc = procs; curr_proc; curr_proc = curr_proc->next )
466 if( find_process(curr_proc->process) < 0 )
467 curr_proc->restart++;
469 curr_proc->restart = 0;
471 /* Process restart required? */
472 if( curr_proc->restart >= HYSTERESIS )
474 curr_proc->restart = 0;
475 syslog(LOG_WARNING, "The %s process died, restarting", curr_proc->process);
481 /* Wifi restart required? */
482 if( restart_wifi >= HYSTERESIS )
485 syslog(LOG_WARNING, "Channel or BSSID mismatch on wireless interface, restarting");
489 /* Is there a load problem? */
490 if( loadavg_panic >= HYSTERESIS )
492 syslog(LOG_EMERG, "Critical system load level, triggering reset!");
494 /* Try watchdog, fall back to reboot */
496 ioctl(wdfd, WDIOC_SETTIMEOUT, &wdtrigger);
503 /* Reset watchdog timer */
505 write(wdfd, &wdkeepalive, 1);
507 sleep(BASE_INTERVAL);
510 shutdown_watchdog(0);
517 int main(int argc, char *argv[])
519 /* Check if watchdog is running ... */
520 if( (argc > 1) && (strcmp(argv[1], "running") == 0) )
522 return (find_process(BINARY) == -1);