Merge branch 'Toastman-RT' into Toastman-RT-N
[tomato.git] / release / src / router / rc / misc.c
blob6c17b1960286acd98ff6dbebcb7ceecbc06357c5
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "rc.h"
10 #include <stdarg.h>
11 #include <sys/ioctl.h>
12 #include <net/if_arp.h>
13 #include <netdb.h>
15 #include <bcmdevs.h>
16 #include <wlutils.h>
17 #include <dirent.h>
18 #include <sys/wait.h>
21 void usage_exit(const char *cmd, const char *help)
23 fprintf(stderr, "Usage: %s %s\n", cmd, help);
24 exit(1);
27 #if 0 // replaced by #define in rc.h
28 int modprobe(const char *mod)
30 #if 1
31 return eval("modprobe", "-s", (char *)mod);
32 #else
33 int r = eval("modprobe", "-s", (char *)mod);
34 cprintf("modprobe %s = %d\n", mod, r);
35 return r;
36 #endif
38 #endif // 0
40 int modprobe_r(const char *mod)
42 #if 1
43 return eval("modprobe", "-r", (char *)mod);
44 #else
45 int r = eval("modprobe", "-r", (char *)mod);
46 cprintf("modprobe -r %s = %d\n", mod, r);
47 return r;
48 #endif
51 #ifndef ct_modprobe
52 #ifdef LINUX26
53 #define ct_modprobe(mod, args...) ({ \
54 modprobe("nf_conntrack_"mod, ## args); \
55 modprobe("nf_nat_"mod); \
57 #else
58 #define ct_modprobe(mod, args...) ({ \
59 modprobe("ip_conntrack_"mod, ## args); \
60 modprobe("ip_nat_"mod, ## args); \
62 #endif
63 #endif
65 #ifndef ct_modprobe_r
66 #ifdef LINUX26
67 #define ct_modprobe_r(mod) ({ \
68 modprobe_r("nf_nat_"mod); \
69 modprobe_r("nf_conntrack_"mod); \
71 #else
72 #define ct_modprobe_r(mod) ({ \
73 modprobe_r("ip_nat_"mod); \
74 modprobe_r("ip_conntrack_"mod); \
76 #endif
77 #endif
79 /*
80 * The various child job starting functions:
81 * _eval()
82 * Start the child. If ppid param is NULL, wait until the child exits.
83 * Otherwise, store the child's pid in ppid and return immediately.
84 * eval()
85 * Call _eval with a NULL ppid, to wait for the child to exit.
86 * xstart()
87 * Call _eval with a garbage ppid (to not wait), then return.
88 * runuserfile
89 * Execute each executable in a directory that has the specified extention.
90 * Call _eval with a ppid (to not wait), then check every second for the child's pid.
91 * After wtime seconds or when the child has exited, return.
92 * If any such filename has an '&' character in it, then do *not* wait at
93 * all for the child to exit, regardless of the wtime.
96 #define MAX_XSTART_ARGC 16
97 int _xstart(const char *cmd, ...)
99 va_list ap;
100 char *argv[MAX_XSTART_ARGC];
101 int argc;
102 int pid;
104 argv[0] = (char *)cmd;
105 argc = 1;
106 va_start(ap, cmd);
107 while ((argv[argc++] = va_arg(ap, char *)) != NULL) {
108 if (argc >= MAX_XSTART_ARGC) {
109 _dprintf("%s: too many parameters\n", __FUNCTION__);
110 break;
113 va_end(ap);
115 return _eval(argv, NULL, 0, &pid);
118 static int endswith(const char *str, char *cmp)
120 int cmp_len, str_len, i;
122 cmp_len = strlen(cmp);
123 str_len = strlen(str);
124 if (cmp_len > str_len)
125 return 0;
126 for (i = 0; i < cmp_len; i++) {
127 if (str[(str_len - 1) - i] != cmp[(cmp_len - 1) - i])
128 return 0;
130 return 1;
133 static void execute_with_maxwait(char *const argv[], int wtime)
135 pid_t pid;
137 if (_eval(argv, NULL, 0, &pid) != 0)
138 pid = -1;
139 else {
140 while (wtime-- > 0) {
141 waitpid(pid, NULL, WNOHANG); /* Reap the zombie if it has terminated. */
142 if (kill(pid, 0) != 0) break;
143 sleep(1);
145 _dprintf("%s killdon: errno: %d pid %d\n", argv[0], errno, pid);
149 /* This is a bit ugly. Why didn't they allow another parameter to filter???? */
150 static char *filter_extension;
151 static int endswith_filter(const struct dirent *entry)
153 return endswith(entry->d_name, filter_extension);
156 /* If the filename has an '&' character in it, don't wait at all. */
157 void run_userfile(char *folder, char *extension, const char *arg1, int wtime)
159 unsigned char buf[PATH_MAX + 1];
160 char *argv[] = { buf, (char *)arg1, NULL };
161 struct dirent **namelist;
162 int i, n;
164 /* Do them in sorted order. */
165 filter_extension = extension;
166 n = scandir(folder, &namelist, endswith_filter, alphasort);
167 if (n >= 0) {
168 for (i = 0; i < n; ++i) {
169 sprintf(buf, "%s/%s", folder, namelist[i]->d_name);
170 execute_with_maxwait(argv,
171 strchr(namelist[i]->d_name, '&') ? 0 : wtime);
172 free(namelist[i]);
174 free(namelist);
178 /* Run user-supplied script(s), with 1 argument.
179 * Return when the script(s) have finished,
180 * or after wtime seconds, even if they aren't finished.
182 * Extract NAME from nvram variable named as "script_NAME".
184 * The sole exception to the nvram item naming rule is sesx.
185 * That one is "sesx_script" rather than "script_sesx", due
186 * to historical accident.
188 * The other exception is time-scheduled commands.
189 * These have names that start with "sch_".
190 * No directories are searched for corresponding user scripts.
192 * Execute in this order:
193 * nvram item: nv (run as a /bin/sh script)
194 * (unless nv starts with a dot)
195 * All files with a suffix of ".NAME" in these directories:
196 * /etc/config/
197 * /jffs/etc/config/
198 * /opt/etc/config/
199 * /mmc/etc/config/
200 * /tmp/config/
203 At this time, the names/events are:
204 (Unless otherwise noted, there are no parameters. Otherwise, one parameter).
205 sesx SES/AOSS Button custom script. Param: ??
206 brau "bridge/auto" button pushed. Param: mode (bridge/auto/etc)
207 fire When firewall service has been started or re-started.
208 shut At system shutdown, just before wan/lan/usb/etc. are stopped.
209 init At system startup, just before wan/lan/usb/etc. are started.
210 The root filesystem and /jffs are mounted, but not any USB devices.
211 usbmount After an auto-mounted USB drive is mounted.
212 usbumount Before an auto-mounted USB drive is unmounted.
213 usbhotplug When any USB device is attached or removed.
214 wanup After WAN has come up.
215 autostop When a USB partition gets un-mounted. Param: the mount-point (directory).
216 If unmounted from the GUI, the directory is still mounted and accessible.
217 If the USB drive was unplugged, it is still mounted but not accessible.
219 User scripts -- no directories are searched. One parameter.
220 autorun When a USB disk partition gets auto-mounted. Param: the mount-point (directory).
221 But not if the partition was already mounted.
222 Only the files in that directory will be run.
224 void run_nvscript(const char *nv, const char *arg1, int wtime)
226 FILE *f;
227 char *script;
228 char s[PATH_MAX + 1];
229 char *argv[] = { s, (char *)arg1, NULL };
230 int check_dirs = 1;
232 if (nv[0] == '.') {
233 strcpy(s, nv);
235 else {
236 script = nvram_get(nv);
238 if ((script) && (*script != 0)) {
239 sprintf(s, "/tmp/%s.sh", nv);
240 if ((f = fopen(s, "w")) != NULL) {
241 fputs("#!/bin/sh\n", f);
242 fputs(script, f);
243 fputs("\n", f);
244 fclose(f);
245 chmod(s, 0700);
246 chdir("/tmp");
248 _dprintf("Running: '%s %s'\n", argv[0], argv[1]? argv[1]: "");
249 execute_with_maxwait(argv, wtime);
250 chdir("/");
254 sprintf(s, ".%s", nv);
255 if (strncmp("sch_c", nv, 5) == 0) {
256 check_dirs = 0;
258 else if (strncmp("sesx_", nv, 5) == 0) {
259 s[5] = 0;
261 else if (strncmp("script_", nv, 7) == 0) {
262 strcpy(&s[1], &nv[7]);
266 if (nvram_match("userfiles_disable", "1")) {
267 // backdoor to disable user scripts execution
268 check_dirs = 0;
271 if ((check_dirs) && strcmp(s, ".") != 0) {
272 _dprintf("checking for user scripts: '%s'\n", s);
273 run_userfile("/etc/config", s, arg1, wtime);
274 run_userfile("/jffs/etc/config", s, arg1, wtime);
275 run_userfile("/opt/etc/config", s, arg1, wtime);
276 run_userfile("/mmc/etc/config", s, arg1, wtime);
277 run_userfile("/tmp/config", s, arg1, wtime);
281 static void write_ct_timeout(const char *type, const char *name, unsigned int val)
283 unsigned char buf[128];
284 char v[16];
286 sprintf(buf, "/proc/sys/net/ipv4/netfilter/ip_conntrack_%s_timeout%s%s",
287 type, (name && name[0]) ? "_" : "", name ? name : "");
288 sprintf(v, "%u", val);
290 f_write_string(buf, v, 0, 0);
293 #ifndef write_tcp_timeout
294 #define write_tcp_timeout(name, val) write_ct_timeout("tcp", name, val)
295 #endif
297 #ifndef write_udp_timeout
298 #define write_udp_timeout(name, val) write_ct_timeout("udp", name, val)
299 #endif
301 static unsigned int read_ct_timeout(const char *type, const char *name)
303 unsigned char buf[128];
304 unsigned int val = 0;
305 char v[16];
307 sprintf(buf, "/proc/sys/net/ipv4/netfilter/ip_conntrack_%s_timeout%s%s",
308 type, (name && name[0]) ? "_" : "", name ? name : "");
309 if (f_read_string(buf, v, sizeof(v)) > 0)
310 val = atoi(v);
312 return val;
315 #ifndef read_tcp_timeout
316 #define read_tcp_timeout(name) read_ct_timeout("tcp", name)
317 #endif
319 #ifndef read_udp_timeout
320 #define read_udp_timeout(name) read_ct_timeout("udp", name)
321 #endif
323 void setup_conntrack(void)
325 unsigned int v[10];
326 const char *p;
327 char buf[70];
328 int i;
330 p = nvram_safe_get("ct_tcp_timeout");
331 if (sscanf(p, "%u%u%u%u%u%u%u%u%u%u",
332 &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]) == 10) { // lightly verify
333 write_tcp_timeout("established", v[1]);
334 write_tcp_timeout("syn_sent", v[2]);
335 write_tcp_timeout("syn_recv", v[3]);
336 write_tcp_timeout("fin_wait", v[4]);
337 write_tcp_timeout("time_wait", v[5]);
338 write_tcp_timeout("close", v[6]);
339 write_tcp_timeout("close_wait", v[7]);
340 write_tcp_timeout("last_ack", v[8]);
342 else {
343 v[1] = read_tcp_timeout("established");
344 v[2] = read_tcp_timeout("syn_sent");
345 v[3] = read_tcp_timeout("syn_recv");
346 v[4] = read_tcp_timeout("fin_wait");
347 v[5] = read_tcp_timeout("time_wait");
348 v[6] = read_tcp_timeout("close");
349 v[7] = read_tcp_timeout("close_wait");
350 v[8] = read_tcp_timeout("last_ack");
351 sprintf(buf, "0 %u %u %u %u %u %u %u %u 0",
352 v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
353 nvram_set("ct_tcp_timeout", buf);
356 p = nvram_safe_get("ct_udp_timeout");
357 if (sscanf(p, "%u%u", &v[0], &v[1]) == 2) {
358 write_udp_timeout(NULL, v[0]);
359 write_udp_timeout("stream", v[1]);
361 else {
362 v[0] = read_udp_timeout(NULL);
363 v[1] = read_udp_timeout("stream");
364 sprintf(buf, "%u %u", v[0], v[1]);
365 nvram_set("ct_udp_timeout", buf);
368 p = nvram_safe_get("ct_timeout");
369 if (sscanf(p, "%u%u", &v[0], &v[1]) == 2) {
370 write_ct_timeout("generic", NULL, v[0]);
371 write_ct_timeout("icmp", NULL, v[1]);
373 else {
374 v[0] = read_ct_timeout("generic", NULL);
375 v[1] = read_ct_timeout("icmp", NULL);
376 sprintf(buf, "%u %u", v[0], v[1]);
377 nvram_set("ct_timeout", buf);
380 #ifdef LINUX26
381 p = nvram_safe_get("ct_hashsize");
382 i = atoi(p);
383 if (i >= 127) {
384 f_write_string("/sys/module/nf_conntrack/parameters/hashsize", p, 0, 0);
386 else if (f_read_string("/sys/module/nf_conntrack/parameters/hashsize", buf, sizeof(buf)) > 0) {
387 if (atoi(buf) > 0) nvram_set("ct_hashsize", buf);
389 #endif
391 p = nvram_safe_get("ct_max");
392 i = atoi(p);
393 if (i >= 128) {
394 f_write_string("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", p, 0, 0);
396 else if (f_read_string("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", buf, sizeof(buf)) > 0) {
397 if (atoi(buf) > 0) nvram_set("ct_max", buf);
400 if (!nvram_match("nf_rtsp", "0")) {
401 ct_modprobe("rtsp");
403 else {
404 ct_modprobe_r("rtsp");
407 if (!nvram_match("nf_h323", "0")) {
408 ct_modprobe("h323");
410 else {
411 ct_modprobe_r("h323");
414 #ifdef LINUX26
415 if (!nvram_match("nf_sip", "0")) {
416 ct_modprobe("sip");
418 else {
419 ct_modprobe_r("sip");
421 #endif
423 // !!TB - FTP Server
424 #ifdef TCONFIG_FTP
425 i = nvram_get_int("ftp_port");
426 if (nvram_match("ftp_enable", "1") && (i > 0) && (i != 21))
428 char ports[32];
430 sprintf(ports, "ports=21,%d", i);
431 ct_modprobe("ftp", ports);
433 else
434 #endif
435 if (!nvram_match("nf_ftp", "0")
436 #ifdef TCONFIG_FTP
437 || nvram_match("ftp_enable", "1") // !!TB - FTP Server
438 #endif
440 ct_modprobe("ftp");
442 else {
443 ct_modprobe_r("ftp");
446 if (!nvram_match("nf_pptp", "0")) {
447 ct_modprobe("proto_gre");
448 ct_modprobe("pptp");
450 else {
451 ct_modprobe_r("pptp");
452 ct_modprobe_r("proto_gre");
456 int host_addr_info(const char *name, int af, struct sockaddr_storage *buf)
458 struct addrinfo hints;
459 struct addrinfo *res;
460 struct addrinfo *p;
461 int err;
462 int addrtypes = 0;
464 memset(&hints, 0, sizeof hints);
465 #ifdef TCONFIG_IPV6
466 switch (af & (IPT_V4 | IPT_V6)) {
467 case IPT_V4:
468 hints.ai_family = AF_INET;
469 break;
470 case IPT_V6:
471 hints.ai_family = AF_INET6;
472 break;
473 //case (IPT_V4 | IPT_V6):
474 //case 0: // error?
475 default:
476 hints.ai_family = AF_UNSPEC;
478 #else
479 hints.ai_family = AF_INET;
480 #endif
481 hints.ai_socktype = SOCK_RAW;
483 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
484 return addrtypes;
487 for(p = res; p != NULL; p = p->ai_next) {
488 switch(p->ai_family) {
489 case AF_INET:
490 addrtypes |= IPT_V4;
491 break;
492 case AF_INET6:
493 addrtypes |= IPT_V6;
494 break;
496 if (buf && (hints.ai_family == p->ai_family) && res->ai_addrlen) {
497 memcpy(buf, res->ai_addr, res->ai_addrlen);
501 freeaddrinfo(res);
502 return (addrtypes & af);
505 inline int host_addrtypes(const char *name, int af)
507 return host_addr_info(name, af, NULL);
510 void inc_mac(char *mac, int plus)
512 unsigned char m[6];
513 int i;
515 for (i = 0; i < 6; i++)
516 m[i] = (unsigned char) strtol(mac + (3 * i), (char **)NULL, 16);
517 while (plus != 0) {
518 for (i = 5; i >= 3; --i) {
519 m[i] += (plus < 0) ? -1 : 1;
520 if (m[i] != 0) break; // continue if rolled over
522 plus += (plus < 0) ? 1 : -1;
524 sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
525 m[0], m[1], m[2], m[3], m[4], m[5]);
528 void set_mac(const char *ifname, const char *nvname, int plus)
530 int sfd;
531 struct ifreq ifr;
532 int up;
533 int j;
535 if ((sfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
536 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
537 return;
540 strcpy(ifr.ifr_name, ifname);
542 up = 0;
543 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0) {
544 if ((up = ifr.ifr_flags & IFF_UP) != 0) {
545 ifr.ifr_flags &= ~IFF_UP;
546 if (ioctl(sfd, SIOCSIFFLAGS, &ifr) != 0) {
547 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
551 else {
552 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
555 if (!ether_atoe(nvram_safe_get(nvname), (unsigned char *)&ifr.ifr_hwaddr.sa_data)) {
556 if (!ether_atoe(nvram_safe_get("et0macaddr"), (unsigned char *)&ifr.ifr_hwaddr.sa_data)) {
558 // goofy et0macaddr, make something up
559 nvram_set("et0macaddr", "00:01:23:45:67:89");
560 ifr.ifr_hwaddr.sa_data[0] = 0;
561 ifr.ifr_hwaddr.sa_data[1] = 0x01;
562 ifr.ifr_hwaddr.sa_data[2] = 0x23;
563 ifr.ifr_hwaddr.sa_data[3] = 0x45;
564 ifr.ifr_hwaddr.sa_data[4] = 0x67;
565 ifr.ifr_hwaddr.sa_data[5] = 0x89;
568 while (plus-- > 0) {
569 for (j = 5; j >= 3; --j) {
570 ifr.ifr_hwaddr.sa_data[j]++;
571 if (ifr.ifr_hwaddr.sa_data[j] != 0) break; // continue if rolled over
576 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
577 if (ioctl(sfd, SIOCSIFHWADDR, &ifr) == -1) {
578 _dprintf("Error setting %s address\n", ifname);
581 if (up) {
582 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0) {
583 ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
584 if (ioctl(sfd, SIOCSIFFLAGS, &ifr) == -1) {
585 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
588 else {
589 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
593 close(sfd);
597 const char *default_wanif(void)
599 return ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) ||
600 (check_hw_type() == HW_BCM4712)) ? "vlan1" : "eth1";
605 const char *default_wlif(void)
607 switch (check_hw_type()) {
608 case HW_BCM4702:
609 case HW_BCM4704_BCM5325F:
610 case HW_BCM4704_BCM5325F_EWC:
611 return "eth2";
613 return "eth1";
618 int _vstrsep(char *buf, const char *sep, ...)
620 va_list ap;
621 char **p;
622 int n;
624 n = 0;
625 va_start(ap, sep);
626 while ((p = va_arg(ap, char **)) != NULL) {
627 if ((*p = strsep(&buf, sep)) == NULL) break;
628 ++n;
630 va_end(ap);
631 return n;
634 void simple_unlock(const char *name)
636 char fn[256];
638 snprintf(fn, sizeof(fn), "/var/lock/%s.lock", name);
639 f_write(fn, NULL, 0, 0, 0600);
642 void simple_lock(const char *name)
644 int n;
645 char fn[256];
647 n = 5 + (getpid() % 10);
648 snprintf(fn, sizeof(fn), "/var/lock/%s.lock", name);
649 while (unlink(fn) != 0) {
650 if (--n == 0) {
651 syslog(LOG_DEBUG, "Breaking %s", fn);
652 break;
654 sleep(1);
658 void killall_tk(const char *name)
660 int n;
662 if (killall(name, SIGTERM) == 0) {
663 n = 50;
664 while ((killall(name, 0) == 0) && (n-- > 0)) {
665 _dprintf("%s: waiting name=%s n=%d\n", __FUNCTION__, name, n);
666 usleep(100 * 1000);
668 if (n < 0) {
669 n = 100;
670 while ((killall(name, SIGKILL) == 0) && (n-- > 0)) {
671 _dprintf("%s: SIGKILL name=%s n=%d\n", __FUNCTION__, name, n);
672 usleep(100 * 1000);
679 * Return non-zero if we created the directory,
680 * and zero if it already existed.
682 int mkdir_if_none(const char *path)
684 DIR *dp;
686 if (!(dp = opendir(path))) {
687 eval("mkdir", "-m", "0777", "-p", (char *)path);
688 return 1;
690 closedir(dp);
691 return 0;
694 long fappend(FILE *out, const char *fname)
696 FILE *in;
697 char buf[1024];
698 int n;
699 long r;
701 if ((in = fopen(fname, "r")) == NULL) return -1;
702 r = 0;
703 while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
704 if (fwrite(buf, 1, n, out) != n) {
705 r = -1;
706 break;
708 else {
709 r += n;
712 fclose(in);
713 return r;
716 long fappend_file(const char *path, const char *fname)
718 FILE *f;
719 int r = -1;
721 if (f_exists(fname) && (f = fopen(path, "a")) != NULL) {
722 r = fappend(f, fname);
723 fclose(f);
725 return r;