rc, httpd: cosmetics
[tomato.git] / release / src / router / rc / misc.c
blobcf3742ee44c3fb8991a2649bdf3fdc2dc580ec91
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");
457 struct sockaddr_storage *host_to_addr(const char *name, sa_family_t family)
459 static struct sockaddr_storage buf;
461 struct addrinfo hints;
462 struct addrinfo *res;
463 int err;
465 memset(&hints, 0, sizeof(hints));
466 #ifdef TCONFIG_IPV6
467 hints.ai_family = family;
468 #else
469 hints.ai_family = AF_INET;
470 #endif
471 hints.ai_socktype = SOCK_RAW;
473 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0)
474 return NULL;
476 #ifdef TCONFIG_IPV6
477 if (res->ai_family != family)
478 return NULL;
480 if (family == AF_INET6) {
481 if (res->ai_addrlen != sizeof(struct sockaddr_in6))
482 return NULL;
483 memcpy(&buf, res->ai_addr, sizeof(struct sockaddr_in6));
485 else
486 #endif
488 if (res->ai_addrlen != sizeof(struct sockaddr_in))
489 return NULL;
490 memcpy(&buf, res->ai_addr, sizeof(struct sockaddr_in));
493 freeaddrinfo(res);
494 return &(buf);
498 int host_addrtypes(const char *name, int af)
500 struct addrinfo hints;
501 struct addrinfo *res;
502 struct addrinfo *p;
503 int err;
504 int addrtypes = 0;
506 memset(&hints, 0, sizeof hints);
507 #ifdef TCONFIG_IPV6
508 switch (af & (IPT_V4 | IPT_V6)) {
509 case IPT_V4:
510 hints.ai_family = AF_INET;
511 break;
512 case IPT_V6:
513 hints.ai_family = AF_INET6;
514 break;
515 //case (IPT_V4 | IPT_V6):
516 //case 0: // error?
517 default:
518 hints.ai_family = AF_UNSPEC;
520 #else
521 hints.ai_family = AF_INET;
522 #endif
523 hints.ai_socktype = SOCK_RAW;
525 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
526 return addrtypes;
529 for(p = res; p != NULL; p = p->ai_next) {
530 switch(p->ai_family) {
531 case AF_INET:
532 addrtypes |= IPT_V4;
533 break;
534 case AF_INET6:
535 addrtypes |= IPT_V6;
536 break;
540 freeaddrinfo(res);
541 return (addrtypes & af);
545 void inc_mac(char *mac, int plus)
547 unsigned char m[6];
548 int i;
550 for (i = 0; i < 6; i++)
551 m[i] = (unsigned char) strtol(mac + (3 * i), (char **)NULL, 16);
552 while (plus != 0) {
553 for (i = 5; i >= 3; --i) {
554 m[i] += (plus < 0) ? -1 : 1;
555 if (m[i] != 0) break; // continue if rolled over
557 plus += (plus < 0) ? 1 : -1;
559 sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
560 m[0], m[1], m[2], m[3], m[4], m[5]);
563 void set_mac(const char *ifname, const char *nvname, int plus)
565 int sfd;
566 struct ifreq ifr;
567 int up;
568 int j;
570 if ((sfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
571 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
572 return;
575 strcpy(ifr.ifr_name, ifname);
577 up = 0;
578 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0) {
579 if ((up = ifr.ifr_flags & IFF_UP) != 0) {
580 ifr.ifr_flags &= ~IFF_UP;
581 if (ioctl(sfd, SIOCSIFFLAGS, &ifr) != 0) {
582 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
586 else {
587 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
590 if (!ether_atoe(nvram_safe_get(nvname), (unsigned char *)&ifr.ifr_hwaddr.sa_data)) {
591 if (!ether_atoe(nvram_safe_get("et0macaddr"), (unsigned char *)&ifr.ifr_hwaddr.sa_data)) {
593 // goofy et0macaddr, make something up
594 nvram_set("et0macaddr", "00:01:23:45:67:89");
595 ifr.ifr_hwaddr.sa_data[0] = 0;
596 ifr.ifr_hwaddr.sa_data[1] = 0x01;
597 ifr.ifr_hwaddr.sa_data[2] = 0x23;
598 ifr.ifr_hwaddr.sa_data[3] = 0x45;
599 ifr.ifr_hwaddr.sa_data[4] = 0x67;
600 ifr.ifr_hwaddr.sa_data[5] = 0x89;
603 while (plus-- > 0) {
604 for (j = 5; j >= 3; --j) {
605 ifr.ifr_hwaddr.sa_data[j]++;
606 if (ifr.ifr_hwaddr.sa_data[j] != 0) break; // continue if rolled over
611 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
612 if (ioctl(sfd, SIOCSIFHWADDR, &ifr) == -1) {
613 _dprintf("Error setting %s address\n", ifname);
616 if (up) {
617 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0) {
618 ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
619 if (ioctl(sfd, SIOCSIFFLAGS, &ifr) == -1) {
620 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
623 else {
624 _dprintf("%s: %s %d\n", ifname, __FUNCTION__, __LINE__);
628 close(sfd);
632 const char *default_wanif(void)
634 return ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) ||
635 (check_hw_type() == HW_BCM4712)) ? "vlan1" : "eth1";
640 const char *default_wlif(void)
642 switch (check_hw_type()) {
643 case HW_BCM4702:
644 case HW_BCM4704_BCM5325F:
645 case HW_BCM4704_BCM5325F_EWC:
646 return "eth2";
648 return "eth1";
653 int _vstrsep(char *buf, const char *sep, ...)
655 va_list ap;
656 char **p;
657 int n;
659 n = 0;
660 va_start(ap, sep);
661 while ((p = va_arg(ap, char **)) != NULL) {
662 if ((*p = strsep(&buf, sep)) == NULL) break;
663 ++n;
665 va_end(ap);
666 return n;
669 void simple_unlock(const char *name)
671 char fn[256];
673 snprintf(fn, sizeof(fn), "/var/lock/%s.lock", name);
674 f_write(fn, NULL, 0, 0, 0600);
677 void simple_lock(const char *name)
679 int n;
680 char fn[256];
682 n = 5 + (getpid() % 10);
683 snprintf(fn, sizeof(fn), "/var/lock/%s.lock", name);
684 while (unlink(fn) != 0) {
685 if (--n == 0) {
686 syslog(LOG_DEBUG, "Breaking %s", fn);
687 break;
689 sleep(1);
693 void killall_tk(const char *name)
695 int n;
697 if (killall(name, SIGTERM) == 0) {
698 n = 50;
699 while ((killall(name, 0) == 0) && (n-- > 0)) {
700 _dprintf("%s: waiting name=%s n=%d\n", __FUNCTION__, name, n);
701 usleep(100 * 1000);
703 if (n < 0) {
704 n = 100;
705 while ((killall(name, SIGKILL) == 0) && (n-- > 0)) {
706 _dprintf("%s: SIGKILL name=%s n=%d\n", __FUNCTION__, name, n);
707 usleep(100 * 1000);
714 * Return non-zero if we created the directory,
715 * and zero if it already existed.
717 int mkdir_if_none(const char *path)
719 DIR *dp;
721 if (!(dp = opendir(path))) {
722 eval("mkdir", "-m", "0777", "-p", (char *)path);
723 return 1;
725 closedir(dp);
726 return 0;
729 long fappend(FILE *out, const char *fname)
731 FILE *in;
732 char buf[1024];
733 int n;
734 long r;
736 if ((in = fopen(fname, "r")) == NULL) return -1;
737 r = 0;
738 while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
739 if (fwrite(buf, 1, n, out) != n) {
740 r = -1;
741 break;
743 else {
744 r += n;
747 fclose(in);
748 return r;
751 long fappend_file(const char *path, const char *fname)
753 FILE *f;
754 int r = -1;
756 if (f_exists(fname) && (f = fopen(path, "a")) != NULL) {
757 r = fappend(f, fname);
758 fclose(f);
760 return r;