4 Copyright (C) 2006-2009 Jonathan Zarate
11 #include <sys/sysinfo.h>
13 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <sys/types.h>
22 #include <sys/statfs.h>
24 #include <net/route.h>
27 //#include <sys/mount.h>
33 // to javascript-safe string
34 char *js_string(const char *s
)
40 if ((buffer
= malloc((strlen(s
) * 4) + 1)) != NULL
) {
42 while ((c
= *s
++) != 0) {
43 if ((c
== '"') || (c
== '\'') || (c
== '\\') || (!isprint(c
))) {
44 b
+= sprintf(b
, "\\x%02x", c
);
55 // to html-safe string
56 char *html_string(const char *s
)
62 if ((buffer
= malloc((strlen(s
) * 6) + 1)) != NULL
) {
64 while ((c
= *s
++) != 0) {
65 if ((c
== '&') || (c
== '<') || (c
== '>') || (c
== '"') || (c
== '\'') || (!isprint(c
))) {
66 b
+= sprintf(b
, "&#%d;", c
);
78 char *unix_string(const char *s
)
84 if ((buffer
= malloc(strlen(s
) + 1)) != NULL
) {
86 while ((c
= *s
++) != 0)
87 if (c
!= '\r') *b
++ = c
;
94 char *reltime(char *buf
, time_t t
)
102 sprintf(buf
, "%d day%s, %02d:%02d:%02d", days
, ((days
==1) ? "" : "s"), ((m
/ 60) % 24), (m
% 60), (int)(t
% 60));
106 int get_client_info(char *mac
, char *ifname
)
114 IP address HW type Flags HW address Mask Device
115 192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1
116 192.168.1.5 0x1 0x2 00:05:06:07:08:09 * br0
119 if ((f
= fopen("/proc/net/arp", "r")) != NULL
) {
120 while (fgets(s
, sizeof(s
), f
)) {
121 if (sscanf(s
, "%15s %*s %*s %17s %*s %16s", ips
, mac
, ifname
) == 3) {
122 if (inet_addr(ips
) == clientsai
.sin_addr
.s_addr
) {
137 // <% lanip(mode); %>
139 // 1 return first 3 octets (192.168.1)
140 // 2 return last octet (1)
141 // else return full (192.168.1.1)
143 void asp_lanip(int argc
, char **argv
)
149 mode
= argc
? *argv
[0] : 0;
151 if ((nv
= nvram_get("lan_ipaddr")) != NULL
) {
153 if ((p
= strrchr(s
, '.')) != NULL
) {
155 web_puts((mode
== '1') ? s
: (mode
== '2') ? (p
+ 1) : nv
);
160 void asp_lipp(int argc
, char **argv
)
166 // <% psup(process); %>
167 // returns 1 if process is running
169 void asp_psup(int argc
, char **argv
)
171 if (argc
== 1) web_printf("%d", pidof(argv
[0]) > 0);
176 total: used: free: shared: buffers: cached:
177 Mem: 14872576 12877824 1994752 0 1236992 4837376
199 unsigned long shared
;
200 unsigned long buffers
;
201 unsigned long cached
;
202 unsigned long swaptotal
;
203 unsigned long swapfree
;
204 unsigned long maxfreeram
;
207 static int get_memory(meminfo_t
*m
)
213 if ((f
= fopen("/proc/meminfo", "r")) != NULL
) {
214 while (fgets(s
, sizeof(s
), f
)) {
215 if (strncmp(s
, "Mem:", 4) == 0) {
216 if (sscanf(s
+ 6, "%ld %*d %ld %ld %ld %ld", &m
->total
, &m
->free
, &m
->shared
, &m
->buffers
, &m
->cached
) == 5)
219 else if (strncmp(s
, "SwapTotal:", 10) == 0) {
220 m
->swaptotal
= strtoul(s
+ 12, NULL
, 10) * 1024;
223 else if (strncmp(s
, "SwapFree:", 9) == 0) {
224 m
->swapfree
= strtoul(s
+ 11, NULL
, 10) * 1024;
232 memset(m
, 0, sizeof(*m
));
235 m
->maxfreeram
= m
->free
;
236 if (nvram_match("t_cafree", "1")) m
->maxfreeram
+= m
->cached
;
240 void asp_sysinfo(int argc
, char **argv
)
246 web_puts("\nsysinfo = {\n");
251 "\tuptime_s: '%s',\n"
252 "\tloads: [%ld, %ld, %ld],\n"
256 "\tbufferram: %ld,\n"
258 "\ttotalswap: %ld,\n"
260 "\ttotalfreeram: %ld,\n"
263 reltime(s
, si
.uptime
),
264 si
.loads
[0], si
.loads
[1], si
.loads
[2],
266 mem
.shared
, mem
.buffers
, mem
.cached
,
267 mem
.swaptotal
, mem
.swapfree
,
273 void asp_activeroutes(int argc
, char **argv
)
279 unsigned long gateway
;
289 web_puts("\nactiveroutes = [");
291 if ((f
= fopen("/proc/net/route", "r")) != NULL
) {
292 while (fgets(s
, sizeof(s
), f
)) {
293 if (sscanf(s
, "%16s%lx%lx%lx%*s%*s%u%lx", dev
, &dest
, &gateway
, &flags
, &metric
, &mask
) != 6) continue;
294 if ((flags
& RTF_UP
) == 0) continue;
297 strcpy(s_dest
, inet_ntoa(ia
));
300 strcpy(s_dest
, "default");
304 strcpy(s_gateway
, inet_ntoa(ia
));
307 strcpy(s_gateway
, "*");
310 strcpy(s_mask
, inet_ntoa(ia
));
311 web_printf("%s['%s','%s','%s','%s',%u]", n
? "," : "", dev
, s_dest
, s_gateway
, s_mask
, metric
);
319 void asp_cgi_get(int argc
, char **argv
)
324 for (i
= 0; i
< argc
; ++i
) {
325 v
= webcgi_get(argv
[i
]);
330 void asp_time(int argc
, char **argv
)
337 web_puts("Not Available");
340 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&t
));
345 void asp_wanup(int argc
, char **argv
)
347 web_puts(check_wanup() ? "1" : "0");
350 void asp_wanstatus(int argc
, char **argv
)
354 if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
357 else if (check_wanup()) {
360 else if (f_exists("/var/lib/misc/wan.connecting")) {
369 void asp_link_uptime(int argc
, char **argv
)
379 if (f_read("/var/lib/misc/wantime", &uptime
, sizeof(uptime
)) == sizeof(uptime
)) {
380 reltime(buf
, si
.uptime
- uptime
);
386 void asp_bandwidth(int argc
, char **argv
)
391 if ((nvram_match("rstats_enable", "1")) && (argc
== 1)) {
392 if (strcmp(argv
[0], "speed") == 0) {
394 name
= "/var/spool/rstats-speed.js";
398 name
= "/var/spool/rstats-history.js";
401 killall("rstats", sig
);
402 f_wait_exists(name
, 5);
408 void asp_rrule(int argc
, char **argv
)
413 i
= nvram_get_int("rruleN");
414 sprintf(s
, "rrule%d", i
);
415 web_puts("\nrrule = '");
416 web_putj(nvram_safe_get(s
));
417 web_printf("';\nrruleN = %d;\n", i
);
420 void asp_compmac(int argc
, char **argv
)
425 if (get_client_info(mac
, ifname
)) {
430 void asp_ident(int argc
, char **argv
)
432 web_puth(nvram_safe_get("router_name"));
435 void asp_statfs(int argc
, char **argv
)
439 if (argc
!= 2) return;
441 // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted
442 if ((statfs(argv
[0], &sf
) != 0) || (sf
.f_type
== 0x73717368))
443 memset(&sf
, 0, sizeof(sf
));
451 ((uint64_t)sf
.f_bsize
* sf
.f_blocks
),
452 ((uint64_t)sf
.f_bsize
* sf
.f_bfree
));
455 void asp_notice(int argc
, char **argv
)
460 if (argc
!= 1) return;
461 snprintf(s
, sizeof(s
), "/var/notice/%s", argv
[0]);
462 if (f_read_string(s
, buf
, sizeof(buf
)) <= 0) return;
466 void wo_wakeup(char *url
)
472 if ((mac
= webcgi_get("mac")) != NULL
) {
473 end
= mac
+ strlen(mac
);
475 while ((*mac
== ' ') || (*mac
== '\t') || (*mac
== '\r') || (*mac
== '\n')) ++mac
;
476 if (*mac
== 0) break;
479 while ((*p
!= 0) && (*p
!= ' ') && (*p
!= '\r') && (*p
!= '\n')) ++p
;
482 eval("ether-wake", "-i", nvram_safe_get("lan_ifname"), mac
);
489 void asp_dns(int argc
, char **argv
)
493 const dns_list_t
*dns
;
495 dns
= get_dns(); // static buffer
496 strcpy(s
, "\ndns = [");
497 for (i
= 0 ; i
< dns
->count
; ++i
) {
498 sprintf(s
+ strlen(s
), "%s'%s'", i
? "," : "", inet_ntoa(dns
->dns
[i
]));
504 void wo_resolve(char *url
)
514 web_puts("\nresolve_data = [\n");
515 if ((p
= webcgi_get("ip")) != NULL
) {
516 while ((ip
= strsep(&p
, ",")) != NULL
) {
517 ia
.s_addr
= inet_addr(ip
);
518 he
= gethostbyaddr(&ia
, sizeof(ia
), AF_INET
);
519 js
= js_string(he
? he
->h_name
: "");
520 web_printf("%c['%s','%s']", comma
, inet_ntoa(ia
), js
);
531 #define PROC_SCSI_ROOT "/proc/scsi"
532 #define USB_STORAGE "usb-storage"
534 /* this value should not match any of the existing EFH_ values in shared.h */
535 #define EFH_PRINT 0x00000080 /* output partition list to the web response */
537 int is_partition_mounted(char *dev_name
, int host_num
, int disc_num
, int part_num
, uint flags
)
544 unsigned long psize
= 0;
546 if (!find_label(dev_name
, the_label
)) {
547 sprintf(the_label
, "disc%d_%d", disc_num
, part_num
);
550 if (flags
& EFH_PRINT
) {
551 if (flags
& EFH_1ST_DISC
) {
552 // [disc_no, [partitions array]],...
553 web_printf("]],[%d,[", disc_num
);
555 // [partition_name, is_mounted, mount_point, type, opts, size],...
556 web_printf("%s['%s',", (flags
& EFH_1ST_DISC
) ? "" : ",", the_label
);
559 if (mnt
= findmntents(dev_name
, 0, 0, 0)) {
561 if (flags
& EFH_PRINT
) {
562 if (statfs(mnt
->mnt_dir
, &s
) == 0) {
563 psize
= (s
.f_blocks
* (unsigned long long) s
.f_bsize
+ 1024*1024/2) / (1024*1024);
565 web_printf("1,'%s','%s','%s','%ld']",
566 mnt
->mnt_dir
, mnt
->mnt_type
, mnt
->mnt_opts
, psize
);
569 else if (mnt
= findmntents(dev_name
, 1, 0, 0)) {
571 if (flags
& EFH_PRINT
) {
572 web_printf("2,'','%s','','%ld']",
573 "swap", (atoi(mnt
->mnt_type
) + 1023) / 1024);
577 if (flags
& EFH_PRINT
) {
578 type
= detect_fs_type(dev_name
);
579 web_printf("0,'','%s','','0']", type
? type
: "");
586 int is_host_mounted(int host_no
, int print_parts
)
588 if (print_parts
) web_puts("[-1,[");
591 int mounted
= exec_for_host(
594 print_parts
? EFH_PRINT
: 0,
595 is_partition_mounted
);
598 if (print_parts
) web_puts("]]");
604 * The disc # doesn't correspond to the host#, since there may be more than
605 * one partition on a disk.
606 * Nor does either correspond to the scsi host number.
607 * And if the user plugs or unplugs a usb storage device after bringing up the
608 * NAS:USB support page, the numbers won't match anymore, since "part#"s
609 * may be added or deleted to the /dev/discs* or /dev/scsi**.
611 * But since we only need to support the devices list and mount/unmount
612 * functionality on the host level, the host# shoudl work ok. Just make sure
613 * to always pass and use the _host#_, and not the disc#.
615 void asp_usbdevices(int argc
, char **argv
)
617 DIR *scsi_dir
=NULL
, *usb_dir
=NULL
;
618 struct dirent
*dp
, *scsi_dirent
;
620 int i
= 0, attached
, mounted
;
623 char *tmp
=NULL
, g_usb_vendor
[25], g_usb_product
[20], g_usb_serial
[20];
625 web_puts("\nusbdev = [");
627 if (!nvram_match("usb_enable", "1")) {
632 /* find all attached USB storage devices */
633 scsi_dir
= opendir(PROC_SCSI_ROOT
);
634 while (scsi_dir
&& (scsi_dirent
= readdir(scsi_dir
)))
636 if (!strncmp(USB_STORAGE
, scsi_dirent
->d_name
, strlen(USB_STORAGE
)))
638 sprintf(line
, "%s/%s", PROC_SCSI_ROOT
, scsi_dirent
->d_name
);
639 usb_dir
= opendir(line
);
640 while (usb_dir
&& (dp
= readdir(usb_dir
)))
642 if (!strcmp(dp
->d_name
, "..") || !strcmp(dp
->d_name
, "."))
644 sprintf(line
, "%s/%s/%s", PROC_SCSI_ROOT
, scsi_dirent
->d_name
, dp
->d_name
);
646 fp
= fopen(line
, "r");
650 g_usb_product
[0] = 0;
654 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
655 if (strstr(line
, "Attached: Yes")) {
658 else if (strstr(line
, "Vendor")) {
659 tmp
= strtok(line
, " ");
660 tmp
= strtok(NULL
, "\n");
661 strcpy(g_usb_vendor
, tmp
);
664 else if (strstr(line
, "Product")) {
665 tmp
= strtok(line
, " ");
666 tmp
= strtok(NULL
, "\n");
667 strcpy(g_usb_product
, tmp
);
670 else if (strstr(line
, "Serial Number")) {
671 tmp
= strtok(line
, " ");
672 tmp
= strtok(NULL
, " ");
673 tmp
= strtok(NULL
, "\n");
674 strcpy(g_usb_serial
, tmp
);
680 /* Host no. assigned by scsi driver for this UFD */
681 host_no
= atoi(dp
->d_name
);
682 web_printf("%s['Storage','%d','%s','%s','%s', [", i
? "," : "",
683 host_no
, g_usb_vendor
, g_usb_product
, g_usb_serial
);
684 mounted
= is_host_mounted(host_no
, 1);
685 web_printf("], %d]", mounted
);
698 /* now look for printers */
699 usb_dir
= opendir("/proc/usblp");
700 while (usb_dir
&& (dp
= readdir(usb_dir
)))
702 if (!strcmp(dp
->d_name
, "..") || !strcmp(dp
->d_name
, "."))
706 sprintf(line, "/dev/usb/%s", dp->d_name);
710 sprintf(line
, "/proc/usblp/%s", dp
->d_name
);
711 if ((fp
= fopen(line
, "r"))) {
713 g_usb_product
[0] = 0;
716 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
717 if (strstr(line
, "Manufacturer")) {
718 tmp
= strtok(line
, "=");
719 tmp
= strtok(NULL
, "\n");
720 strcpy(g_usb_vendor
, tmp
);
723 else if (strstr(line
, "Model")) {
724 tmp
= strtok(line
, "=");
725 tmp
= strtok(NULL
, "\n");
726 strcpy(g_usb_product
, tmp
);
730 if ((strlen(g_usb_product
) > 0) || (strlen(g_usb_vendor
) > 0)) {
731 web_printf("%s['Printer','%s','%s','%s','']", i
? "," : "",
732 dp
->d_name
, g_usb_vendor
, g_usb_product
);
745 //#define SAME_AS_KERNEL
747 /* Simulate a hotplug event, as if a USB storage device
748 * got plugged or unplugged.
749 * Either use a hardcoded program name, or the same
750 * hotplug program that the kernel uses for a real event.
752 void wo_usbcommand(char *url
)
756 #ifdef SAME_AS_KERNEL
757 char pgm
[256] = "/sbin/hotplug usb";
758 int fd
= open("/proc/sys/kernel/hotplug", O_RDONLY
);
760 if (read(fd
, pgm
, sizeof(pgm
) - 5) >= 0) {
761 if ((p
= strchr(pgm
, '\n')) != NULL
)
768 // don't use value from /proc/sys/kernel/hotplug
769 // since it may be overriden by a user.
770 const char pgm
[] = "/sbin/hotplug usb";
773 web_puts("\nusb = [\n");
774 if ((p
= webcgi_get("remove")) != NULL
) {
775 setenv("ACTION", "remove", 1);
777 else if ((p
= webcgi_get("mount")) != NULL
) {
778 setenv("ACTION", "add", 1);
781 setenv("SCSI_HOST", p
, 1);
782 setenv("PRODUCT", p
, 1);
783 setenv("INTERFACE", "TOMATO/0", 1);
785 unsetenv("INTERFACE");
787 unsetenv("SCSI_HOST");
789 web_printf("%d", is_host_mounted(atoi(p
), 0));