Merge Tomato 1.26
[tomato.git] / release / src / router / httpd / misc.c
blobed3f02f8ef69ec94b45e972fd9193e0648ac9324
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "tomato.h"
10 #include <ctype.h>
11 #include <sys/sysinfo.h>
12 #include <sys/stat.h>
13 #include <sys/ioctl.h>
14 #include <net/if.h>
15 #include <fcntl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include <time.h>
22 #include <sys/statfs.h>
23 #include <netdb.h>
24 #include <net/route.h>
26 // !!TB
27 #ifdef TCONFIG_USB
28 //#include <sys/mount.h>
29 #include <mntent.h>
30 #endif
32 #include <wlioctl.h>
33 #include <wlutils.h>
35 // to javascript-safe string
36 char *js_string(const char *s)
38 unsigned char c;
39 char *buffer;
40 char *b;
42 if ((buffer = malloc((strlen(s) * 4) + 1)) != NULL) {
43 b = buffer;
44 while ((c = *s++) != 0) {
45 if ((c == '"') || (c == '\'') || (c == '\\') || (!isprint(c))) {
46 b += sprintf(b, "\\x%02x", c);
48 else {
49 *b++ = c;
52 *b = 0;
54 return buffer;
57 // to html-safe string
58 char *html_string(const char *s)
60 unsigned char c;
61 char *buffer;
62 char *b;
64 if ((buffer = malloc((strlen(s) * 6) + 1)) != NULL) {
65 b = buffer;
66 while ((c = *s++) != 0) {
67 if ((c == '&') || (c == '<') || (c == '>') || (c == '"') || (c == '\'') || (!isprint(c))) {
68 b += sprintf(b, "&#%d;", c);
70 else {
71 *b++ = c;
74 *b = 0;
76 return buffer;
79 // removes \r
80 char *unix_string(const char *s)
82 char *buffer;
83 char *b;
84 char c;
86 if ((buffer = malloc(strlen(s) + 1)) != NULL) {
87 b = buffer;
88 while ((c = *s++) != 0)
89 if (c != '\r') *b++ = c;
90 *b = 0;
92 return buffer;
95 // # days, ##:##:##
96 char *reltime(char *buf, time_t t)
98 int days;
99 int m;
101 if (t < 0) t = 0;
102 days = t / 86400;
103 m = t / 60;
104 sprintf(buf, "%d day%s, %02d:%02d:%02d", days, ((days==1) ? "" : "s"), ((m / 60) % 24), (m % 60), (int)(t % 60));
105 return buf;
108 int get_client_info(char *mac, char *ifname)
110 FILE *f;
111 char s[256];
112 char ips[16];
115 # cat /proc/net/arp
116 IP address HW type Flags HW address Mask Device
117 192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1
118 192.168.1.5 0x1 0x2 00:05:06:07:08:09 * br0
121 if ((f = fopen("/proc/net/arp", "r")) != NULL) {
122 while (fgets(s, sizeof(s), f)) {
123 if (sscanf(s, "%15s %*s %*s %17s %*s %16s", ips, mac, ifname) == 3) {
124 if (inet_addr(ips) == clientsai.sin_addr.s_addr) {
125 fclose(f);
126 return 1;
130 fclose(f);
132 return 0;
139 // <% lanip(mode); %>
140 // <mode>
141 // 1 return first 3 octets (192.168.1)
142 // 2 return last octet (1)
143 // else return full (192.168.1.1)
145 void asp_lanip(int argc, char **argv)
147 char *nv, *p;
148 char s[64];
149 char mode;
151 mode = argc ? *argv[0] : 0;
153 if ((nv = nvram_get("lan_ipaddr")) != NULL) {
154 strcpy(s, nv);
155 if ((p = strrchr(s, '.')) != NULL) {
156 *p = 0;
157 web_puts((mode == '1') ? s : (mode == '2') ? (p + 1) : nv);
162 void asp_lipp(int argc, char **argv)
164 char *one = "1";
165 asp_lanip(1, &one);
168 // <% psup(process); %>
169 // returns 1 if process is running
171 void asp_psup(int argc, char **argv)
173 if (argc == 1) web_printf("%d", pidof(argv[0]) > 0);
177 # cat /proc/meminfo
178 total: used: free: shared: buffers: cached:
179 Mem: 14872576 12877824 1994752 0 1236992 4837376
180 Swap: 0 0 0
181 MemTotal: 14524 kB
182 MemFree: 1948 kB
183 MemShared: 0 kB
184 Buffers: 1208 kB
185 Cached: 4724 kB
186 SwapCached: 0 kB
187 Active: 4364 kB
188 Inactive: 2952 kB
189 HighTotal: 0 kB
190 HighFree: 0 kB
191 LowTotal: 14524 kB
192 LowFree: 1948 kB
193 SwapTotal: 0 kB
194 SwapFree: 0 kB
198 typedef struct {
199 unsigned long total;
200 unsigned long free;
201 unsigned long shared;
202 unsigned long buffers;
203 unsigned long cached;
204 unsigned long swaptotal;
205 unsigned long swapfree;
206 unsigned long maxfreeram;
207 } meminfo_t;
209 static int get_memory(meminfo_t *m)
211 FILE *f;
212 char s[128];
213 int ok = 0;
215 if ((f = fopen("/proc/meminfo", "r")) != NULL) {
216 while (fgets(s, sizeof(s), f)) {
217 if (strncmp(s, "Mem:", 4) == 0) {
218 if (sscanf(s + 6, "%ld %*d %ld %ld %ld %ld", &m->total, &m->free, &m->shared, &m->buffers, &m->cached) == 5)
219 ++ok;
221 else if (strncmp(s, "SwapTotal:", 10) == 0) {
222 m->swaptotal = strtoul(s + 12, NULL, 10) * 1024;
223 ++ok;
225 else if (strncmp(s, "SwapFree:", 9) == 0) {
226 m->swapfree = strtoul(s + 11, NULL, 10) * 1024;
227 ++ok;
228 break;
231 fclose(f);
233 if (ok != 3) {
234 memset(m, 0, sizeof(*m));
235 return 0;
237 m->maxfreeram = m->free;
238 if (nvram_match("t_cafree", "1")) m->maxfreeram += m->cached;
239 return 1;
242 void asp_sysinfo(int argc, char **argv)
244 struct sysinfo si;
245 char s[64];
246 meminfo_t mem;
248 web_puts("\nsysinfo = {\n");
249 sysinfo(&si);
250 get_memory(&mem);
251 web_printf(
252 "\tuptime: %ld,\n"
253 "\tuptime_s: '%s',\n"
254 "\tloads: [%ld, %ld, %ld],\n"
255 "\ttotalram: %ld,\n"
256 "\tfreeram: %ld,\n"
257 "\tshareram: %ld,\n"
258 "\tbufferram: %ld,\n"
259 "\tcached: %ld,\n"
260 "\ttotalswap: %ld,\n"
261 "\tfreeswap: %ld,\n"
262 "\ttotalfreeram: %ld,\n"
263 "\tprocs: %d\n",
264 si.uptime,
265 reltime(s, si.uptime),
266 si.loads[0], si.loads[1], si.loads[2],
267 mem.total, mem.free,
268 mem.shared, mem.buffers, mem.cached,
269 mem.swaptotal, mem.swapfree,
270 mem.maxfreeram,
271 si.procs);
272 web_puts("};\n");
275 void asp_activeroutes(int argc, char **argv)
277 FILE *f;
278 char s[512];
279 char dev[17];
280 unsigned long dest;
281 unsigned long gateway;
282 unsigned long flags;
283 unsigned long mask;
284 unsigned metric;
285 struct in_addr ia;
286 char s_dest[16];
287 char s_gateway[16];
288 char s_mask[16];
289 int n;
291 web_puts("\nactiveroutes = [");
292 n = 0;
293 if ((f = fopen("/proc/net/route", "r")) != NULL) {
294 while (fgets(s, sizeof(s), f)) {
295 if (sscanf(s, "%16s%lx%lx%lx%*s%*s%u%lx", dev, &dest, &gateway, &flags, &metric, &mask) != 6) continue;
296 if ((flags & RTF_UP) == 0) continue;
297 if (dest != 0) {
298 ia.s_addr = dest;
299 strcpy(s_dest, inet_ntoa(ia));
301 else {
302 strcpy(s_dest, "default");
304 if (gateway != 0) {
305 ia.s_addr = gateway;
306 strcpy(s_gateway, inet_ntoa(ia));
308 else {
309 strcpy(s_gateway, "*");
311 ia.s_addr = mask;
312 strcpy(s_mask, inet_ntoa(ia));
313 web_printf("%s['%s','%s','%s','%s',%u]", n ? "," : "", dev, s_dest, s_gateway, s_mask, metric);
314 ++n;
316 fclose(f);
318 web_puts("];\n");
321 void asp_cgi_get(int argc, char **argv)
323 const char *v;
324 int i;
326 for (i = 0; i < argc; ++i) {
327 v = webcgi_get(argv[i]);
328 if (v) web_puts(v);
332 void asp_time(int argc, char **argv)
334 time_t t;
335 char s[64];
337 t = time(NULL);
338 if (t < Y2K) {
339 web_puts("Not Available");
341 else {
342 strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
343 web_puts(s);
347 void asp_wanup(int argc, char **argv)
349 web_puts(check_wanup() ? "1" : "0");
352 void asp_wanstatus(int argc, char **argv)
354 const char *p;
356 if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
357 p = "Renewing...";
359 else if (check_wanup()) {
360 p = "Connected";
362 else if (f_exists("/var/lib/misc/wan.connecting")) {
363 p = "Connecting...";
365 else {
366 p = "Disconnected";
368 web_puts(p);
371 void asp_link_uptime(int argc, char **argv)
373 struct sysinfo si;
374 char buf[64];
375 long uptime;
377 buf[0] = '-';
378 buf[1] = 0;
379 if (check_wanup()) {
380 sysinfo(&si);
381 if (f_read("/var/lib/misc/wantime", &uptime, sizeof(uptime)) == sizeof(uptime)) {
382 reltime(buf, si.uptime - uptime);
385 web_puts(buf);
388 void asp_rrule(int argc, char **argv)
390 char s[32];
391 int i;
393 i = nvram_get_int("rruleN");
394 sprintf(s, "rrule%d", i);
395 web_puts("\nrrule = '");
396 web_putj(nvram_safe_get(s));
397 web_printf("';\nrruleN = %d;\n", i);
400 void asp_compmac(int argc, char **argv)
402 char mac[32];
403 char ifname[32];
405 if (get_client_info(mac, ifname)) {
406 web_puts(mac);
410 void asp_ident(int argc, char **argv)
412 web_puth(nvram_safe_get("router_name"));
415 void asp_statfs(int argc, char **argv)
417 struct statfs sf;
419 if (argc != 2) return;
421 // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted
422 if ((statfs(argv[0], &sf) != 0) || (sf.f_type == 0x73717368))
423 memset(&sf, 0, sizeof(sf));
425 web_printf(
426 "\n%s = {\n"
427 "\tsize: %llu,\n"
428 "\tfree: %llu\n"
429 "};\n",
430 argv[1],
431 ((uint64_t)sf.f_bsize * sf.f_blocks),
432 ((uint64_t)sf.f_bsize * sf.f_bfree));
435 void asp_notice(int argc, char **argv)
437 char s[256];
438 char buf[2048];
440 if (argc != 1) return;
441 snprintf(s, sizeof(s), "/var/notice/%s", argv[0]);
442 if (f_read_string(s, buf, sizeof(buf)) <= 0) return;
443 web_putj(buf);
446 void wo_wakeup(char *url)
448 char *mac;
449 char *p;
450 char *end;
452 if ((mac = webcgi_get("mac")) != NULL) {
453 end = mac + strlen(mac);
454 while (mac < end) {
455 while ((*mac == ' ') || (*mac == '\t') || (*mac == '\r') || (*mac == '\n')) ++mac;
456 if (*mac == 0) break;
458 p = mac;
459 while ((*p != 0) && (*p != ' ') && (*p != '\r') && (*p != '\n')) ++p;
460 *p = 0;
462 eval("ether-wake", "-i", nvram_safe_get("lan_ifname"), mac);
463 mac = p + 1;
466 common_redirect();
469 void asp_dns(int argc, char **argv)
471 char s[128];
472 int i;
473 const dns_list_t *dns;
475 dns = get_dns(); // static buffer
476 strcpy(s, "\ndns = [");
477 for (i = 0 ; i < dns->count; ++i) {
478 sprintf(s + strlen(s), "%s'%s:%u'", i ? "," : "", inet_ntoa(dns->dns[i].addr), dns->dns[i].port);
480 strcat(s, "];\n");
481 web_puts(s);
484 void wo_resolve(char *url)
486 char *p;
487 char *ip;
488 struct hostent *he;
489 struct in_addr ia;
490 char comma;
491 char *js;
493 comma = ' ';
494 web_puts("\nresolve_data = [\n");
495 if ((p = webcgi_get("ip")) != NULL) {
496 while ((ip = strsep(&p, ",")) != NULL) {
497 ia.s_addr = inet_addr(ip);
498 he = gethostbyaddr(&ia, sizeof(ia), AF_INET);
499 js = js_string(he ? he->h_name : "");
500 web_printf("%c['%s','%s']", comma, inet_ntoa(ia), js);
501 free(js);
502 comma = ',';
505 web_puts("];\n");
509 #ifdef TCONFIG_USB
511 //!!TB - USB support
513 #define PROC_SCSI_ROOT "/proc/scsi"
514 #define USB_STORAGE "usb-storage"
516 /* this value should not match any of the existing EFH_ values in shared.h */
517 #define EFH_PRINT 0x00000080 /* output partition list to the web response */
519 int is_partition_mounted(char *dev_name, int host_num, int disc_num, int part_num, uint flags)
521 char the_label[128];
522 char *type;
523 int is_mounted = 0;
524 struct mntent *mnt;
525 struct statfs s;
526 unsigned long psize = 0;
528 if (!find_label_or_uuid(dev_name, the_label, NULL)) {
529 sprintf(the_label, "disc%d_%d", disc_num, part_num);
532 if (flags & EFH_PRINT) {
533 if (flags & EFH_1ST_DISC) {
534 // [disc_no, [partitions array]],...
535 web_printf("]],[%d,[", disc_num);
537 // [partition_name, is_mounted, mount_point, type, opts, size],...
538 web_printf("%s['%s',", (flags & EFH_1ST_DISC) ? "" : ",", the_label);
541 if ((mnt = findmntents(dev_name, 0, 0, 0))) {
542 is_mounted = 1;
543 if (flags & EFH_PRINT) {
544 if (statfs(mnt->mnt_dir, &s) == 0) {
545 psize = (s.f_blocks * (unsigned long long) s.f_bsize + 1024*1024/2) / (1024*1024);
547 web_printf("1,'%s','%s','%s','%ld']",
548 mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, psize);
551 else if ((mnt = findmntents(dev_name, 1, 0, 0))) {
552 is_mounted = 1;
553 if (flags & EFH_PRINT) {
554 web_printf("2,'','%s','','%ld']",
555 "swap", (atoi(mnt->mnt_type) + 1023) / 1024);
558 else {
559 if (flags & EFH_PRINT) {
560 type = detect_fs_type(dev_name);
561 web_printf("0,'','%s','','0']", type ? type : "");
565 return is_mounted;
568 int is_host_mounted(int host_no, int print_parts)
570 if (print_parts) web_puts("[-1,[");
572 int fd = nvram_get_int("usb_nolock") ? -1 : file_lock("usb");
573 int mounted = exec_for_host(
574 host_no,
575 0x00,
576 print_parts ? EFH_PRINT : 0,
577 is_partition_mounted);
578 file_unlock(fd);
580 if (print_parts) web_puts("]]");
582 return mounted;
586 * The disc # doesn't correspond to the host#, since there may be more than
587 * one partition on a disk.
588 * Nor does either correspond to the scsi host number.
589 * And if the user plugs or unplugs a usb storage device after bringing up the
590 * NAS:USB support page, the numbers won't match anymore, since "part#"s
591 * may be added or deleted to the /dev/discs* or /dev/scsi**.
593 * But since we only need to support the devices list and mount/unmount
594 * functionality on the host level, the host# shoudl work ok. Just make sure
595 * to always pass and use the _host#_, and not the disc#.
597 void asp_usbdevices(int argc, char **argv)
599 DIR *scsi_dir=NULL, *usb_dir=NULL;
600 struct dirent *dp, *scsi_dirent;
601 uint host_no;
602 int i = 0, attached, mounted;
603 FILE *fp;
604 char line[128];
605 char *tmp=NULL, g_usb_vendor[30], g_usb_product[30], g_usb_serial[30];
607 web_puts("\nusbdev = [");
609 if (!nvram_match("usb_enable", "1")) {
610 web_puts("];\n");
611 return;
614 /* find all attached USB storage devices */
615 scsi_dir = opendir(PROC_SCSI_ROOT);
616 while (scsi_dir && (scsi_dirent = readdir(scsi_dir)))
618 if (!strncmp(USB_STORAGE, scsi_dirent->d_name, strlen(USB_STORAGE)))
620 sprintf(line, "%s/%s", PROC_SCSI_ROOT, scsi_dirent->d_name);
621 usb_dir = opendir(line);
622 while (usb_dir && (dp = readdir(usb_dir)))
624 if (!strcmp(dp->d_name, "..") || !strcmp(dp->d_name, "."))
625 continue;
626 sprintf(line, "%s/%s/%s", PROC_SCSI_ROOT, scsi_dirent->d_name, dp->d_name);
628 fp = fopen(line, "r");
629 if (fp) {
630 attached = 0;
631 g_usb_vendor[0] = 0;
632 g_usb_product[0] = 0;
633 g_usb_serial[0] = 0;
634 tmp = NULL;
636 while (fgets(line, sizeof(line), fp) != NULL) {
637 if (strstr(line, "Attached: Yes")) {
638 attached = 1;
640 else if (strstr(line, "Vendor")) {
641 tmp = strtok(line, " ");
642 tmp = strtok(NULL, "\n");
643 strncpy(g_usb_vendor, tmp, sizeof(g_usb_vendor) - 1);
644 tmp = NULL;
646 else if (strstr(line, "Product")) {
647 tmp = strtok(line, " ");
648 tmp = strtok(NULL, "\n");
649 strncpy(g_usb_product, tmp, sizeof(g_usb_product) - 1);
650 tmp = NULL;
652 else if (strstr(line, "Serial Number")) {
653 tmp = strtok(line, " ");
654 tmp = strtok(NULL, " ");
655 tmp = strtok(NULL, "\n");
656 strncpy(g_usb_serial, tmp, sizeof(g_usb_serial) - 1);
657 tmp = NULL;
660 fclose(fp);
661 if (attached) {
662 /* Host no. assigned by scsi driver for this UFD */
663 host_no = atoi(dp->d_name);
664 web_printf("%s['Storage','%d','%s','%s','%s', [", i ? "," : "",
665 host_no, g_usb_vendor, g_usb_product, g_usb_serial);
666 mounted = is_host_mounted(host_no, 1);
667 web_printf("], %d]", mounted);
668 ++i;
673 if (usb_dir)
674 closedir(usb_dir);
677 if (scsi_dir)
678 closedir(scsi_dir);
680 /* now look for printers */
681 usb_dir = opendir("/proc/usblp");
682 while (usb_dir && (dp = readdir(usb_dir)))
684 if (!strcmp(dp->d_name, "..") || !strcmp(dp->d_name, "."))
685 continue;
688 sprintf(line, "/dev/usb/%s", dp->d_name);
689 if (!f_exists(line))
690 continue;
692 sprintf(line, "/proc/usblp/%s", dp->d_name);
693 if ((fp = fopen(line, "r"))) {
694 g_usb_vendor[0] = 0;
695 g_usb_product[0] = 0;
696 tmp = NULL;
698 while (fgets(line, sizeof(line), fp) != NULL) {
699 if (strstr(line, "Manufacturer")) {
700 tmp = strtok(line, "=");
701 tmp = strtok(NULL, "\n");
702 strncpy(g_usb_vendor, tmp, sizeof(g_usb_vendor) - 1);
703 tmp = NULL;
705 else if (strstr(line, "Model")) {
706 tmp = strtok(line, "=");
707 tmp = strtok(NULL, "\n");
708 strncpy(g_usb_product, tmp, sizeof(g_usb_product) - 1);
709 tmp = NULL;
712 if ((strlen(g_usb_product) > 0) || (strlen(g_usb_vendor) > 0)) {
713 web_printf("%s['Printer','%s','%s','%s','']", i ? "," : "",
714 dp->d_name, g_usb_vendor, g_usb_product);
715 ++i;
718 fclose(fp);
721 if (usb_dir)
722 closedir(usb_dir);
724 web_puts("];\n");
727 void wo_usbcommand(char *url)
729 char *p;
730 int add = 0;
732 web_puts("\nusb = [\n");
733 if ((p = webcgi_get("remove")) != NULL) {
734 add = 0;
736 else if ((p = webcgi_get("mount")) != NULL) {
737 add = 1;
739 if (p) {
740 add_remove_usbhost(p, add);
741 web_printf("%d", is_host_mounted(atoi(p), 0));
743 web_puts("];\n");
746 #endif // TCONFIG_USB