luci-0.8: Merge r4467, r4468

This commit is contained in:
Jo-Philipp Wich 2009-05-04 17:31:32 +00:00
parent 684dc1a1aa
commit 0ddb6064a3
8 changed files with 1811 additions and 0 deletions

View file

@ -0,0 +1,50 @@
#
# Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=freifunk-watchdog
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/freifunk-watchdog
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Freifunk Ad-Hoc watchdog daemon
endef
define Package/freifunk-watchdog/description
A watchdog daemon that monitors wireless interfaces to ensure the correct bssid and channel.
The process will initiate a wireless restart as soon as it detects a bssid or channel mismatch.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Configure
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -I$(STAGING_DIR)/usr/include" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
define Package/freifunk-watchdog/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/freifunk-watchdog.init $(1)/etc/init.d/freifunk-watchdog
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ffwatchd $(1)/usr/sbin/
endef
$(eval $(call BuildPackage,freifunk-watchdog))

View file

@ -0,0 +1,24 @@
#!/bin/sh /etc/rc.common
START=99
PID=/var/run/ffwatchd.pid
BIN=/usr/sbin/ffwatchd
boot()
{
if ! grep -q "$BIN" /etc/crontabs/root 2>/dev/null; then
echo "* * * * * $BIN running || /etc/init.d/freifunk-watchdog restart" >> /etc/crontabs/root
fi
start
}
start()
{
start-stop-daemon -q -b -m -p $PID -x $BIN -S
}
stop()
{
start-stop-daemon -q -p $PID -x $BIN -K
}

View file

@ -0,0 +1,12 @@
WD_BINARY:=ffwatchd
WD_CFLAGS:=$(CFLAGS) -c -DBINARY=\"$(WD_BINARY)\"
WD_LDFLAGS:=$(LDFLAGS) -lm -luci
watchdog:
$(CC) $(WD_CFLAGS) -o ucix.o ucix.c
$(CC) $(WD_CFLAGS) -o watchdog.o watchdog.c
$(CC) $(WD_LDFLAGS) -o $(WD_BINARY) watchdog.o ucix.o
clean:
rm -f *~ $(WD_BINARY) *.o

View file

@ -0,0 +1,98 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
*
* Changed by Jo-Philipp Wich <xm@subsignal.org>
*/
#include <string.h>
#include <stdlib.h>
#include <uci_config.h>
#include <uci.h>
#include "ucix.h"
static struct uci_ptr ptr;
static inline int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t)
{
memset(&ptr, 0, sizeof(ptr));
ptr.package = p;
ptr.section = s;
ptr.option = o;
ptr.value = t;
return uci_lookup_ptr(ctx, &ptr, NULL, true);
}
struct uci_context* ucix_init(const char *config_file)
{
struct uci_context *ctx = uci_alloc_context();
uci_add_history_path(ctx, "/var/state");
if(uci_load(ctx, config_file, NULL) != UCI_OK)
{
return NULL;
}
return ctx;
}
void ucix_cleanup(struct uci_context *ctx)
{
uci_free_context(ctx);
}
const char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o)
{
struct uci_element *e = NULL;
const char *value = NULL;
if(ucix_get_ptr(ctx, p, s, o, NULL))
return NULL;
if (!(ptr.flags & UCI_LOOKUP_COMPLETE))
return NULL;
e = ptr.last;
switch (e->type)
{
case UCI_TYPE_SECTION:
value = uci_to_section(e)->type;
break;
case UCI_TYPE_OPTION:
switch(ptr.o->type) {
case UCI_TYPE_STRING:
value = ptr.o->v.string;
break;
default:
value = NULL;
break;
}
break;
default:
return 0;
}
return value;
}
void ucix_for_each_section_type(struct uci_context *ctx,
const char *p, const char *t,
void (*cb)(const char*, void*), void *priv)
{
struct uci_element *e;
if(ucix_get_ptr(ctx, p, NULL, NULL, NULL))
return;
uci_foreach_element(&ptr.p->sections, e)
if (!strcmp(t, uci_to_section(e)->type))
cb(e->name, priv);
}

View file

@ -0,0 +1,29 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
*/
#ifndef _UCI_H__
#define _UCI_H__
struct uci_context* ucix_init(const char *config_file);
void ucix_for_each_section_type(struct uci_context *ctx,
const char *p, const char *t,
void (*cb)(const char*, void*), void *priv);
const char* ucix_get_option(struct uci_context *ctx,
const char *p, const char *s, const char *o);
#endif

View file

@ -0,0 +1,352 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
*/
#include "watchdog.h"
/* Get BSSID of given interface */
static int iw_get_bssid(int iwfd, const char *ifname, char *bssid)
{
struct iwreq iwrq;
if( iw_ioctl(iwfd, ifname, SIOCGIWAP, &iwrq) >= 0 )
{
unsigned char *addr = (unsigned char *)iwrq.u.ap_addr.sa_data;
sprintf(bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
return 0;
}
return -1;
}
/* Get channel of given interface */
static int iw_get_channel(int iwfd, const char *ifname, int *channel)
{
int i;
char buffer[sizeof(struct iw_range)];
double cur_freq, cmp_freq;
struct iwreq iwrq;
struct iw_range *range;
memset(buffer, 0, sizeof(buffer));
iwrq.u.data.pointer = (char *)buffer;
iwrq.u.data.length = sizeof(buffer);
iwrq.u.data.flags = 0;
if( iw_ioctl(iwfd, ifname, SIOCGIWRANGE, &iwrq) < 0)
{
*channel = -1;
return -1;
}
range = (struct iw_range *)buffer;
if( iw_ioctl(iwfd, ifname, SIOCGIWFREQ, &iwrq) >= 0 )
{
cur_freq = ((double)iwrq.u.freq.m) * pow(10, iwrq.u.freq.e);
if( cur_freq < 1000.00 )
{
*channel = (int)cur_freq;
return 0;
}
for(i = 0; i < range->num_frequency; i++)
{
cmp_freq = ((double)range->freq[i].m) * pow(10, range->freq[i].e);
if( cmp_freq == cur_freq )
{
*channel = (int)range->freq[i].i;
return 0;
}
}
}
*channel = -1;
return -1;
}
/* Get the (first) pid of given process name */
static int find_process(const char *name)
{
int pid = -1;
int file;
char buffer[128];
char cmpname[128];
DIR *dir;
struct dirent *entry;
if( (dir = opendir("/proc")) != NULL )
{
snprintf(cmpname, sizeof(cmpname), "Name:\t%s\n", name);
while( (entry = readdir(dir)) != NULL )
{
if( !strcmp(entry->d_name, "..") || !isdigit(*entry->d_name) )
continue;
sprintf(buffer, "/proc/%s/status", entry->d_name);
if( (file = open(buffer, O_RDONLY)) > -1 )
{
read(file, buffer, sizeof(buffer));
close(file);
if( strstr(buffer, cmpname) == buffer )
{
pid = atoi(entry->d_name);
/* Skip myself ... */
if( pid == getpid() )
pid = -1;
else
break;
}
}
}
closedir(dir);
return pid;
}
syslog(LOG_CRIT, "Unable to open /proc: %s",
strerror(errno));
return -1;
}
/* Check if given uci file was updated */
static int check_uci_update(const char *config, time_t *mtime)
{
struct stat s;
char path[128];
snprintf(path, sizeof(path), "/etc/config/%s", config);
if( stat(path, &s) > -1 )
{
if( (*mtime == 0) || (s.st_mtime > *mtime) )
{
*mtime = s.st_mtime;
return 1;
}
else
{
snprintf(path, sizeof(path), "/var/state/%s", config);
if( stat(path, &s) > -1 )
{
if( (*mtime == 0) || (s.st_mtime > *mtime) )
{
*mtime = s.st_mtime;
return 1;
}
}
return 0;
}
}
return -1;
}
/* Add tuple */
static void load_wifi_uci_add_iface(const char *section, struct uci_itr_ctx *itr)
{
wifi_tuple_t *t;
const char *ucitmp;
int val = 0;
if( (t = (wifi_tuple_t *)malloc(sizeof(wifi_tuple_t))) != NULL )
{
ucitmp = ucix_get_option(itr->ctx, "wireless", section, "ifname");
if(ucitmp)
{
strncpy(t->ifname, ucitmp, sizeof(t->ifname));
val++;
}
ucitmp = ucix_get_option(itr->ctx, "wireless", section, "bssid");
if(ucitmp)
{
strncpy(t->bssid, ucitmp, sizeof(t->bssid));
val++;
}
ucitmp = ucix_get_option(itr->ctx, "wireless", section, "device");
if(ucitmp)
{
ucitmp = ucix_get_option(itr->ctx, "wireless", ucitmp, "channel");
if(ucitmp)
{
t->channel = atoi(ucitmp);
val++;
}
}
if( val == 3 )
{
syslog(LOG_INFO, "Monitoring %s: bssid=%s channel=%d",
t->ifname, t->bssid, t->channel);
t->next = itr->list;
itr->list = t;
}
else
{
free(t);
}
}
}
/* Load config */
static wifi_tuple_t * load_wifi_uci(wifi_tuple_t *ifs, time_t *modtime)
{
struct uci_context *ctx;
struct uci_itr_ctx itr;
wifi_tuple_t *cur, *next;
if( check_uci_update("wireless", modtime) )
{
syslog(LOG_INFO, "Config changed, reloading");
if( (ctx = ucix_init("wireless")) != NULL )
{
if( ifs != NULL )
{
for(cur = ifs; cur; cur = next)
{
next = cur->next;
free(cur);
}
}
itr.list = NULL;
itr.ctx = ctx;
ucix_for_each_section_type(ctx, "wireless", "wifi-iface",
(void *)load_wifi_uci_add_iface, &itr);
return itr.list;
}
}
return ifs;
}
/* Daemon implementation */
static int do_daemon(void)
{
int iwfd;
int channel;
char bssid[18];
wifi_tuple_t *ifs = NULL, *curif;
time_t modtime = 0;
int restart_wifi = 0;
int restart_cron = 0;
openlog(SYSLOG_IDENT, 0, LOG_DAEMON);
//daemon(1, 1);
if( (iwfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 )
{
perror("Can not open wireless control socket");
return 1;
}
while( 1 )
{
if( (ifs = load_wifi_uci(ifs, &modtime)) == NULL )
{
printf("Can not load wireless uci. File corrupt?\n");
return 1;
}
/* Check crond */
if( find_process("crond") < 0 )
{
syslog(LOG_WARNING, "The crond process died, restarting");
restart_cron++;
}
/* Check wireless interfaces */
for( curif = ifs; curif; curif = curif->next )
{
/* Get current channel and bssid */
if( (iw_get_bssid(iwfd, curif->ifname, bssid) == 0) &&
(iw_get_channel(iwfd, curif->ifname, &channel) == 0) )
{
/* Check BSSID */
if( strcasecmp(bssid, curif->bssid) != 0 )
{
syslog(LOG_WARNING, "BSSID mismatch on %s: current=%s wanted=%s",
curif->ifname, bssid, curif->bssid);
restart_wifi++;
}
/* Check channel */
if( channel != curif->channel )
{
syslog(LOG_WARNING, "Channel mismatch on %s: current=%d wanted=%d",
curif->ifname, channel, curif->channel);
restart_wifi++;
}
}
else
{
syslog(LOG_WARNING, "Requested interface %s not present", curif->ifname);
}
}
/* Wifi restart required? */
if( restart_wifi > 0 )
{
restart_wifi = 0;
EXEC(WIFI_ACTION);
}
/* Cron restart required? */
if( restart_cron > 0 )
{
restart_cron = 0;
EXEC(CRON_ACTION);
}
sleep(INTERVAL);
}
closelog();
return 0;
}
int main(int argc, char *argv[])
{
/* Check if watchdog is running ... */
if( (argc > 1) && (strcmp(argv[1], "running") == 0) )
{
return (find_process(BINARY) == -1);
}
/* Start daemon */
return do_daemon();
}

View file

@ -0,0 +1,107 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <syslog.h>
#include <ctype.h>
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <math.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "ucix.h"
#include "wireless.22.h"
/* Check interval */
#define INTERVAL 30
/* How to call myself in the logs */
#define SYSLOG_IDENT "Freifunk Watchdog"
/* Wifi error action */
#define WIFI_ACTION "/sbin/wifi", "/sbin/wifi"
/* Crond error action */
#define CRON_ACTION "/etc/init.d/cron", "/etc/init.d/cron", "restart"
/* Fallback binary name (passed by makefile) */
#ifndef BINARY
#define BINARY "ffwatchd"
#endif
/* ifname/bssid/channel tuples */
struct wifi_tuple {
char ifname[16];
char bssid[18];
int channel;
struct wifi_tuple *next;
};
/* structure to hold tuple-list and uci context during iteration */
struct uci_itr_ctx {
struct wifi_tuple *list;
struct uci_context *ctx;
};
typedef struct wifi_tuple wifi_tuple_t;
/* ioctl() helper (stolen from iwlib) */
static inline int
iw_ioctl(int skfd, /* Socket to the kernel */
const char * ifname, /* Device name */
int request, /* WE ID */
struct iwreq * pwrq) /* Fixed part of the request */
{
/* Set device name */
strncpy(pwrq->ifr_ifrn.ifrn_name, ifname, 16);
/* Do the request */
return(ioctl(skfd, request, pwrq));
}
/* fork() & execl() helper */
#define EXEC(x) \
do { \
switch(fork()) \
{ \
case -1: \
syslog(LOG_CRIT, "Unable to fork child: %s", \
strerror(errno)); \
\
break; \
\
case 0: \
execl(x, NULL); \
syslog(LOG_CRIT, "Unable to execute action: %s", \
strerror(errno)); \
\
return 1; \
} \
} while(0)

File diff suppressed because it is too large Load diff