Changed reading printers data using new usblp procfs structure.
[tomato.git] / release / src / router / httpd / misc.c
blobaa536da2eb65de52cac0bed907730ce5b5e8eaaf
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2008 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>
34 int wait_file_exists(const char *name, int max, int invert)
36 while (max-- > 0) {
37 if (f_exists(name) ^ invert) return 1;
38 sleep(1);
40 return 0;
43 // to javascript-safe string
44 char *js_string(const char *s)
46 unsigned char c;
47 char *buffer;
48 char *b;
50 if ((buffer = malloc((strlen(s) * 4) + 1)) != NULL) {
51 b = buffer;
52 while ((c = *s++) != 0) {
53 if ((c == '"') || (c == '\'') || (c == '\\') || (!isprint(c))) {
54 b += sprintf(b, "\\x%02x", c);
56 else {
57 *b++ = c;
60 *b = 0;
62 return buffer;
65 // to html-safe string
66 char *html_string(const char *s)
68 unsigned char c;
69 char *buffer;
70 char *b;
72 if ((buffer = malloc((strlen(s) * 6) + 1)) != NULL) {
73 b = buffer;
74 while ((c = *s++) != 0) {
75 if ((c == '&') || (c == '<') || (c == '>') || (c == '"') || (c == '\'') || (!isprint(c))) {
76 b += sprintf(b, "&#%d;", c);
78 else {
79 *b++ = c;
82 *b = 0;
84 return buffer;
87 // removes \r
88 char *unix_string(const char *s)
90 char *buffer;
91 char *b;
92 char c;
94 if ((buffer = malloc(strlen(s) + 1)) != NULL) {
95 b = buffer;
96 while ((c = *s++) != 0)
97 if (c != '\r') *b++ = c;
98 *b = 0;
100 return buffer;
103 // # days, ##:##:##
104 char *reltime(char *buf, time_t t)
106 int days;
107 int m;
109 if (t < 0) t = 0;
110 days = t / 86400;
111 m = t / 60;
112 sprintf(buf, "%d day%s, %02d:%02d:%02d", days, ((days==1) ? "" : "s"), ((m / 60) % 24), (m % 60), (int)(t % 60));
113 return buf;
116 int get_client_info(char *mac, char *ifname)
118 FILE *f;
119 char s[256];
120 char ips[16];
123 # cat /proc/net/arp
124 IP address HW type Flags HW address Mask Device
125 192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1
126 192.168.1.5 0x1 0x2 00:05:06:07:08:09 * br0
129 if ((f = fopen("/proc/net/arp", "r")) != NULL) {
130 while (fgets(s, sizeof(s), f)) {
131 if (sscanf(s, "%15s %*s %*s %17s %*s %16s", ips, mac, ifname) == 3) {
132 if (inet_addr(ips) == clientsai.sin_addr.s_addr) {
133 fclose(f);
134 return 1;
138 fclose(f);
140 return 0;
147 // <% lanip(mode); %>
148 // <mode>
149 // 1 return first 3 octets (192.168.1)
150 // 2 return last octet (1)
151 // else return full (192.168.1.1)
153 void asp_lanip(int argc, char **argv)
155 char *nv, *p;
156 char s[64];
157 char mode;
159 mode = argc ? *argv[0] : 0;
161 if ((nv = nvram_get("lan_ipaddr")) != NULL) {
162 strcpy(s, nv);
163 if ((p = strrchr(s, '.')) != NULL) {
164 *p = 0;
165 web_puts((mode == '1') ? s : (mode == '2') ? (p + 1) : nv);
170 void asp_lipp(int argc, char **argv)
172 char *one = "1";
173 asp_lanip(1, &one);
176 // <% psup(process); %>
177 // returns 1 if process is running
179 void asp_psup(int argc, char **argv)
181 if (argc == 1) web_printf("%d", pidof(argv[0]) > 0);
185 # cat /proc/meminfo
186 total: used: free: shared: buffers: cached:
187 Mem: 14872576 12877824 1994752 0 1236992 4837376
188 Swap: 0 0 0
189 MemTotal: 14524 kB
190 MemFree: 1948 kB
191 MemShared: 0 kB
192 Buffers: 1208 kB
193 Cached: 4724 kB
194 SwapCached: 0 kB
195 Active: 4364 kB
196 Inactive: 2952 kB
197 HighTotal: 0 kB
198 HighFree: 0 kB
199 LowTotal: 14524 kB
200 LowFree: 1948 kB
201 SwapTotal: 0 kB
202 SwapFree: 0 kB
206 typedef struct {
207 unsigned long total;
208 unsigned long free;
209 unsigned long shared;
210 unsigned long buffers;
211 unsigned long cached;
212 unsigned long swaptotal;
213 unsigned long swapfree;
214 unsigned long maxfreeram;
215 } meminfo_t;
217 static int get_memory(meminfo_t *m)
219 FILE *f;
220 char s[128];
221 int ok = 0;
223 if ((f = fopen("/proc/meminfo", "r")) != NULL) {
224 while (fgets(s, sizeof(s), f)) {
225 if (strncmp(s, "Mem:", 4) == 0) {
226 if (sscanf(s + 6, "%ld %*d %ld %ld %ld %ld", &m->total, &m->free, &m->shared, &m->buffers, &m->cached) == 5)
227 ++ok;
229 else if (strncmp(s, "SwapTotal:", 10) == 0) {
230 m->swaptotal = strtoul(s + 12, NULL, 10) * 1024;
231 ++ok;
233 else if (strncmp(s, "SwapFree:", 9) == 0) {
234 m->swapfree = strtoul(s + 11, NULL, 10) * 1024;
235 ++ok;
236 break;
239 fclose(f);
241 if (ok != 3) {
242 memset(m, 0, sizeof(*m));
243 return 0;
245 m->maxfreeram = m->free;
246 if (nvram_match("t_cafree", "1")) m->maxfreeram += m->cached;
247 return 1;
250 void asp_sysinfo(int argc, char **argv)
252 struct sysinfo si;
253 char s[64];
254 meminfo_t mem;
256 web_puts("\nsysinfo = {\n");
257 sysinfo(&si);
258 get_memory(&mem);
259 web_printf(
260 "\tuptime: %ld,\n"
261 "\tuptime_s: '%s',\n"
262 "\tloads: [%ld, %ld, %ld],\n"
263 "\ttotalram: %ld,\n"
264 "\tfreeram: %ld,\n"
265 "\tshareram: %ld,\n"
266 "\tbufferram: %ld,\n"
267 "\tcached: %ld,\n"
268 "\ttotalswap: %ld,\n"
269 "\tfreeswap: %ld,\n"
270 "\ttotalfreeram: %ld,\n"
271 "\tprocs: %d\n",
272 si.uptime,
273 reltime(s, si.uptime),
274 si.loads[0], si.loads[1], si.loads[2],
275 mem.total, mem.free,
276 mem.shared, mem.buffers, mem.cached,
277 mem.swaptotal, mem.swapfree,
278 mem.maxfreeram,
279 si.procs);
280 web_puts("};\n");
283 void asp_activeroutes(int argc, char **argv)
285 FILE *f;
286 char s[512];
287 char dev[17];
288 unsigned long dest;
289 unsigned long gateway;
290 unsigned long flags;
291 unsigned long mask;
292 unsigned metric;
293 struct in_addr ia;
294 char s_dest[16];
295 char s_gateway[16];
296 char s_mask[16];
297 int n;
299 web_puts("\nactiveroutes = [");
300 n = 0;
301 if ((f = fopen("/proc/net/route", "r")) != NULL) {
302 while (fgets(s, sizeof(s), f)) {
303 if (sscanf(s, "%16s%lx%lx%lx%*s%*s%u%lx", dev, &dest, &gateway, &flags, &metric, &mask) != 6) continue;
304 if ((flags & RTF_UP) == 0) continue;
305 if (dest != 0) {
306 ia.s_addr = dest;
307 strcpy(s_dest, inet_ntoa(ia));
309 else {
310 strcpy(s_dest, "default");
312 if (gateway != 0) {
313 ia.s_addr = gateway;
314 strcpy(s_gateway, inet_ntoa(ia));
316 else {
317 strcpy(s_gateway, "*");
319 ia.s_addr = mask;
320 strcpy(s_mask, inet_ntoa(ia));
321 web_printf("%s['%s','%s','%s','%s',%u]", n ? "," : "", dev, s_dest, s_gateway, s_mask, metric);
322 ++n;
324 fclose(f);
326 web_puts("];\n");
329 void asp_cgi_get(int argc, char **argv)
331 const char *v;
332 int i;
334 for (i = 0; i < argc; ++i) {
335 v = webcgi_get(argv[i]);
336 if (v) web_puts(v);
340 void asp_time(int argc, char **argv)
342 time_t t;
343 char s[64];
345 t = time(NULL);
346 if (t < Y2K) {
347 web_puts("Not Available");
349 else {
350 strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
351 web_puts(s);
355 void asp_wanup(int argc, char **argv)
357 web_puts(check_wanup() ? "1" : "0");
360 void asp_wanstatus(int argc, char **argv)
362 const char *p;
364 if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
365 p = "Renewing...";
367 else if (check_wanup()) {
368 p = "Connected";
370 else if (f_exists("/var/lib/misc/wan.connecting")) {
371 p = "Connecting...";
373 else {
374 p = "Disconnected";
376 web_puts(p);
379 void asp_link_uptime(int argc, char **argv)
381 struct sysinfo si;
382 char buf[64];
383 long uptime;
385 buf[0] = '-';
386 buf[1] = 0;
387 if (check_wanup()) {
388 sysinfo(&si);
389 if (f_read("/var/lib/misc/wantime", &uptime, sizeof(uptime)) == sizeof(uptime)) {
390 reltime(buf, si.uptime - uptime);
393 web_puts(buf);
396 void asp_bandwidth(int argc, char **argv)
398 char *name;
399 int sig;
401 if ((nvram_match("rstats_enable", "1")) && (argc == 1)) {
402 if (strcmp(argv[0], "speed") == 0) {
403 sig = SIGUSR1;
404 name = "/var/spool/rstats-speed.js";
406 else {
407 sig = SIGUSR2;
408 name = "/var/spool/rstats-history.js";
410 unlink(name);
411 killall("rstats", sig);
412 wait_file_exists(name, 5, 0);
413 do_file(name);
414 unlink(name);
418 void asp_rrule(int argc, char **argv)
420 char s[32];
421 int i;
423 i = nvram_get_int("rruleN");
424 sprintf(s, "rrule%d", i);
425 web_puts("\nrrule = '");
426 web_putj(nvram_safe_get(s));
427 web_printf("';\nrruleN = %d;\n", i);
430 void asp_compmac(int argc, char **argv)
432 char mac[32];
433 char ifname[32];
435 if (get_client_info(mac, ifname)) {
436 web_puts(mac);
440 void asp_ident(int argc, char **argv)
442 web_puth(nvram_safe_get("router_name"));
445 void asp_statfs(int argc, char **argv)
447 struct statfs sf;
449 if (argc != 2) return;
451 // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted
452 if ((statfs(argv[0], &sf) != 0) || (sf.f_type == 0x73717368))
453 memset(&sf, 0, sizeof(sf));
455 web_printf(
456 "\n%s = {\n"
457 "\tsize: %llu,\n"
458 "\tfree: %llu\n"
459 "};\n",
460 argv[1],
461 ((uint64_t)sf.f_bsize * sf.f_blocks),
462 ((uint64_t)sf.f_bsize * sf.f_bfree));
465 void asp_notice(int argc, char **argv)
467 char s[256];
468 char buf[2048];
470 if (argc != 1) return;
471 snprintf(s, sizeof(s), "/var/notice/%s", argv[0]);
472 if (f_read_string(s, buf, sizeof(buf)) <= 0) return;
473 web_putj(buf);
476 void wo_wakeup(char *url)
478 char *mac;
479 char *p;
480 char *end;
482 if ((mac = webcgi_get("mac")) != NULL) {
483 end = mac + strlen(mac);
484 while (mac < end) {
485 while ((*mac == ' ') || (*mac == '\t') || (*mac == '\r') || (*mac == '\n')) ++mac;
486 if (*mac == 0) break;
488 p = mac;
489 while ((*p != 0) && (*p != ' ') && (*p != '\r') && (*p != '\n')) ++p;
490 *p = 0;
492 eval("ether-wake", "-i", nvram_safe_get("lan_ifname"), mac);
493 mac = p + 1;
496 common_redirect();
499 void asp_dns(int argc, char **argv)
501 char s[128];
502 int i;
503 const dns_list_t *dns;
505 dns = get_dns(); // static buffer
506 strcpy(s, "\ndns = [");
507 for (i = 0 ; i < dns->count; ++i) {
508 sprintf(s + strlen(s), "%s'%s'", i ? "," : "", inet_ntoa(dns->dns[i]));
510 strcat(s, "];\n");
511 web_puts(s);
514 void wo_resolve(char *url)
516 char *p;
517 char *ip;
518 struct hostent *he;
519 struct in_addr ia;
520 char comma;
521 char *js;
523 comma = ' ';
524 web_puts("\nresolve_data = [\n");
525 if ((p = webcgi_get("ip")) != NULL) {
526 while ((ip = strsep(&p, ",")) != NULL) {
527 ia.s_addr = inet_addr(ip);
528 he = gethostbyaddr(&ia, sizeof(ia), AF_INET);
529 js = js_string(he ? he->h_name : "");
530 web_printf("%c['%s','%s']", comma, inet_ntoa(ia), js);
531 free(js);
532 comma = ',';
535 web_puts("];\n");
539 //!!TB - USB support
541 #define PROC_SCSI_ROOT "/proc/scsi"
542 #define USB_STORAGE "usb-storage"
544 /* this value should not match any of the existing EFH_ values in shared.h */
545 #define EFH_PRINT 0x00000080 /* output partition list to the web response */
547 int is_partition_mounted(char *dev_name, int host_num, int disc_num, int part_num, uint flags)
549 char the_label[128];
550 char *type;
551 int is_mounted = 0;
552 struct mntent *mnt;
554 if (!find_label(dev_name, the_label)) {
555 sprintf(the_label, "disc%d_%d", disc_num, part_num);
558 if (flags & EFH_PRINT) {
559 if (flags & EFH_1ST_DISC) {
560 // [disc_no, [partitions array]],...
561 web_printf("]],[%d,[", disc_num);
563 // [partition_name, is_mounted, mount_point, type, opts],...
564 web_printf("%s['%s',", (flags & EFH_1ST_DISC) ? "" : ",", the_label);
567 mnt = findmntent(dev_name);
568 if (mnt) {
569 is_mounted = 1;
570 if (flags & EFH_PRINT) {
571 web_printf("1,'%s','%s','%s']",
572 mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts);
575 else {
576 if (flags & EFH_PRINT) {
577 type = detect_fs_type(dev_name);
578 web_printf("0,'','%s','']", type ? type : "");
582 return is_mounted;
585 int is_host_mounted(int host_no, int print_parts)
587 if (print_parts) web_puts("[-1,[");
589 int fd = usb_lock();
590 int mounted = exec_for_host(
591 host_no,
592 0x00,
593 print_parts ? EFH_PRINT : 0,
594 is_partition_mounted);
595 usb_unlock(fd);
597 if (print_parts) web_puts("]]");
599 return mounted;
603 * The disc # doesn't correspond to the host#, since there may be more than
604 * one partition on a disk.
605 * Nor does either correspond to the scsi host number.
606 * And if the user plugs or unplugs a usb storage device after bringing up the
607 * NAS:USB support page, the numbers won't match anymore, since "part#"s
608 * may be added or deleted to the /dev/discs* or /dev/scsi**.
610 * But since we only need to support the devices list and mount/unmount
611 * functionality on the host level, the host# shoudl work ok. Just make sure
612 * to always pass and use the _host#_, and not the disc#.
614 void asp_usbdevices(int argc, char **argv)
616 DIR *scsi_dir=NULL, *usb_dir=NULL;
617 struct dirent *dp, *scsi_dirent;
618 uint host_no;
619 int i = 0, attached, mounted;
620 FILE *fp;
621 char line[128];
622 char *tmp=NULL, g_usb_vendor[25], g_usb_product[20], g_usb_serial[20];
624 web_puts("\nusbdev = [");
626 if (!nvram_match("usb_enable", "1")) {
627 web_puts("];\n");
628 return;
631 /* find all attached USB storage devices */
632 scsi_dir = opendir(PROC_SCSI_ROOT);
633 while (scsi_dir && (scsi_dirent = readdir(scsi_dir)))
635 if (!strncmp(USB_STORAGE, scsi_dirent->d_name, strlen(USB_STORAGE)))
637 sprintf(line, "%s/%s", PROC_SCSI_ROOT, scsi_dirent->d_name);
638 usb_dir = opendir(line);
639 while (usb_dir && (dp = readdir(usb_dir)))
641 if (!strcmp(dp->d_name, "..") || !strcmp(dp->d_name, "."))
642 continue;
643 sprintf(line, "%s/%s/%s", PROC_SCSI_ROOT, scsi_dirent->d_name, dp->d_name);
645 fp = fopen(line, "r");
646 if (fp) {
647 attached = 0;
648 g_usb_vendor[0] = 0;
649 g_usb_product[0] = 0;
650 g_usb_serial[0] = 0;
651 tmp = NULL;
653 while (fgets(line, sizeof(line), fp) != NULL) {
654 if (strstr(line, "Attached: Yes")) {
655 attached = 1;
657 else if (strstr(line, "Vendor")) {
658 tmp = strtok(line, " ");
659 tmp = strtok(NULL, "\n");
660 strcpy(g_usb_vendor, tmp);
661 tmp = NULL;
663 else if (strstr(line, "Product")) {
664 tmp = strtok(line, " ");
665 tmp = strtok(NULL, "\n");
666 strcpy(g_usb_product, tmp);
667 tmp = NULL;
669 else if (strstr(line, "Serial Number")) {
670 tmp = strtok(line, " ");
671 tmp = strtok(NULL, " ");
672 tmp = strtok(NULL, "\n");
673 strcpy(g_usb_serial, tmp);
674 tmp = NULL;
677 fclose(fp);
678 if (attached) {
679 /* Host no. assigned by scsi driver for this UFD */
680 host_no = atoi(dp->d_name);
681 web_printf("%s['Storage','%d','%s','%s','%s', [", i ? "," : "",
682 host_no, g_usb_vendor, g_usb_product, g_usb_serial);
683 mounted = is_host_mounted(host_no, 1);
684 web_printf("], %d]", mounted);
685 ++i;
690 if (usb_dir)
691 closedir(usb_dir);
694 if (scsi_dir)
695 closedir(scsi_dir);
697 /* now look for printers */
698 usb_dir = opendir("/proc/usblp");
699 while (usb_dir && (dp = readdir(usb_dir)))
701 if (!strcmp(dp->d_name, "..") || !strcmp(dp->d_name, "."))
702 continue;
705 sprintf(line, "/dev/usb/%s", dp->d_name);
706 if (!f_exists(line))
707 continue;
709 sprintf(line, "/proc/usblp/%s", dp->d_name);
710 if ((fp = fopen(line, "r"))) {
711 g_usb_vendor[0] = 0;
712 g_usb_product[0] = 0;
713 tmp = NULL;
715 while (fgets(line, sizeof(line), fp) != NULL) {
716 if (strstr(line, "Manufacturer")) {
717 tmp = strtok(line, "=");
718 tmp = strtok(NULL, "\n");
719 strcpy(g_usb_vendor, tmp);
720 tmp = NULL;
722 else if (strstr(line, "Model")) {
723 tmp = strtok(line, "=");
724 tmp = strtok(NULL, "\n");
725 strcpy(g_usb_product, tmp);
726 tmp = NULL;
729 if ((strlen(g_usb_product) > 0) || (strlen(g_usb_vendor) > 0)) {
730 web_printf("%s['Printer','%s','%s','%s','']", i ? "," : "",
731 dp->d_name, g_usb_vendor, g_usb_product);
732 ++i;
735 fclose(fp);
738 if (usb_dir)
739 closedir(usb_dir);
741 web_puts("];\n");
744 //#define SAME_AS_KERNEL
746 /* Simulate a hotplug event, as if a USB storage device
747 * got plugged or unplugged.
748 * Either use a hardcoded program name, or the same
749 * hotplug program that the kernel uses for a real event.
751 void wo_usbcommand(char *url)
753 char *p;
755 #ifdef SAME_AS_KERNEL
756 char pgm[256] = "/sbin/hotplug usb";
757 int fd = open("/proc/sys/kernel/hotplug", O_RDONLY);
758 if (fd) {
759 if (read(fd, pgm, sizeof(pgm) - 5) >= 0) {
760 if ((p = strchr(pgm, '\n')) != NULL)
761 *p = 0;
762 strcat(pgm, " usb");
764 close(fd);
766 #else
767 // don't use value from /proc/sys/kernel/hotplug
768 // since it may be overriden by a user.
769 const char pgm[] = "/sbin/hotplug usb";
770 #endif
772 web_puts("\nusb = [\n");
773 if ((p = webcgi_get("remove")) != NULL) {
774 setenv("ACTION", "remove", 1);
776 else if ((p = webcgi_get("mount")) != NULL) {
777 setenv("ACTION", "add", 1);
779 if (p) {
780 setenv("SCSI_HOST", p, 1);
781 setenv("PRODUCT", p, 1);
782 setenv("INTERFACE", "TOMATO/0", 1);
783 system(pgm);
784 unsetenv("INTERFACE");
785 unsetenv("PRODUCT");
786 unsetenv("SCSI_HOST");
787 unsetenv("ACTION");
788 web_printf("%d", is_host_mounted(atoi(p), 0));
790 web_puts("];\n");