contrib/package/freifunk-watchdog: fixup build and package dependencies, fix hysteres...
[project/luci.git] / contrib / package / freifunk-watchdog / src / watchdog.c
1 /*
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.
6 *
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.
11 *
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.
15 *
16 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
17 */
18
19 #include "watchdog.h"
20
21 /* Get BSSID of given interface */
22 static int iw_get_bssid(int iwfd, const char *ifname, char *bssid)
23 {
24 struct iwreq iwrq;
25
26 if( iw_ioctl(iwfd, ifname, SIOCGIWAP, &iwrq) >= 0 )
27 {
28 unsigned char *addr = (unsigned char *)iwrq.u.ap_addr.sa_data;
29
30 sprintf(bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
31 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
32
33 return 0;
34 }
35
36 return -1;
37 }
38
39 /* Get channel of given interface */
40 static int iw_get_channel(int iwfd, const char *ifname, int *channel)
41 {
42 int i;
43 char buffer[sizeof(struct iw_range)];
44 double cur_freq, cmp_freq;
45 struct iwreq iwrq;
46 struct iw_range *range;
47
48 memset(buffer, 0, sizeof(buffer));
49
50 iwrq.u.data.pointer = (char *)buffer;
51 iwrq.u.data.length = sizeof(buffer);
52 iwrq.u.data.flags = 0;
53
54 if( iw_ioctl(iwfd, ifname, SIOCGIWRANGE, &iwrq) < 0)
55 {
56 *channel = -1;
57 return -1;
58 }
59
60 range = (struct iw_range *)buffer;
61
62 if( iw_ioctl(iwfd, ifname, SIOCGIWFREQ, &iwrq) >= 0 )
63 {
64 cur_freq = ((double)iwrq.u.freq.m) * pow(10, iwrq.u.freq.e);
65 if( cur_freq < 1000.00 )
66 {
67 *channel = (int)cur_freq;
68 return 0;
69 }
70
71 for(i = 0; i < range->num_frequency; i++)
72 {
73 cmp_freq = ((double)range->freq[i].m) * pow(10, range->freq[i].e);
74 if( cmp_freq == cur_freq )
75 {
76 *channel = (int)range->freq[i].i;
77 return 0;
78 }
79 }
80 }
81
82 *channel = -1;
83 return -1;
84 }
85
86 /* Get the (first) pid of given process name */
87 static int find_process(const char *name)
88 {
89 int pid = -1;
90 int file;
91 char buffer[128];
92 char cmpname[128];
93 DIR *dir;
94 struct dirent *entry;
95
96 if( (dir = opendir("/proc")) != NULL )
97 {
98 snprintf(cmpname, sizeof(cmpname), "Name:\t%s\n", name);
99
100 while( (entry = readdir(dir)) != NULL )
101 {
102 if( !strcmp(entry->d_name, "..") || !isdigit(*entry->d_name) )
103 continue;
104
105 sprintf(buffer, "/proc/%s/status", entry->d_name);
106 if( (file = open(buffer, O_RDONLY)) > -1 )
107 {
108 read(file, buffer, sizeof(buffer));
109 close(file);
110
111 if( strstr(buffer, cmpname) == buffer )
112 {
113 pid = atoi(entry->d_name);
114
115 /* Skip myself ... */
116 if( pid == getpid() )
117 pid = -1;
118 else
119 break;
120 }
121 }
122 }
123
124 closedir(dir);
125 return pid;
126 }
127
128 syslog(LOG_CRIT, "Unable to open /proc: %s",
129 strerror(errno));
130
131 return -1;
132 }
133
134 /* Check if given uci file was updated */
135 static int check_uci_update(const char *config, time_t *mtime)
136 {
137 struct stat s;
138 char path[128];
139
140 snprintf(path, sizeof(path), "/etc/config/%s", config);
141 if( stat(path, &s) > -1 )
142 {
143 if( (*mtime == 0) || (s.st_mtime > *mtime) )
144 {
145 *mtime = s.st_mtime;
146 return 1;
147 }
148 else
149 {
150 snprintf(path, sizeof(path), "/var/state/%s", config);
151 if( stat(path, &s) > -1 )
152 {
153 if( (*mtime == 0) || (s.st_mtime > *mtime) )
154 {
155 *mtime = s.st_mtime;
156 return 1;
157 }
158 }
159
160 return 0;
161 }
162 }
163
164 return -1;
165 }
166
167 /* Add tuple */
168 static void load_wifi_uci_add_iface(const char *section, struct uci_itr_ctx *itr)
169 {
170 wifi_tuple_t *t;
171 const char *ucitmp;
172 int val = 0;
173
174 if( (t = (wifi_tuple_t *)malloc(sizeof(wifi_tuple_t))) != NULL )
175 {
176 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "ifname");
177 if(ucitmp)
178 {
179 strncpy(t->ifname, ucitmp, sizeof(t->ifname));
180 val++;
181 }
182
183 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "bssid");
184 if(ucitmp)
185 {
186 strncpy(t->bssid, ucitmp, sizeof(t->bssid));
187 val++;
188 }
189
190 ucitmp = ucix_get_option(itr->ctx, "wireless", section, "device");
191 if(ucitmp)
192 {
193 ucitmp = ucix_get_option(itr->ctx, "wireless", ucitmp, "channel");
194 if(ucitmp)
195 {
196 t->channel = atoi(ucitmp);
197 val++;
198 }
199 }
200
201 if( val == 3 )
202 {
203 syslog(LOG_INFO, "Monitoring %s: bssid=%s channel=%d",
204 t->ifname, t->bssid, t->channel);
205
206 t->next = itr->list;
207 itr->list = t;
208 }
209 else
210 {
211 free(t);
212 }
213 }
214 }
215
216 /* Load config */
217 static wifi_tuple_t * load_wifi_uci(wifi_tuple_t *ifs, time_t *modtime)
218 {
219 struct uci_context *ctx;
220 struct uci_itr_ctx itr;
221 wifi_tuple_t *cur, *next;
222
223 if( check_uci_update("wireless", modtime) )
224 {
225 syslog(LOG_INFO, "Config changed, reloading");
226
227 if( (ctx = ucix_init("wireless")) != NULL )
228 {
229 if( ifs != NULL )
230 {
231 for(cur = ifs; cur; cur = next)
232 {
233 next = cur->next;
234 free(cur);
235 }
236 }
237
238 itr.list = NULL;
239 itr.ctx = ctx;
240
241 ucix_for_each_section_type(ctx, "wireless", "wifi-iface",
242 (void *)load_wifi_uci_add_iface, &itr);
243
244 return itr.list;
245 }
246 }
247
248 return ifs;
249 }
250
251 /* Daemon implementation */
252 static int do_daemon(void)
253 {
254 int iwfd;
255 int channel;
256 char bssid[18];
257
258 wifi_tuple_t *ifs = NULL, *curif;
259 time_t modtime = 0;
260
261 int restart_wifi = 0;
262 int restart_cron = 0;
263
264 openlog(SYSLOG_IDENT, 0, LOG_DAEMON);
265 //daemon(1, 1);
266
267 if( (iwfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 )
268 {
269 perror("Can not open wireless control socket");
270 return 1;
271 }
272
273 while( 1 )
274 {
275 if( (ifs = load_wifi_uci(ifs, &modtime)) == NULL )
276 {
277 printf("Can not load wireless uci. File corrupt?\n");
278 return 1;
279 }
280
281 /* Check crond */
282 if( find_process("crond") < 0 )
283 {
284 syslog(LOG_WARNING, "The crond process died, restarting");
285 restart_cron++;
286 }
287
288 /* Check wireless interfaces */
289 for( curif = ifs; curif; curif = curif->next )
290 {
291 /* Get current channel and bssid */
292 if( (iw_get_bssid(iwfd, curif->ifname, bssid) == 0) &&
293 (iw_get_channel(iwfd, curif->ifname, &channel) == 0) )
294 {
295 /* Check BSSID */
296 if( strcasecmp(bssid, curif->bssid) != 0 )
297 {
298 syslog(LOG_WARNING, "BSSID mismatch on %s: current=%s wanted=%s",
299 curif->ifname, bssid, curif->bssid);
300
301 restart_wifi++;
302 }
303
304 /* Check channel */
305 else if( channel != curif->channel )
306 {
307 syslog(LOG_WARNING, "Channel mismatch on %s: current=%d wanted=%d",
308 curif->ifname, channel, curif->channel);
309
310 restart_wifi++;
311 }
312 }
313 else
314 {
315 syslog(LOG_WARNING, "Requested interface %s not present", curif->ifname);
316 }
317 }
318
319
320 /* Wifi restart required? */
321 if( restart_wifi >= HYSTERESIS )
322 {
323 restart_wifi = 0;
324 syslog(LOG_WARNING, "Restarting wireless");
325 EXEC(WIFI_ACTION);
326 }
327
328 /* Cron restart required? */
329 if( restart_cron >= HYSTERESIS )
330 {
331 restart_cron = 0;
332 syslog(LOG_WARNING, "Restarting crond process");
333 EXEC(CRON_ACTION);
334 }
335
336 sleep(INTERVAL);
337 }
338
339 closelog();
340 return 0;
341 }
342
343
344 int main(int argc, char *argv[])
345 {
346 /* Check if watchdog is running ... */
347 if( (argc > 1) && (strcmp(argv[1], "running") == 0) )
348 {
349 return (find_process(BINARY) == -1);
350 }
351
352 /* Start daemon */
353 return do_daemon();
354 }