Turn off the swap on unmounting; unmount ALL mountpoints; show swap active status...
[tomato.git] / release / src / router / httpd / misc.c
blob7c87ddd21f1af6ed22d099ece078d9f826ac1ccc
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 //#include <sys/mount.h>
28 #include <mntent.h>
30 #include <wlioctl.h>
31 #include <wlutils.h>
33 // to javascript-safe string
34 char *js_string(const char *s)
36 unsigned char c;
37 char *buffer;
38 char *b;
40 if ((buffer = malloc((strlen(s) * 4) + 1)) != NULL) {
41 b = buffer;
42 while ((c = *s++) != 0) {
43 if ((c == '"') || (c == '\'') || (c == '\\') || (!isprint(c))) {
44 b += sprintf(b, "\\x%02x", c);
46 else {
47 *b++ = c;
50 *b = 0;
52 return buffer;
55 // to html-safe string
56 char *html_string(const char *s)
58 unsigned char c;
59 char *buffer;
60 char *b;
62 if ((buffer = malloc((strlen(s) * 6) + 1)) != NULL) {
63 b = buffer;
64 while ((c = *s++) != 0) {
65 if ((c == '&') || (c == '<') || (c == '>') || (c == '"') || (c == '\'') || (!isprint(c))) {
66 b += sprintf(b, "&#%d;", c);
68 else {
69 *b++ = c;
72 *b = 0;
74 return buffer;
77 // removes \r
78 char *unix_string(const char *s)
80 char *buffer;
81 char *b;
82 char c;
84 if ((buffer = malloc(strlen(s) + 1)) != NULL) {
85 b = buffer;
86 while ((c = *s++) != 0)
87 if (c != '\r') *b++ = c;
88 *b = 0;
90 return buffer;
93 // # days, ##:##:##
94 char *reltime(char *buf, time_t t)
96 int days;
97 int m;
99 if (t < 0) t = 0;
100 days = t / 86400;
101 m = t / 60;
102 sprintf(buf, "%d day%s, %02d:%02d:%02d", days, ((days==1) ? "" : "s"), ((m / 60) % 24), (m % 60), (int)(t % 60));
103 return buf;
106 int get_client_info(char *mac, char *ifname)
108 FILE *f;
109 char s[256];
110 char ips[16];
113 # cat /proc/net/arp
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) {
123 fclose(f);
124 return 1;
128 fclose(f);
130 return 0;
137 // <% lanip(mode); %>
138 // <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)
145 char *nv, *p;
146 char s[64];
147 char mode;
149 mode = argc ? *argv[0] : 0;
151 if ((nv = nvram_get("lan_ipaddr")) != NULL) {
152 strcpy(s, nv);
153 if ((p = strrchr(s, '.')) != NULL) {
154 *p = 0;
155 web_puts((mode == '1') ? s : (mode == '2') ? (p + 1) : nv);
160 void asp_lipp(int argc, char **argv)
162 char *one = "1";
163 asp_lanip(1, &one);
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);
175 # cat /proc/meminfo
176 total: used: free: shared: buffers: cached:
177 Mem: 14872576 12877824 1994752 0 1236992 4837376
178 Swap: 0 0 0
179 MemTotal: 14524 kB
180 MemFree: 1948 kB
181 MemShared: 0 kB
182 Buffers: 1208 kB
183 Cached: 4724 kB
184 SwapCached: 0 kB
185 Active: 4364 kB
186 Inactive: 2952 kB
187 HighTotal: 0 kB
188 HighFree: 0 kB
189 LowTotal: 14524 kB
190 LowFree: 1948 kB
191 SwapTotal: 0 kB
192 SwapFree: 0 kB
196 typedef struct {
197 unsigned long total;
198 unsigned long free;
199 unsigned long shared;
200 unsigned long buffers;
201 unsigned long cached;
202 unsigned long swaptotal;
203 unsigned long swapfree;
204 unsigned long maxfreeram;
205 } meminfo_t;
207 static int get_memory(meminfo_t *m)
209 FILE *f;
210 char s[128];
211 int ok = 0;
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)
217 ++ok;
219 else if (strncmp(s, "SwapTotal:", 10) == 0) {
220 m->swaptotal = strtoul(s + 12, NULL, 10) * 1024;
221 ++ok;
223 else if (strncmp(s, "SwapFree:", 9) == 0) {
224 m->swapfree = strtoul(s + 11, NULL, 10) * 1024;
225 ++ok;
226 break;
229 fclose(f);
231 if (ok != 3) {
232 memset(m, 0, sizeof(*m));
233 return 0;
235 m->maxfreeram = m->free;
236 if (nvram_match("t_cafree", "1")) m->maxfreeram += m->cached;
237 return 1;
240 void asp_sysinfo(int argc, char **argv)
242 struct sysinfo si;
243 char s[64];
244 meminfo_t mem;
246 web_puts("\nsysinfo = {\n");
247 sysinfo(&si);
248 get_memory(&mem);
249 web_printf(
250 "\tuptime: %ld,\n"
251 "\tuptime_s: '%s',\n"
252 "\tloads: [%ld, %ld, %ld],\n"
253 "\ttotalram: %ld,\n"
254 "\tfreeram: %ld,\n"
255 "\tshareram: %ld,\n"
256 "\tbufferram: %ld,\n"
257 "\tcached: %ld,\n"
258 "\ttotalswap: %ld,\n"
259 "\tfreeswap: %ld,\n"
260 "\ttotalfreeram: %ld,\n"
261 "\tprocs: %d\n",
262 si.uptime,
263 reltime(s, si.uptime),
264 si.loads[0], si.loads[1], si.loads[2],
265 mem.total, mem.free,
266 mem.shared, mem.buffers, mem.cached,
267 mem.swaptotal, mem.swapfree,
268 mem.maxfreeram,
269 si.procs);
270 web_puts("};\n");
273 void asp_activeroutes(int argc, char **argv)
275 FILE *f;
276 char s[512];
277 char dev[17];
278 unsigned long dest;
279 unsigned long gateway;
280 unsigned long flags;
281 unsigned long mask;
282 unsigned metric;
283 struct in_addr ia;
284 char s_dest[16];
285 char s_gateway[16];
286 char s_mask[16];
287 int n;
289 web_puts("\nactiveroutes = [");
290 n = 0;
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;
295 if (dest != 0) {
296 ia.s_addr = dest;
297 strcpy(s_dest, inet_ntoa(ia));
299 else {
300 strcpy(s_dest, "default");
302 if (gateway != 0) {
303 ia.s_addr = gateway;
304 strcpy(s_gateway, inet_ntoa(ia));
306 else {
307 strcpy(s_gateway, "*");
309 ia.s_addr = mask;
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);
312 ++n;
314 fclose(f);
316 web_puts("];\n");
319 void asp_cgi_get(int argc, char **argv)
321 const char *v;
322 int i;
324 for (i = 0; i < argc; ++i) {
325 v = webcgi_get(argv[i]);
326 if (v) web_puts(v);
330 void asp_time(int argc, char **argv)
332 time_t t;
333 char s[64];
335 t = time(NULL);
336 if (t < Y2K) {
337 web_puts("Not Available");
339 else {
340 strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
341 web_puts(s);
345 void asp_wanup(int argc, char **argv)
347 web_puts(check_wanup() ? "1" : "0");
350 void asp_wanstatus(int argc, char **argv)
352 const char *p;
354 if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
355 p = "Renewing...";
357 else if (check_wanup()) {
358 p = "Connected";
360 else if (f_exists("/var/lib/misc/wan.connecting")) {
361 p = "Connecting...";
363 else {
364 p = "Disconnected";
366 web_puts(p);
369 void asp_link_uptime(int argc, char **argv)
371 struct sysinfo si;
372 char buf[64];
373 long uptime;
375 buf[0] = '-';
376 buf[1] = 0;
377 if (check_wanup()) {
378 sysinfo(&si);
379 if (f_read("/var/lib/misc/wantime", &uptime, sizeof(uptime)) == sizeof(uptime)) {
380 reltime(buf, si.uptime - uptime);
383 web_puts(buf);
386 void asp_bandwidth(int argc, char **argv)
388 char *name;
389 int sig;
391 if ((nvram_match("rstats_enable", "1")) && (argc == 1)) {
392 if (strcmp(argv[0], "speed") == 0) {
393 sig = SIGUSR1;
394 name = "/var/spool/rstats-speed.js";
396 else {
397 sig = SIGUSR2;
398 name = "/var/spool/rstats-history.js";
400 unlink(name);
401 killall("rstats", sig);
402 f_wait_exists(name, 5);
403 do_file(name);
404 unlink(name);
408 void asp_rrule(int argc, char **argv)
410 char s[32];
411 int i;
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)
422 char mac[32];
423 char ifname[32];
425 if (get_client_info(mac, ifname)) {
426 web_puts(mac);
430 void asp_ident(int argc, char **argv)
432 web_puth(nvram_safe_get("router_name"));
435 void asp_statfs(int argc, char **argv)
437 struct statfs sf;
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));
445 web_printf(
446 "\n%s = {\n"
447 "\tsize: %llu,\n"
448 "\tfree: %llu\n"
449 "};\n",
450 argv[1],
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)
457 char s[256];
458 char buf[2048];
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;
463 web_putj(buf);
466 void wo_wakeup(char *url)
468 char *mac;
469 char *p;
470 char *end;
472 if ((mac = webcgi_get("mac")) != NULL) {
473 end = mac + strlen(mac);
474 while (mac < end) {
475 while ((*mac == ' ') || (*mac == '\t') || (*mac == '\r') || (*mac == '\n')) ++mac;
476 if (*mac == 0) break;
478 p = mac;
479 while ((*p != 0) && (*p != ' ') && (*p != '\r') && (*p != '\n')) ++p;
480 *p = 0;
482 eval("ether-wake", "-i", nvram_safe_get("lan_ifname"), mac);
483 mac = p + 1;
486 common_redirect();
489 void asp_dns(int argc, char **argv)
491 char s[128];
492 int i;
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]));
500 strcat(s, "];\n");
501 web_puts(s);
504 void wo_resolve(char *url)
506 char *p;
507 char *ip;
508 struct hostent *he;
509 struct in_addr ia;
510 char comma;
511 char *js;
513 comma = ' ';
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);
521 free(js);
522 comma = ',';
525 web_puts("];\n");
529 //!!TB - USB support
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)
539 char the_label[128];
540 char *type;
541 int is_mounted = 0;
542 struct mntent *mnt;
543 struct statfs s;
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)) {
560 is_mounted = 1;
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)) {
570 is_mounted = 1;
571 if (flags & EFH_PRINT) {
572 web_printf("2,'','%s','','%ld']",
573 "swap", (atoi(mnt->mnt_type) + 1023) / 1024);
576 else {
577 if (flags & EFH_PRINT) {
578 type = detect_fs_type(dev_name);
579 web_printf("0,'','%s','','0']", type ? type : "");
583 return is_mounted;
586 int is_host_mounted(int host_no, int print_parts)
588 if (print_parts) web_puts("[-1,[");
590 int fd = usb_lock();
591 int mounted = exec_for_host(
592 host_no,
593 0x00,
594 print_parts ? EFH_PRINT : 0,
595 is_partition_mounted);
596 usb_unlock(fd);
598 if (print_parts) web_puts("]]");
600 return mounted;
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;
619 uint host_no;
620 int i = 0, attached, mounted;
621 FILE *fp;
622 char line[128];
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")) {
628 web_puts("];\n");
629 return;
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, "."))
643 continue;
644 sprintf(line, "%s/%s/%s", PROC_SCSI_ROOT, scsi_dirent->d_name, dp->d_name);
646 fp = fopen(line, "r");
647 if (fp) {
648 attached = 0;
649 g_usb_vendor[0] = 0;
650 g_usb_product[0] = 0;
651 g_usb_serial[0] = 0;
652 tmp = NULL;
654 while (fgets(line, sizeof(line), fp) != NULL) {
655 if (strstr(line, "Attached: Yes")) {
656 attached = 1;
658 else if (strstr(line, "Vendor")) {
659 tmp = strtok(line, " ");
660 tmp = strtok(NULL, "\n");
661 strcpy(g_usb_vendor, tmp);
662 tmp = NULL;
664 else if (strstr(line, "Product")) {
665 tmp = strtok(line, " ");
666 tmp = strtok(NULL, "\n");
667 strcpy(g_usb_product, tmp);
668 tmp = NULL;
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);
675 tmp = NULL;
678 fclose(fp);
679 if (attached) {
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);
686 ++i;
691 if (usb_dir)
692 closedir(usb_dir);
695 if (scsi_dir)
696 closedir(scsi_dir);
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, "."))
703 continue;
706 sprintf(line, "/dev/usb/%s", dp->d_name);
707 if (!f_exists(line))
708 continue;
710 sprintf(line, "/proc/usblp/%s", dp->d_name);
711 if ((fp = fopen(line, "r"))) {
712 g_usb_vendor[0] = 0;
713 g_usb_product[0] = 0;
714 tmp = NULL;
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);
721 tmp = NULL;
723 else if (strstr(line, "Model")) {
724 tmp = strtok(line, "=");
725 tmp = strtok(NULL, "\n");
726 strcpy(g_usb_product, tmp);
727 tmp = NULL;
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);
733 ++i;
736 fclose(fp);
739 if (usb_dir)
740 closedir(usb_dir);
742 web_puts("];\n");
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)
754 char *p;
756 #ifdef SAME_AS_KERNEL
757 char pgm[256] = "/sbin/hotplug usb";
758 int fd = open("/proc/sys/kernel/hotplug", O_RDONLY);
759 if (fd) {
760 if (read(fd, pgm, sizeof(pgm) - 5) >= 0) {
761 if ((p = strchr(pgm, '\n')) != NULL)
762 *p = 0;
763 strcat(pgm, " usb");
765 close(fd);
767 #else
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";
771 #endif
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);
780 if (p) {
781 setenv("SCSI_HOST", p, 1);
782 setenv("PRODUCT", p, 1);
783 setenv("INTERFACE", "TOMATO/0", 1);
784 system(pgm);
785 unsetenv("INTERFACE");
786 unsetenv("PRODUCT");
787 unsetenv("SCSI_HOST");
788 unsetenv("ACTION");
789 web_printf("%d", is_host_mounted(atoi(p), 0));
791 web_puts("];\n");