Display partitions list for attached storage devices in the Web GUI.
[tomato.git] / release / src / router / shared / misc.c
blobda17bd979d502a14efe6725ec8bc6154455d5574
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2008 Jonathan Zarate
6 */
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13 #include <stdarg.h>
14 #include <syslog.h>
15 #include <sys/ioctl.h>
16 #include <net/if.h>
17 #include <sys/socket.h>
18 #include <arpa/inet.h>
19 #include <sys/sysinfo.h>
21 #include <bcmnvram.h>
22 #include <bcmdevs.h>
23 #include <wlutils.h>
25 #include "shutils.h"
26 #include "shared.h"
28 #if 0
29 #define _dprintf cprintf
30 #else
31 #define _dprintf(args...) do { } while(0)
32 #endif
35 int get_wan_proto(void)
37 const char *names[] = { // order must be synced with def at shared.h
38 "static",
39 "dhcp",
40 // hbobs "heartbeat",
41 "l2tp",
42 "pppoe",
43 "pptp",
44 NULL
46 int i;
47 const char *p;
49 p = nvram_safe_get("wan_proto");
50 for (i = 0; names[i] != NULL; ++i) {
51 if (strcmp(p, names[i]) == 0) return i + 1;
53 return WP_DISABLED;
56 int using_dhcpc(void)
58 #if 0 // hbobs
59 const char *proto = nvram_safe_get("wan_proto");
60 return (strcmp(proto, "dhcp") == 0) || (strcmp(proto, "l2tp") == 0) || (strcmp(proto, "heartbeat") == 0);
61 #endif
63 switch (get_wan_proto()) {
64 case WP_DHCP:
65 case WP_L2TP:
66 return 1;
68 return 0;
71 int wl_client(void)
73 return ((nvram_match("wl_mode", "sta")) || (nvram_match("wl_mode", "wet")));
76 void notice_set(const char *path, const char *format, ...)
78 char p[256];
79 char buf[2048];
80 va_list args;
82 va_start(args, format);
83 vsnprintf(buf, sizeof(buf), format, args);
84 va_end(args);
86 mkdir("/var/notice", 0755);
87 snprintf(p, sizeof(p), "/var/notice/%s", path);
88 f_write_string(p, buf, 0, 0);
89 if (buf[0]) syslog(LOG_INFO, "notice[%s]: %s", path, buf);
93 // #define _x_dprintf(args...) syslog(LOG_DEBUG, args);
94 #define _x_dprintf(args...) do { } while (0);
96 int check_wanup(void)
98 int up = 0;
99 int proto;
100 char buf1[64];
101 char buf2[64];
102 const char *name;
103 int f;
104 struct ifreq ifr;
106 proto = get_wan_proto();
107 if (proto == WP_DISABLED) return 0;
109 if ((proto == WP_PPTP) || (proto == WP_L2TP) || (proto == WP_PPPOE)) {
110 if (f_read_string("/tmp/ppp/link", buf1, sizeof(buf1)) > 0) {
111 // contains the base name of a file in /var/run/ containing pid of a daemon
112 snprintf(buf2, sizeof(buf2), "/var/run/%s.pid", buf1);
113 if (f_read_string(buf2, buf1, sizeof(buf1)) > 0) {
114 name = psname(atoi(buf1), buf2, sizeof(buf2));
115 if (proto == WP_PPPOE) {
116 if (strcmp(name, "pppoecd") == 0) up = 1;
118 else {
119 if (strcmp(name, "pppd") == 0) up = 1;
122 else {
123 _dprintf("%s: error reading %s\n", __FUNCTION__, buf2);
125 if (!up) {
126 unlink("/tmp/ppp/link");
127 _x_dprintf("required daemon not found, assuming link is dead\n");
130 else {
131 _x_dprintf("%s: error reading %s\n", __FUNCTION__, "/tmp/ppp/link");
134 else if (!nvram_match("wan_ipaddr", "0.0.0.0")) {
135 up = 1;
137 else {
138 _x_dprintf("%s: default !up\n", __FUNCTION__);
141 if ((up) && ((f = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)) {
142 strlcpy(ifr.ifr_name, nvram_safe_get("wan_iface"), sizeof(ifr.ifr_name));
143 if (ioctl(f, SIOCGIFFLAGS, &ifr) < 0) {
144 up = 0;
145 _x_dprintf("%s: SIOCGIFFLAGS\n", __FUNCTION__);
147 close(f);
148 if ((ifr.ifr_flags & IFF_UP) == 0) {
149 up = 0;
150 _x_dprintf("%s: !IFF_UP\n", __FUNCTION__);
154 return up;
158 const dns_list_t *get_dns(void)
160 static dns_list_t dns;
161 char s[512];
162 int n;
163 int i, j;
164 struct in_addr ia;
165 char d[4][16];
167 dns.count = 0;
169 strlcpy(s, nvram_safe_get("wan_dns"), sizeof(s));
170 if ((nvram_match("dns_addget", "1")) || (s[0] == 0)) {
171 n = strlen(s);
172 snprintf(s + n, sizeof(s) - n, " %s", nvram_safe_get("wan_get_dns"));
175 n = sscanf(s, "%15s %15s %15s %15s", d[0], d[1], d[2], d[3]);
176 for (i = 0; i < n; ++i) {
177 if (inet_pton(AF_INET, d[i], &ia) > 0) {
178 for (j = dns.count - 1; j >= 0; --j) {
179 if (dns.dns[j].s_addr == ia.s_addr) break;
181 if (j < 0) {
182 dns.dns[dns.count++].s_addr = ia.s_addr;
183 if (dns.count == 3) break;
188 return &dns;
191 // -----------------------------------------------------------------------------
193 void set_action(int a)
195 int r = 3;
196 while (f_write("/var/lock/action", &a, sizeof(a), 0, 0) != sizeof(a)) {
197 sleep(1);
198 if (--r == 0) return;
200 if (a != ACT_IDLE) sleep(2);
203 int check_action(void)
205 int a;
206 int r = 3;
208 while (f_read("/var/lock/action", &a, sizeof(a)) != sizeof(a)) {
209 sleep(1);
210 if (--r == 0) return ACT_UNKNOWN;
212 return a;
215 int wait_action_idle(int n)
217 while (n-- > 0) {
218 if (check_action() == ACT_IDLE) return 1;
219 sleep(1);
221 return 0;
224 // -----------------------------------------------------------------------------
226 const char *get_wanip(void)
228 const char *p;
230 if (!check_wanup()) return "0.0.0.0";
231 switch (get_wan_proto()) {
232 case WP_DISABLED:
233 return "0.0.0.0";
234 case WP_PPTP:
235 p = "pptp_get_ip";
236 break;
237 case WP_L2TP:
238 p = "l2tp_get_ip";
239 break;
240 default:
241 p = "wan_ipaddr";
242 break;
244 return nvram_safe_get(p);
247 long get_uptime(void)
249 struct sysinfo si;
250 sysinfo(&si);
251 return si.uptime;
254 int get_radio(void)
256 uint32 n;
258 return (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_RADIO, &n, sizeof(n)) == 0) &&
259 ((n & WL_RADIO_SW_DISABLE) == 0);
262 void set_radio(int on)
264 uint32 n;
266 #ifndef WL_BSS_INFO_VERSION
267 #error WL_BSS_INFO_VERSION
268 #endif
270 #if WL_BSS_INFO_VERSION >= 108
271 n = on ? (WL_RADIO_SW_DISABLE << 16) : ((WL_RADIO_SW_DISABLE << 16) | 1);
272 wl_ioctl(nvram_safe_get("wl_ifname"), WLC_SET_RADIO, &n, sizeof(n));
273 if (!on) {
274 led(LED_WLAN, 0);
275 led(LED_DIAG, 0);
277 #else
278 n = on ? 0 : WL_RADIO_SW_DISABLE;
279 wl_ioctl(nvram_safe_get("wl_ifname"), WLC_SET_RADIO, &n, sizeof(n));
280 if (!on) {
281 led(LED_DIAG, 0);
283 #endif
286 int nvram_get_int(const char *key)
288 return atoi(nvram_safe_get(key));
292 long nvram_xget_long(const char *name, long min, long max, long def)
294 const char *p;
295 char *e;
296 long n;
298 p = nvram_get(name);
299 if ((p != NULL) && (*p != 0)) {
300 n = strtol(p, &e, 0);
301 if ((e != p) && ((*e == 0) || (*e == ' ')) && (n > min) && (n < max)) {
302 return n;
305 return def;
309 int nvram_get_file(const char *key, const char *fname, int max)
311 char b[2048];
312 int n;
313 char *p;
315 p = nvram_safe_get(key);
316 n = strlen(p);
317 if (n <= max) {
318 n = base64_decode(p, b, n);
319 if (n > 0) return (f_write(fname, b, n, 0, 0700) == n);
321 return 0;
324 int nvram_set_file(const char *key, const char *fname, int max)
326 char a[2048];
327 char b[4096];
328 int n;
330 if (((n = f_read(fname, &a, sizeof(a))) > 0) && (n <= max)) {
331 n = base64_encode(a, b, n);
332 b[n] = 0;
333 nvram_set(key, b);
334 return 1;
336 return 0;
339 int nvram_contains_word(const char *key, const char *word)
341 return (find_word(nvram_safe_get(key), word) != NULL);
344 int connect_timeout(int fd, const struct sockaddr *addr, socklen_t len, int timeout)
346 fd_set fds;
347 struct timeval tv;
348 int flags;
349 int n;
350 int r;
352 if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
353 (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) {
354 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
355 return -1;
358 if (connect(fd, addr, len) < 0) {
359 // _dprintf("%s: connect %d = <0\n", __FUNCTION__, fd);
361 if (errno != EINPROGRESS) {
362 _dprintf("%s: error in connect %d errno=%d\n", __FUNCTION__, fd, errno);
363 return -1;
366 while (1) {
367 tv.tv_sec = timeout;
368 tv.tv_usec = 0;
369 FD_ZERO(&fds);
370 FD_SET(fd, &fds);
371 r = select(fd + 1, NULL, &fds, NULL, &tv);
372 if (r == 0) {
373 _dprintf("%s: timeout in select %d\n", __FUNCTION__, fd);
374 return -1;
376 else if (r < 0) {
377 if (errno != EINTR) {
378 _dprintf("%s: error in select %d\n", __FUNCTION__, fd);
379 return -1;
381 // loop
383 else {
384 r = 0;
385 n = sizeof(r);
386 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &n) < 0) || (r != 0)) {
387 _dprintf("%s: error in SO_ERROR %d\n", __FUNCTION__, fd);
388 return -1;
390 break;
395 if (fcntl(fd, F_SETFL, flags) < 0) {
396 _dprintf("%s: error in F_*ETFL %d\n", __FUNCTION__, fd);
397 return -1;
400 // _dprintf("%s: OK %d\n", __FUNCTION__, fd);
401 return 0;
405 int time_ok(void)
407 return time(0) > Y2K;
411 // -----------------------------------------------------------------------------
412 //!!TB - USB Support
414 /* stolen from the e2fsprogs/ismounted.c */
415 /* Find wherever 'file' (actually: device) is mounted.
416 * Either the exact same device-name, or another device-name.
417 * The latter is detected by comparing the rdev or dev&inode.
418 * So aliasing won't fool us---we'll still find if it's mounted.
419 * Return its mnt entry.
420 * In particular, the caller would look at the mnt->mountpoint.
421 * If "file" is an empty string, return the mntent of the first
422 * mount that is for a USB disc that is no longer accessible.
424 struct mntent *findmntent(char *file)
426 struct mntent *mnt;
427 struct stat st_buf;
428 dev_t file_dev=0, file_rdev=0;
429 ino_t file_ino=0;
430 FILE *f;
432 if ((f = setmntent("/proc/mounts", "r")) == NULL)
433 return NULL;
435 if (stat(file, &st_buf) == 0) {
436 if (S_ISBLK(st_buf.st_mode)) {
437 file_rdev = st_buf.st_rdev;
438 } else {
439 file_dev = st_buf.st_dev;
440 file_ino = st_buf.st_ino;
443 while ((mnt = getmntent(f)) != NULL) {
444 if (*file == 0 && strncmp(mnt->mnt_fsname, "/dev/discs/", 11) == 0) {
445 if (stat(mnt->mnt_fsname, &st_buf) != 0)
446 break; /* Device is no longer valid. */
449 if (strcmp(file, mnt->mnt_fsname) == 0)
450 break;
451 if (stat(mnt->mnt_fsname, &st_buf) == 0) {
452 if (S_ISBLK(st_buf.st_mode)) {
453 if (file_rdev && (file_rdev == st_buf.st_rdev))
454 break;
455 } else {
456 if (file_dev && ((file_dev == st_buf.st_dev) &&
457 (file_ino == st_buf.st_ino)))
458 break;
463 fclose(f);
464 return mnt;
467 /* Figure out the volume label. */
468 /* If we found it, return Non-Zero and store it at the_label. */
469 #define USE_BB 0 /* Use the actual busybox .a file. */
471 #if USE_BB
472 char applet_name[] = "hotplug"; /* Needed to satisfy a reference. */
473 int find_label(char *mnt_dev, char *the_label)
475 char *uuid, *label;
476 int i;
478 *the_label = 0;
479 /* heuristic: partition name ends in a digit */
480 if ( !isdigit(mnt_dev[strlen(mnt_dev) - 1]))
481 return(0);
483 cprintf("\n\nGetting volume label for '%s'\n", mnt_dev);
485 /* it's in get_devname.c */
486 i = get_label_uuid(mnt_dev, &label, &uuid, 0);
487 cprintf("get_label_uuid= %d\n", i);
488 if (i == 0) {
489 cprintf(" label= %s uuid = %s\n", label, uuid);
490 strcpy(the_label, label);
491 return(1);
493 return (0);
495 #else
496 int find_label(char *mnt_dev, char *the_label)
498 char *label, *p;
499 FILE *mfp;
500 char buf[128];
501 struct stat st_arg, st_mou;
503 *the_label = 0;
504 /* heuristic: partition name ends in a digit */
505 if ( !isdigit(mnt_dev[strlen(mnt_dev) - 1]))
506 return(0);
508 mfp = popen("mount LABEL= /no-such-label", "r");
509 if (mfp == NULL) {
510 _dprintf("Cannot popen mount!!\n");
511 return(0);
514 while (fgets(buf, sizeof(buf), mfp)) {
515 if ((p = strchr(buf, '\n')))
516 *p = 0;
517 if ((p = strstr(buf, "LABEL "))) { /* Isolate the label. */
518 if ((label=strchr(p+6, '\''))) {
519 ++label;
520 if ((p = strchr(label, '\''))) {
521 *p++ = 0;
522 if ((p = strchr(p, '/'))) { /* Isolate the device. */
523 /* See if the argument is the same as what mount gives. */
524 if (stat(mnt_dev, &st_arg) == 0 && stat(p, &st_mou) == 0) {
525 if (S_ISBLK(st_arg.st_mode) && S_ISBLK(st_mou.st_mode) &&
526 st_arg.st_rdev == st_mou.st_rdev) {
527 strcpy(the_label, label);
528 fclose(mfp);
529 return(1);
537 fclose(mfp);
538 return(0);
540 #endif