Merge commit 'origin/tomato-ND-usbmod-mixvpn' into tomato-ND-USBmod
[tomato.git] / release / src / router / httpd / tomato.c
blob7ad6fee17a9852df093e348465f3442e0f00a1e3
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "tomato.h"
10 #include <sys/sysinfo.h>
11 #include <sys/stat.h>
12 #include <arpa/inet.h>
13 #include <time.h>
16 // #define DEBUG_NOEXECSERVICE
17 // #define DEBUG_NVRAMSET(k, v) cprintf("nvram set %s=%s\n", k, v);
18 #define DEBUG_NVRAMSET(k, v) do { } while(0);
21 char *post_buf = NULL;
22 int rboot = 0;
23 extern int post;
25 static void asp_css(int argc, char **argv);
26 static void asp_resmsg(int argc, char **argv);
29 static void wo_tomato(char *url);
30 static void wo_update(char *url);
31 static void wo_service(char *url);
32 static void wo_shutdown(char *url);
33 static void wo_nvcommit(char *url);
34 // static void wo_logout(char *url);
37 // ----------------------------------------------------------------------------
40 void exec_service(const char *action)
42 int i;
44 _dprintf("exec_service: %s\n", action);
46 i = 10;
47 while ((!nvram_match("action_service", "")) && (i-- > 0)) {
48 _dprintf("%s: waiting before %d\n", __FUNCTION__, i);
49 sleep(1);
52 nvram_set("action_service", action);
53 kill(1, SIGUSR1);
55 i = 3;
56 while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
57 _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
58 sleep(1);
62 if (atoi(webcgi_safeget("_service_wait", ""))) {
63 i = 10;
64 while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
65 _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
66 sleep(1);
72 static void wi_generic_noid(char *url, int len, char *boundary)
74 if (post == 1) {
75 if (len >= (32 * 1024)) {
76 // syslog(LOG_WARNING, "POST max");
77 exit(1);
80 if (post_buf) free(post_buf);
81 if ((post_buf = malloc(len + 1)) == NULL) {
82 // syslog(LOG_CRIT, "Unable to allocate post buffer");
83 exit(1);
86 if (web_read_x(post_buf, len) != len) {
87 exit(1);
89 post_buf[len] = 0;
90 webcgi_init(post_buf);
94 void wi_generic(char *url, int len, char *boundary)
96 wi_generic_noid(url, len, boundary);
97 check_id(url);
100 // !!TB - CGI Support
101 void wi_cgi_bin(char *url, int len, char *boundary)
103 if (post_buf) free(post_buf);
104 post_buf = NULL;
106 if (post) {
107 if (len >= (32 * 1024)) {
108 syslog(LOG_WARNING, "POST length exceeded maximum allowed");
109 exit(1);
112 if (len > 0) {
113 if ((post_buf = malloc(len + 1)) == NULL) {
114 exit(1);
116 if (web_read_x(post_buf, len) != len) {
117 exit(1);
119 post_buf[len] = 0;
124 static void _execute_command(char *url, char *command, char *query, char *output)
126 char webExecFile[] = "/tmp/.wxXXXXXX";
127 char webQueryFile[] = "/tmp/.wqXXXXXX";
128 FILE *f;
130 mktemp(webExecFile);
131 if (query) mktemp(webQueryFile);
133 if ((f = fopen(webExecFile, "wb")) != NULL) {
134 fprintf(f,
135 "#!/bin/sh\n"
136 "export REQUEST_METHOD=\"%s\"\n"
137 "export PATH=%s\n"
138 ". /etc/profile\n"
139 "%s%s %s%s\n",
140 post ? "POST" : "GET", getenv("PATH"),
141 command ? "" : "./", command ? command : url,
142 query ? "<" : "", query ? webQueryFile : "");
143 fclose(f);
145 else {
146 unlink(output);
147 exit(1);
149 chmod(webExecFile, 0700);
151 if (query) {
152 if ((f = fopen(webQueryFile, "wb")) != NULL) {
153 fprintf(f, "%s\n", query);
154 fclose(f);
156 else {
157 unlink(output);
158 unlink(webExecFile);
159 exit(1);
163 char cmd[128];
164 sprintf(cmd, "%s >%s 2>&1", webExecFile, output);
165 system(cmd);
166 unlink(webQueryFile);
167 unlink(webExecFile);
170 static void wo_cgi_bin(char *url)
172 char webOutpFile[] = "/tmp/.woXXXXXX";
174 mktemp(webOutpFile);
175 _execute_command(url, NULL, post_buf, webOutpFile);
177 if (post_buf) {
178 free(post_buf);
179 post_buf = NULL;
181 wo_asp(webOutpFile);
182 unlink(webOutpFile);
185 static void wo_shell(char *url)
187 char webOutpFile[] = "/tmp/.woXXXXXX";
189 mktemp(webOutpFile);
190 _execute_command(NULL, webcgi_get("command"), NULL, webOutpFile);
192 web_puts("\ncmdresult = '");
193 web_putfile(webOutpFile, WOF_JAVASCRIPT);
194 web_puts("';");
195 unlink(webOutpFile);
198 static void wo_blank(char *url)
200 web_puts("\n\n\n\n");
203 static void wo_favicon(char *url)
205 send_header(200, NULL, "image/vnd.microsoft.icon", 0);
206 do_file(url);
208 if (nvram_match("web_favicon", "1")) {
209 send_header(200, NULL, "image/vnd.microsoft.icon", 0);
210 do_file(url);
212 else {
213 send_error(404, NULL, NULL);
218 static void wo_cfe(char *url)
220 do_file("/dev/mtd/0ro");
223 static void wo_nvram(char *url)
225 web_pipecmd("nvram show", WOF_NONE);
228 static void wo_iptables(char *url)
230 web_pipecmd("iptables -nvL; iptables -t nat -nvL; iptables -t mangle -nvL", WOF_NONE);
234 static void wo_spin(char *url)
236 char s[64];
238 strlcpy(s, nvram_safe_get("web_css"), sizeof(s));
239 strlcat(s, "_spin.gif", sizeof(s));
240 if (f_exists(s)) do_file(s);
241 else do_file("_spin.gif");
245 void common_redirect(void)
247 if (atoi(webcgi_safeget("_ajax", ""))) {
248 send_header(200, NULL, mime_html, 0);
249 web_puts("OK");
251 else {
252 redirect(webcgi_safeget("_redirect", "/"));
256 // ----------------------------------------------------------------------------
258 const struct mime_handler mime_handlers[] = {
259 { "update.cgi", mime_javascript, 0, wi_generic, wo_update, 1 },
260 { "tomato.cgi", NULL, 0, wi_generic, wo_tomato, 1 },
262 { "debug.js", mime_javascript, 5, wi_generic_noid, wo_blank, 1 }, // while debugging
263 { "cfe/*.bin", mime_binary, 0, wi_generic, wo_cfe, 1 },
264 { "nvram/*.txt", mime_binary, 0, wi_generic, wo_nvram, 1 },
265 { "ipt/*.txt", mime_binary, 0, wi_generic, wo_iptables, 1 },
267 { "cfg/*.cfg", NULL, 0, wi_generic, wo_backup, 1 },
268 { "cfg/restore.cgi", mime_html, 0, wi_restore, wo_restore, 1 },
269 { "cfg/defaults.cgi", NULL, 0, wi_generic, wo_defaults, 1 },
271 { "bwm/*.gz", NULL, 0, wi_generic, wo_bwmbackup, 1 },
272 { "bwm/restore.cgi", NULL, 0, wi_bwmrestore, wo_bwmrestore, 1 },
274 { "logs/view.cgi", NULL, 0, wi_generic, wo_viewlog, 1 },
275 { "logs/*.txt", NULL, 0, wi_generic, wo_syslog, 1 },
277 { "logout.asp", NULL, 0, wi_generic, wo_asp, 1 },
278 { "clearcookies.asp", NULL, 0, wi_generic, wo_asp, 1 },
280 // { "spin.gif", NULL, 0, wi_generic_noid, wo_spin, 1 },
282 { "**.asp", NULL, 0, wi_generic_noid, wo_asp, 1 },
283 { "**.css", "text/css", 2, wi_generic_noid, do_file, 1 },
284 { "**.htm", mime_html, 2, wi_generic_noid, do_file, 1 },
285 { "**.gif", "image/gif", 5, wi_generic_noid, do_file, 1 },
286 { "**.jpg", "image/jpeg", 5, wi_generic_noid, do_file, 1 },
287 { "**.png", "image/png", 5, wi_generic_noid, do_file, 1 },
288 { "**.js", mime_javascript, 2, wi_generic_noid, do_file, 1 },
289 { "**.jsx", mime_javascript, 0, wi_generic, wo_asp, 1 },
290 { "**.svg", "image/svg+xml", 2, wi_generic_noid, do_file, 1 },
291 { "**.txt", mime_plain, 2, wi_generic_noid, do_file, 1 },
292 { "**.bin", mime_binary, 0, wi_generic_noid, do_file, 1 },
293 { "**.bino", mime_octetstream, 0, wi_generic_noid, do_file, 1 },
294 { "favicon.ico", NULL, 5, wi_generic_noid, wo_favicon, 1 },
295 // !!TB - CGI Support, enable downloading archives
296 { "**/cgi-bin/**|**.sh", NULL, 0, wi_cgi_bin, wo_cgi_bin, 1 },
297 { "**.tar|**.gz", mime_binary, 0, wi_generic_noid, do_file, 1 },
298 { "shell.cgi", mime_javascript, 0, wi_generic, wo_shell, 1 },
300 { "dhcpc.cgi", NULL, 0, wi_generic, wo_dhcpc, 1 },
301 { "dhcpd.cgi", mime_javascript, 0, wi_generic, wo_dhcpd, 1 },
302 { "nvcommit.cgi", NULL, 0, wi_generic, wo_nvcommit, 1 },
303 { "ping.cgi", mime_javascript, 0, wi_generic, wo_ping, 1 },
304 { "trace.cgi", mime_javascript, 0, wi_generic, wo_trace, 1 },
305 { "upgrade.cgi", mime_html, 0, wi_upgrade, wo_flash, 1 },
306 { "upnp.cgi", NULL, 0, wi_generic, wo_upnp, 1 },
307 { "wakeup.cgi", NULL, 0, wi_generic, wo_wakeup, 1 },
308 { "wlmnoise.cgi", mime_html, 0, wi_generic, wo_wlmnoise, 1 },
309 { "wlradio.cgi", NULL, 0, wi_generic, wo_wlradio, 1 },
310 { "resolve.cgi", mime_javascript, 0, wi_generic, wo_resolve, 1 },
311 { "expct.cgi", mime_html, 0, wi_generic, wo_expct, 1 },
312 { "service.cgi", NULL, 0, wi_generic, wo_service, 1 },
313 // { "logout.cgi", NULL, 0, wi_generic, wo_logout, 0 }, // see httpd.c
314 { "shutdown.cgi", mime_html, 0, wi_generic, wo_shutdown, 1 },
315 #ifdef TCONFIG_OPENVPN
316 { "vpnstatus.cgi", mime_javascript, 0, wi_generic, wo_vpn_status, 1 },
317 #endif
318 #ifdef TCONFIG_USB
319 { "usbcmd.cgi", mime_javascript, 0, wi_generic, wo_usbcommand, 1 }, //!!TB - USB
320 #endif
321 #ifdef BLACKHOLE
322 { "blackhole.cgi", NULL, 0, wi_blackhole, NULL, 1 },
323 #endif
324 // { "test", mime_html, 0, wi_generic, wo_test, 1 },
325 { NULL, NULL, 0, NULL, NULL, 1 }
328 const aspapi_t aspapi[] = {
329 { "activeroutes", asp_activeroutes },
330 { "arplist", asp_arplist },
331 { "bandwidth", asp_bandwidth },
332 { "build_time", asp_build_time },
333 { "cgi_get", asp_cgi_get },
334 { "compmac", asp_compmac },
335 { "ctcount", asp_ctcount },
336 { "ctdump", asp_ctdump },
337 { "ddnsx", asp_ddnsx },
338 { "devlist", asp_devlist },
339 { "dhcpc_time", asp_dhcpc_time },
340 { "dns", asp_dns },
341 { "ident", asp_ident },
342 { "lanip", asp_lanip },
343 { "layer7", asp_layer7 },
344 { "link_uptime", asp_link_uptime },
345 { "lipp", asp_lipp },
346 { "netdev", asp_netdev },
347 { "notice", asp_notice },
348 { "nv", asp_nv },
349 { "nvram", asp_nvram },
350 { "nvramseq", asp_nvramseq },
351 { "psup", asp_psup },
352 { "qrate", asp_qrate },
353 { "resmsg", asp_resmsg },
354 { "rrule", asp_rrule },
355 { "statfs", asp_statfs },
356 { "sysinfo", asp_sysinfo },
357 { "time", asp_time },
358 { "upnpinfo", asp_upnpinfo },
359 { "version", asp_version },
360 { "wanstatus", asp_wanstatus },
361 { "wanup", asp_wanup },
362 { "wlchannel", asp_wlchannel },
363 { "wlclient", asp_wlclient },
364 { "wlcrssi", asp_wlcrssi },
365 { "wlnoise", asp_wlnoise },
366 { "wlnbw", asp_wlnbw },
367 { "wlnctrlsb", asp_wlnctrlsb },
368 { "wlradio", asp_wlradio },
369 { "wlscan", asp_wlscan },
370 { "wlchannels", asp_wlchannels }, //!!TB
371 #ifdef TCONFIG_USB
372 { "usbdevices", asp_usbdevices }, //!!TB - USB Support
373 #endif
374 { "css", asp_css },
375 { NULL, NULL }
378 // -----------------------------------------------------------------------------
380 static void asp_css(int argc, char **argv)
382 const char *css = nvram_safe_get("web_css");
384 if (strcmp(css, "tomato") != 0) {
385 web_printf("<link rel='stylesheet' type='text/css' href='%s.css'>", css);
389 // -----------------------------------------------------------------------------
391 const char *resmsg_get(void)
393 return webcgi_safeget("resmsg", "");
396 void resmsg_set(const char *msg)
398 webcgi_set("resmsg", strdup(msg)); // m ok
401 int resmsg_fread(const char *fname)
403 char s[256];
404 char *p;
406 f_read_string(fname, s, sizeof(s));
407 if ((p = strchr(s, '\n')) != NULL) *p = 0;
408 if (s[0]) {
409 resmsg_set(s);
410 return 1;
412 return 0;
415 static void asp_resmsg(int argc, char **argv)
417 char *p;
419 if ((p = js_string(webcgi_safeget("resmsg", (argc > 0) ? argv[0] : ""))) == NULL) return;
420 web_printf("\nresmsg='%s';\n", p);
421 free(p);
424 // ----------------------------------------------------------------------------
426 // verification... simple sanity checks. UI should verify all fields.
428 // todo: move and re-use for filtering - zzz
430 typedef union {
431 int i;
432 long l;
433 const char *s;
434 } nvset_varg_t;
436 typedef struct {
437 const char *name;
438 enum {
439 VT_NONE, // no checking
440 VT_LENGTH, // check length of string
441 VT_TEXT, // strip \r, check length of string
442 VT_RANGE, // expect an integer, check range
443 VT_IP, // expect an ip address
444 VT_MAC, // expect a mac address
445 VT_TEMP // no checks, no commit
446 } vtype;
447 nvset_varg_t va;
448 nvset_varg_t vb;
449 } nvset_t;
452 #define V_NONE VT_NONE, { }, { }
453 #define V_01 VT_RANGE, { .l = 0 }, { .l = 1 }
454 #define V_PORT VT_RANGE, { .l = 2 }, { .l = 65535 }
455 #define V_ONOFF VT_LENGTH, { .i = 2 }, { .i = 3 }
456 #define V_WORD VT_LENGTH, { .i = 1 }, { .i = 16 }
457 #define V_LENGTH(min, max) VT_LENGTH, { .i = min }, { .i = max }
458 #define V_TEXT(min, max) VT_TEXT, { .i = min }, { .i = max }
459 #define V_RANGE(min, max) VT_RANGE, { .l = min }, { .l = max }
460 #define V_IP VT_IP, { }, { }
461 #define V_OCTET VT_RANGE, { .l = 0 }, { .l = 255 }
462 #define V_NUM VT_RANGE, { .l = 0 }, { .l = 0x7FFFFFFF }
463 #define V_TEMP VT_TEMP, { }, { }
465 static const nvset_t nvset_list[] = {
467 // basic-ident
468 { "router_name", V_LENGTH(0, 32) },
469 { "wan_hostname", V_LENGTH(0, 32) },
470 { "wan_domain", V_LENGTH(0, 32) },
472 // basic-time
473 { "tm_tz", V_LENGTH(1, 64) }, // PST8PDT
474 { "tm_sel", V_LENGTH(1, 64) }, // PST8PDT
475 { "tm_dst", V_01 },
476 { "ntp_updates", V_RANGE(-1, 24) },
477 { "ntp_tdod", V_01 },
478 { "ntp_server", V_LENGTH(1, 150) }, // x y z
479 { "ntp_kiss", V_LENGTH(0, 255) },
481 // basic-static
482 { "dhcpd_static", V_LENGTH(0, 106*101)}, // 106 (max chars per entry) x 100 entries
484 // basic-ddns
485 { "ddnsx0", V_LENGTH(0, 2048) },
486 { "ddnsx1", V_LENGTH(0, 2048) },
487 { "ddnsx0_cache", V_LENGTH(0, 1) }, // only to clear
488 { "ddnsx1_cache", V_LENGTH(0, 1) },
489 { "ddnsx_ip", V_LENGTH(0, 32) },
490 { "ddnsx_save", V_01 },
491 { "ddnsx_refresh", V_RANGE(0, 365) },
493 // basic-network
494 // WAN
495 { "wan_proto", V_LENGTH(1, 16) }, // disabled, dhcp, static, pppoe, pptp, l2tp
496 { "wan_ipaddr", V_IP },
497 { "wan_netmask", V_IP },
498 { "wan_gateway", V_IP },
499 { "hb_server_ip", V_LENGTH(0, 32) },
500 { "l2tp_server_ip", V_IP },
501 { "pptp_server_ip", V_IP },
502 { "ppp_username", V_LENGTH(0, 50) },
503 { "ppp_passwd", V_LENGTH(0, 50) },
504 { "ppp_service", V_LENGTH(0, 50) },
505 { "ppp_demand", V_01 },
506 { "ppp_idletime", V_RANGE(0, 1440) },
507 { "ppp_redialperiod", V_RANGE(1, 86400) },
508 { "mtu_enable", V_01 },
509 { "wan_mtu", V_RANGE(576, 1500) },
510 { "wan_islan", V_01 },
512 // LAN
513 { "lan_ipaddr", V_IP },
514 { "lan_netmask", V_IP },
515 { "lan_gateway", V_IP },
516 { "wan_dns", V_LENGTH(0, 50) }, // ip ip ip
517 { "lan_proto", V_WORD }, // static, dhcp
518 { "dhcp_start", V_RANGE(1, 254) }, // remove !
519 { "dhcp_num", V_RANGE(1, 255) }, // remove !
520 { "dhcpd_startip", V_IP },
521 { "dhcpd_endip", V_IP },
522 { "dhcp_lease", V_RANGE(1, 10080) },
523 { "wan_wins", V_IP },
525 // wireless
526 { "wl_radio", V_01 },
527 { "wl_mode", V_LENGTH(2, 3) }, // ap, sta, wet, wds
528 { "wl_net_mode", V_LENGTH(5, 8) }, // disabled, mixed, b-only, g-only, bg-mixed, n-only [speedbooster]
529 { "wl_ssid", V_LENGTH(1, 32) },
530 { "wl_closed", V_01 },
531 { "wl_channel", V_RANGE(0, 14) }, //!!TB - 0=Auto
532 #if TOMATO_N
533 // ! update
534 #endif
536 { "security_mode2", V_LENGTH(1, 32) }, // disabled, radius, wep, wpa_personal, wpa_enterprise, wpa2_personal, wpa2_enterprise
537 { "wl_radius_ipaddr", V_IP },
538 { "wl_radius_port", V_PORT },
539 { "wl_radius_key", V_LENGTH(1, 64) },
540 { "wl_wep_bit", V_RANGE(64, 128) }, // 64 or 128
541 { "wl_passphrase", V_LENGTH(0, 20) },
542 { "wl_key", V_RANGE(1, 4) },
543 { "wl_key1", V_LENGTH(0, 26) },
544 { "wl_key2", V_LENGTH(0, 26) },
545 { "wl_key3", V_LENGTH(0, 26) },
546 { "wl_key4", V_LENGTH(0, 26) },
547 { "wl_crypto", V_LENGTH(3, 8) }, // tkip, aes, tkip+aes
548 { "wl_wpa_psk", V_LENGTH(8, 64) },
549 { "wl_wpa_gtk_rekey", V_RANGE(60, 7200) },
551 { "wl_lazywds", V_01 },
552 { "wl_wds", V_LENGTH(0, 180) }, // mac mac mac (x 10)
554 { "security_mode", V_LENGTH(1, 32) }, // disabled, radius, wpa, psk,wep, wpa2, psk2, wpa wpa2, psk psk2
555 { "wds_enable", V_01 },
556 { "wl_gmode", V_RANGE(-1, 6) },
557 { "wl_wep", V_LENGTH(1, 32) }, // off, on, restricted,tkip,aes,tkip+aes
558 { "wl_akm", V_LENGTH(0, 32) }, // wpa, wpa2, psk, psk2, wpa wpa2, psk psk2, ""
559 { "wl_auth_mode", V_LENGTH(4, 6) }, // none, radius
561 { "wl_nmode", V_NONE },
562 { "wl_nreqd", V_NONE },
563 { "wl_nbw_cap", V_RANGE(0, 2) }, // 0 - 20MHz, 1 - 40MHz, 2 - Auto
564 { "wl_nbw", V_NONE },
565 { "wl_mimo_preamble", V_WORD }, // 802.11n Preamble: mm/gf/auto/gfbcm
566 { "wl_nctrlsb", V_NONE }, // none, lower, upper
568 // basic-wfilter
569 { "wl_macmode", V_NONE }, // allow, deny, disabled
570 { "wl_maclist", V_LENGTH(0, 18*201) }, // 18 x 200 (11:22:33:44:55:66 ...)
571 { "macnames", V_LENGTH(0, 62*201) }, // 62 (12+1+48+1) x 50 (112233445566<..>) todo: re-use -- zzz
573 // advanced-ctnf
574 { "ct_max", V_RANGE(128, 10240) },
575 { "ct_tcp_timeout", V_LENGTH(20, 70) },
576 { "ct_udp_timeout", V_LENGTH(5, 15) },
577 { "ct_timeout", V_LENGTH(5, 15) },
578 { "nf_ttl", V_RANGE(-10, 10) },
579 { "nf_l7in", V_01 },
580 { "nf_rtsp", V_01 },
581 { "nf_pptp", V_01 },
582 { "nf_h323", V_01 },
583 { "nf_ftp", V_01 },
585 // advanced-dhcpdns
586 { "dhcpd_slt", V_RANGE(-1, 43200) }, // -1=infinite, 0=follow normal lease time, >=1 custom
587 { "dhcpd_dmdns", V_01 },
588 { "dhcpd_lmax", V_NUM },
589 { "dhcpd_gwmode", V_NUM },
590 { "dns_addget", V_01 },
591 { "dns_intcpt", V_01 },
592 { "dhcpc_minpkt", V_01 },
593 { "dnsmasq_custom", V_TEXT(0, 2048) },
594 // { "dnsmasq_norw", V_01 },
596 // advanced-firewall
597 { "block_wan", V_01 },
598 { "multicast_pass", V_01 },
599 { "block_loopback", V_01 },
600 { "nf_loopback", V_NUM },
601 { "ne_syncookies", V_01 },
603 // advanced-misc
604 { "wait_time", V_RANGE(3, 20) },
605 { "wan_speed", V_RANGE(0, 4) },
607 // advanced-mac
608 { "mac_wan", V_LENGTH(0, 17) },
609 { "mac_wl", V_LENGTH(0, 17) },
611 // advanced-routing
612 { "routes_static", V_LENGTH(0, 2048) },
613 { "lan_stp", V_RANGE(0, 1) },
614 { "wk_mode", V_LENGTH(1, 32) }, // gateway, router
615 #ifdef TCONFIG_ZEBRA
616 { "dr_setting", V_RANGE(0, 3) },
617 { "dr_lan_tx", V_LENGTH(0, 32) },
618 { "dr_lan_rx", V_LENGTH(0, 32) },
619 { "dr_wan_tx", V_LENGTH(0, 32) },
620 { "dr_wan_rx", V_LENGTH(0, 32) },
621 #endif
623 // advanced-wireless
624 { "wl_country", V_LENGTH(0, 64) }, // !!TB - Country code
625 { "wl_country_code", V_LENGTH(0, 4) }, // !!TB - Country code
626 { "wl_btc_mode", V_RANGE(0, 2) }, // !!TB - BT Coexistence Mode: 0 (disable), 1 (enable), 2 (preemption)
627 { "wl_afterburner", V_LENGTH(2, 4) }, // off, on, auto
628 { "wl_auth", V_01 },
629 { "wl_rateset", V_LENGTH(2, 7) }, // all, default, 12
630 { "wl_rate", V_RANGE(0, 54 * 1000 * 1000) },
631 { "wl_mrate", V_RANGE(0, 54 * 1000 * 1000) },
632 { "wl_gmode_protection",V_LENGTH(3, 4) }, // off, auto
633 { "wl_frameburst", V_ONOFF }, // off, on
634 { "wl_bcn", V_RANGE(1, 65535) },
635 { "wl_dtim", V_RANGE(1, 255) },
636 { "wl_frag", V_RANGE(256, 2346) },
637 { "wl_rts", V_RANGE(0, 2347) },
638 { "wl_ap_isolate", V_01 },
639 { "wl_plcphdr", V_LENGTH(4, 5) }, // long, short
640 { "wl_antdiv", V_RANGE(0, 3) },
641 { "wl_txant", V_RANGE(0, 3) },
642 { "wl_txpwr", V_RANGE(0, 255) },
643 { "wl_wme", V_ONOFF }, // off, on
644 { "wl_wme_no_ack", V_ONOFF }, // off, on
645 { "wl_maxassoc", V_RANGE(0, 255) },
646 { "wl_distance", V_LENGTH(0, 5) }, // "", 1-99999
647 { "wlx_hpamp", V_01 },
648 { "wlx_hperx", V_01 },
649 { "wl_reg_mode", V_LENGTH(1, 3) }, // !!TB - Regulatory: off, h, d
651 { "wl_nmode_protection", V_WORD, }, // off, auto
652 { "wl_nmcsidx", V_RANGE(-2, 32), }, // -2 - 32
654 // forward-dmz
655 { "dmz_enable", V_01 },
656 { "dmz_ipaddr", V_LENGTH(0, 15) },
657 { "dmz_sip", V_LENGTH(0, 512) },
659 // forward-upnp
660 { "upnp_enable", V_NUM },
661 { "upnp_secure", V_01 },
662 { "upnp_port", V_RANGE(0, 65535) },
663 { "upnp_ssdp_interval", V_RANGE(10, 9999) },
664 { "upnp_mnp", V_01 },
665 { "upnp_clean", V_01 },
666 { "upnp_clean_interval", V_RANGE(60, 65535) },
667 { "upnp_clean_threshold", V_RANGE(0, 9999) },
668 { "upnp_min_port_int", V_PORT },
669 { "upnp_max_port_int", V_PORT },
670 { "upnp_min_port_ext", V_PORT },
671 { "upnp_max_port_ext", V_PORT },
672 #ifndef USE_MINIUPNPD
673 // { "upnp_config", V_01 },
674 { "upnp_max_age", V_RANGE(5, 9999) },
675 #endif
677 // forward-basic
678 { "portforward", V_LENGTH(0, 4096) },
680 // forward-triggered
681 { "trigforward", V_LENGTH(0, 4096) },
684 // access restriction
685 { "rruleN", V_RANGE(0, 49) },
686 // { "rrule##", V_LENGTH(0, 2048) }, // in save_variables()
688 // admin-access
689 { "http_enable", V_01 },
690 { "https_enable", V_01 },
691 { "https_crt_save", V_01 },
692 { "https_crt_cn", V_LENGTH(0, 64) },
693 { "https_crt_gen", V_TEMP },
694 { "remote_management", V_01 },
695 { "remote_mgt_https", V_01 },
696 { "http_lanport", V_PORT },
697 { "https_lanport", V_PORT },
698 { "web_wl_filter", V_01 },
699 // { "web_favicon", V_01 },
700 { "web_css", V_LENGTH(1, 32) },
701 { "http_wanport", V_PORT },
702 { "telnetd_eas", V_01 },
703 { "telnetd_port", V_PORT },
704 { "sshd_eas", V_01 },
705 { "sshd_pass", V_01 },
706 { "sshd_port", V_PORT },
707 { "sshd_remote", V_01 },
708 { "sshd_forwarding", V_01 },
709 { "sshd_rport", V_PORT },
710 { "sshd_authkeys", V_TEXT(0, 4096) },
711 { "rmgt_sip", V_LENGTH(0, 512) },
712 { "ne_shlimit", V_TEXT(1, 50) },
714 // admin-bwm
715 { "rstats_enable", V_01 },
716 { "rstats_path", V_LENGTH(0, 48) },
717 { "rstats_stime", V_RANGE(1, 168) },
718 { "rstats_offset", V_RANGE(1, 31) },
719 { "rstats_exclude", V_LENGTH(0, 64) },
720 { "rstats_sshut", V_01 },
721 { "rstats_bak", V_01 },
723 // admin-buttons
724 { "sesx_led", V_RANGE(0, 255) }, // amber, white, aoss
725 { "sesx_b0", V_RANGE(0, 5) }, // 0-5: toggle wireless, reboot, shutdown, script, usb unmount
726 { "sesx_b1", V_RANGE(0, 5) }, // "
727 { "sesx_b2", V_RANGE(0, 5) }, // "
728 { "sesx_b3", V_RANGE(0, 5) }, // "
729 { "sesx_script", V_TEXT(0, 1024) }, //
731 // admin-debug
732 { "debug_nocommit", V_01 },
733 { "debug_cprintf", V_01 },
734 { "debug_cprintf_file", V_01 },
735 // { "debug_keepfiles", V_01 },
736 { "debug_ddns", V_01 },
737 { "debug_norestart", V_TEXT(0, 128) },
738 { "console_loglevel", V_RANGE(1, 8) },
739 { "t_cafree", V_01 },
740 { "t_hidelr", V_01 },
742 // admin-sched
743 { "sch_rboot", V_TEXT(0, 64) },
744 { "sch_rcon", V_TEXT(0, 64) },
745 { "sch_c1", V_TEXT(0, 64) },
746 { "sch_c1_cmd", V_TEXT(0, 2048) },
747 { "sch_c2", V_TEXT(0, 64) },
748 { "sch_c2_cmd", V_TEXT(0, 2048) },
749 { "sch_c3", V_TEXT(0, 64) },
750 { "sch_c3_cmd", V_TEXT(0, 2048) },
752 // admin-scripts
753 { "script_init", V_TEXT(0, 4096) },
754 { "script_shut", V_TEXT(0, 4096) },
755 { "script_fire", V_TEXT(0, 8192) },
756 { "script_wanup", V_TEXT(0, 4096) },
758 // admin-log
759 { "log_remote", V_01 },
760 { "log_remoteip", V_IP },
761 { "log_remoteport", V_PORT },
762 { "log_file", V_01 },
763 { "log_limit", V_RANGE(0, 2400) },
764 { "log_in", V_RANGE(0, 3) },
765 { "log_out", V_RANGE(0, 3) },
766 { "log_mark", V_RANGE(0, 1440) },
767 { "log_events", V_TEXT(0, 32) }, // "acre,crond,ntp"
769 // admin-cifs
770 { "cifs1", V_LENGTH(1, 1024) },
771 { "cifs2", V_LENGTH(1, 1024) },
773 // admin-jffs2
774 { "jffs2_on", V_01 },
775 { "jffs2_exec", V_LENGTH(0, 64) },
776 { "jffs2_format", V_01 },
778 // nas-usb - !!TB
779 #ifdef TCONFIG_USB
780 { "usb_enable", V_01 },
781 { "usb_uhci", V_01 },
782 { "usb_ohci", V_01 },
783 { "usb_usb2", V_01 },
784 { "usb_storage", V_01 },
785 { "usb_printer", V_01 },
786 { "usb_printer_bidirect", V_01 },
787 { "usb_fs_ext3", V_01 },
788 { "usb_fs_fat", V_01 },
789 #ifdef TCONFIG_NTFS
790 { "usb_fs_ntfs", V_01 },
791 #endif
792 { "usb_automount", V_01 },
793 { "script_usbhotplug", V_TEXT(0, 2048) },
794 { "script_usbmount", V_TEXT(0, 2048) },
795 { "script_usbumount", V_TEXT(0, 2048) },
796 #endif
798 // nas-ftp - !!TB
799 #ifdef TCONFIG_FTP
800 { "ftp_enable", V_RANGE(0, 2) },
801 { "ftp_super", V_01 },
802 { "ftp_anonymous", V_RANGE(0, 3) },
803 { "ftp_dirlist", V_RANGE(0, 2) },
804 { "ftp_port", V_PORT },
805 { "ftp_max", V_RANGE(0, 12) },
806 { "ftp_ipmax", V_RANGE(0, 12) },
807 { "ftp_staytimeout", V_RANGE(0, 65535) },
808 { "ftp_rate", V_RANGE(0, 99999) },
809 { "ftp_anonrate", V_RANGE(0, 99999) },
810 { "ftp_anonroot", V_LENGTH(0, 256) },
811 { "ftp_pubroot", V_LENGTH(0, 256) },
812 { "ftp_pvtroot", V_LENGTH(0, 256) },
813 { "ftp_users", V_LENGTH(0, 4096) },
814 { "ftp_custom", V_TEXT(0, 2048) },
815 { "ftp_sip", V_LENGTH(0, 512) },
816 { "ftp_limit", V_TEXT(1, 50) },
817 { "log_ftp", V_01 },
818 #endif
820 #ifdef TCONFIG_SAMBASRV
821 // nas-samba - !!TB
822 { "smbd_enable", V_RANGE(0, 2) },
823 { "smbd_wgroup", V_LENGTH(0, 20) },
824 { "smbd_master", V_01 },
825 { "smbd_wins", V_01 },
826 { "smbd_cpage", V_LENGTH(0, 4) },
827 { "smbd_cset", V_LENGTH(0, 20) },
828 { "smbd_loglevel", V_RANGE(0, 100) },
829 { "smbd_custom", V_TEXT(0, 2048) },
830 { "smbd_autoshare", V_RANGE(0, 3) },
831 { "smbd_shares", V_LENGTH(0, 4096) },
832 { "smbd_user", V_LENGTH(0, 50) },
833 { "smbd_passwd", V_LENGTH(0, 50) },
834 #endif
836 // qos
837 { "qos_enable", V_01 },
838 { "qos_ack", V_01 },
839 { "qos_syn", V_01 },
840 { "qos_fin", V_01 },
841 { "qos_rst", V_01 },
842 { "qos_icmp", V_01 },
843 { "qos_reset", V_01 },
844 { "qos_pfifo", V_01 }, // !!TB
845 { "qos_obw", V_RANGE(10, 999999) },
846 { "qos_ibw", V_RANGE(10, 999999) },
847 { "qos_orules", V_LENGTH(0, 4096) },
848 { "qos_default", V_RANGE(0, 9) },
849 { "qos_irates", V_LENGTH(0, 128) },
850 { "qos_orates", V_LENGTH(0, 128) },
852 { "ne_vegas", V_01 },
853 { "ne_valpha", V_NUM },
854 { "ne_vbeta", V_NUM },
855 { "ne_vgamma", V_NUM },
857 #ifdef TCONFIG_OPENVPN
858 // vpn
859 { "vpn_debug", V_01 },
860 { "vpn_server_eas", V_NONE },
861 { "vpn_server_dns", V_NONE },
862 { "vpn_server1_if", V_TEXT(3, 3) }, // tap, tun
863 { "vpn_server1_proto", V_TEXT(3, 10) }, // udp, tcp-server
864 { "vpn_server1_port", V_PORT },
865 { "vpn_server1_firewall", V_TEXT(0, 8) }, // auto, external, custom
866 { "vpn_server1_crypt", V_TEXT(0, 6) }, // tls, secret, custom
867 { "vpn_server1_comp", V_TEXT(0, 8) }, // yes, no, adaptive
868 { "vpn_server1_cipher", V_TEXT(0, 16) },
869 { "vpn_server1_dhcp", V_01 },
870 { "vpn_server1_r1", V_IP },
871 { "vpn_server1_r2", V_IP },
872 { "vpn_server1_sn", V_IP },
873 { "vpn_server1_nm", V_IP },
874 { "vpn_server1_local", V_IP },
875 { "vpn_server1_remote", V_IP },
876 { "vpn_server1_reneg", V_RANGE(-1,2147483647)},
877 { "vpn_server1_hmac", V_RANGE(-1, 2) },
878 { "vpn_server1_plan", V_01 },
879 { "vpn_server1_ccd", V_01 },
880 { "vpn_server1_c2c", V_01 },
881 { "vpn_server1_ccd_excl", V_01 },
882 { "vpn_server1_ccd_val", V_NONE },
883 { "vpn_server1_pdns", V_01 },
884 { "vpn_server1_rgw", V_01 },
885 { "vpn_server1_custom", V_NONE },
886 { "vpn_server1_static", V_NONE },
887 { "vpn_server1_ca", V_NONE },
888 { "vpn_server1_crt", V_NONE },
889 { "vpn_server1_key", V_NONE },
890 { "vpn_server1_dh", V_NONE },
891 { "vpn_server2_if", V_TEXT(3, 3) }, // tap, tun
892 { "vpn_server2_proto", V_TEXT(3, 10) }, // udp, tcp-server
893 { "vpn_server2_port", V_PORT },
894 { "vpn_server2_firewall", V_TEXT(0, 8) }, // auto, external, custom
895 { "vpn_server2_crypt", V_TEXT(0, 6) }, // tls, secret, custom
896 { "vpn_server2_comp", V_TEXT(0, 8) }, // yes, no, adaptive
897 { "vpn_server2_cipher", V_TEXT(0, 16) },
898 { "vpn_server2_dhcp", V_01 },
899 { "vpn_server2_r1", V_IP },
900 { "vpn_server2_r2", V_IP },
901 { "vpn_server2_sn", V_IP },
902 { "vpn_server2_nm", V_IP },
903 { "vpn_server2_local", V_IP },
904 { "vpn_server2_remote", V_IP },
905 { "vpn_server2_reneg", V_RANGE(-1,2147483647)},
906 { "vpn_server2_hmac", V_RANGE(-1, 2) },
907 { "vpn_server2_plan", V_01 },
908 { "vpn_server2_pdns", V_01 },
909 { "vpn_server2_rgw", V_01 },
910 { "vpn_server2_custom", V_NONE },
911 { "vpn_server2_ccd", V_01 },
912 { "vpn_server2_c2c", V_01 },
913 { "vpn_server2_ccd_excl", V_01 },
914 { "vpn_server2_ccd_val", V_NONE },
915 { "vpn_server2_static", V_NONE },
916 { "vpn_server2_ca", V_NONE },
917 { "vpn_server2_crt", V_NONE },
918 { "vpn_server2_key", V_NONE },
919 { "vpn_server2_dh", V_NONE },
920 { "vpn_client_eas", V_NONE },
921 { "vpn_client1_if", V_TEXT(3, 3) }, // tap, tun
922 { "vpn_client1_bridge", V_01 },
923 { "vpn_client1_nat", V_01 },
924 { "vpn_client1_proto", V_TEXT(3, 10) }, // udp, tcp-server
925 { "vpn_client1_addr", V_NONE },
926 { "vpn_client1_port", V_PORT },
927 { "vpn_client1_retry", V_RANGE(-1,32767) }, // -1 infinite, 0 disabled, >= 1 custom
928 { "vpn_client1_firewall", V_TEXT(0, 6) }, // auto, custom
929 { "vpn_client1_crypt", V_TEXT(0, 6) }, // tls, secret, custom
930 { "vpn_client1_comp", V_TEXT(0, 8) }, // yes, no, adaptive
931 { "vpn_client1_cipher", V_TEXT(0, 16) },
932 { "vpn_client1_local", V_IP },
933 { "vpn_client1_remote", V_IP },
934 { "vpn_client1_nm", V_IP },
935 { "vpn_client1_reneg", V_RANGE(-1,2147483647)},
936 { "vpn_client1_hmac", V_RANGE(-1, 2) },
937 { "vpn_client1_adns", V_RANGE(0, 3) },
938 { "vpn_client1_rgw", V_01 },
939 { "vpn_client1_gw", V_TEXT(0, 15) },
940 { "vpn_client1_custom", V_NONE },
941 { "vpn_client1_static", V_NONE },
942 { "vpn_client1_ca", V_NONE },
943 { "vpn_client1_crt", V_NONE },
944 { "vpn_client1_key", V_NONE },
945 { "vpn_client2_if", V_TEXT(3, 3) }, // tap, tun
946 { "vpn_client2_bridge", V_01 },
947 { "vpn_client2_nat", V_01 },
948 { "vpn_client2_proto", V_TEXT(3, 10) }, // udp, tcp-server
949 { "vpn_client2_addr", V_NONE },
950 { "vpn_client2_port", V_PORT },
951 { "vpn_client2_retry", V_RANGE(-1,32767) }, // -1 infinite, 0 disabled, >= 1 custom
952 { "vpn_client2_firewall", V_TEXT(0, 6) }, // auto, custom
953 { "vpn_client2_crypt", V_TEXT(0, 6) }, // tls, secret, custom
954 { "vpn_client2_comp", V_TEXT(0, 8) }, // yes, no, adaptive
955 { "vpn_client2_cipher", V_TEXT(0, 16) },
956 { "vpn_client2_local", V_IP },
957 { "vpn_client2_remote", V_IP },
958 { "vpn_client2_nm", V_IP },
959 { "vpn_client2_reneg", V_RANGE(-1,2147483647)},
960 { "vpn_client2_hmac", V_RANGE(-1, 2) },
961 { "vpn_client2_adns", V_RANGE(0, 3) },
962 { "vpn_client2_rgw", V_01 },
963 { "vpn_client2_gw", V_TEXT(0, 15) },
964 { "vpn_client2_custom", V_NONE },
965 { "vpn_client2_static", V_NONE },
966 { "vpn_client2_ca", V_NONE },
967 { "vpn_client2_crt", V_NONE },
968 { "vpn_client2_key", V_NONE },
969 #endif // vpn
972 ppp_static 0/1
973 ppp_static_ip IP
974 wl_enable 0/1
975 wl_wds_timeout
976 wl_maxassoc 1-256
977 wl_phytype a,b,g
978 wl_net_reauth
979 wl_preauth
980 wl_wme_ap_bk
981 wl_wme_ap_be
982 wl_wme_ap_vi
983 wl_wme_ap_vo
984 wl_wme_sta_bk
985 wl_wme_sta_be
986 wl_wme_sta_vi
987 wl_wme_sta_vo
989 port_priority_1 0-2
990 port_flow_control_1 0,1
991 port_rate_limit_1 0-8
992 port_priority_2 0-2
993 port_flow_control_2 0,1
994 port_rate_limit_2 0-8
995 port_priority_3 0-2
996 port_flow_control_3 0,1
997 port_rate_limit_3 0-8
998 port_priority_4 0-2
999 port_flow_control_4 0,1
1000 port_rate_limit_4 0-8
1001 wl_ap_ip
1002 wl_ap_ssid
1005 { NULL }
1008 static int save_variables(int write)
1010 const nvset_t *v;
1011 char *p, *e;
1012 int n;
1013 long l;
1014 unsigned u[6];
1015 int ok;
1016 char s[256];
1017 int dirty;
1018 static const char *msgf = "The field \"%s\" is invalid. Please report this problem.";
1020 dirty = 0;
1021 for (v = nvset_list; v->name; ++v) {
1022 // _dprintf("[%s] %p\n", v->name, webcgi_get((char*)v->name));
1023 if ((p = webcgi_get((char*)v->name)) == NULL) continue;
1024 ok = 1;
1025 switch (v->vtype) {
1026 case VT_TEXT:
1027 p = unix_string(p); // NOTE: p = malloc'd
1028 // drop
1029 case VT_LENGTH:
1030 n = strlen(p);
1031 if ((n < v->va.i) || (n > v->vb.i)) ok = 0;
1032 break;
1033 case VT_RANGE:
1034 l = strtol(p, &e, 10);
1035 if ((p == e) || (*e) || (l < v->va.l) || (l > v->vb.l)) ok = 0;
1036 break;
1037 case VT_IP:
1038 if ((sscanf(p, "%3u.%3u.%3u.%3u", &u[0], &u[1], &u[2], &u[3]) != 4) ||
1039 (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255)) ok = 0;
1040 break;
1041 case VT_MAC:
1042 if ((sscanf(p, "%2x:%2x:%2x:%2x:%2x:%2x", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]) != 6) ||
1043 (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255) || (u[4] > 255) || (u[5] > 255)) ok = 0;
1044 break;
1045 default:
1046 // shutup gcc
1047 break;
1049 if (!ok) {
1050 if (v->vtype == VT_TEXT) free(p);
1052 sprintf(s, msgf, v->name);
1053 resmsg_set(s);
1054 return 0;
1056 if (write) {
1057 if (!nvram_match((char *)v->name, p)) {
1058 if (v->vtype != VT_TEMP) dirty = 1;
1059 nvram_set(v->name, p);
1062 if (v->vtype == VT_TEXT) free(p);
1066 // special cases
1068 char *p1, *p2;
1069 if (((p1 = webcgi_get("set_password_1")) != NULL) && (strcmp(p1, "**********") != 0)) {
1070 if (((p2 = webcgi_get("set_password_2")) != NULL) && (strcmp(p1, p2) == 0)) {
1071 if ((write) && (!nvram_match("http_passwd", p1))) {
1072 dirty = 1;
1073 nvram_set("http_passwd", p1);
1076 else {
1077 sprintf(s, msgf, "password");
1078 resmsg_set(s);
1079 return 0;
1083 for (n = 0; n < 50; ++n) {
1084 sprintf(s, "rrule%d", n);
1085 if ((p = webcgi_get(s)) != NULL) {
1086 if (strlen(p) > 2048) {
1087 sprintf(s, msgf, s);
1088 resmsg_set(s);
1089 return 0;
1091 if ((write) && (!nvram_match(s, p))) {
1092 dirty = 1;
1093 nvram_set(s, p);
1098 return (write) ? dirty : 1;
1101 static void wo_tomato(char *url)
1103 char *v;
1104 int i;
1105 int ajax;
1106 int nvset;
1107 const char *red;
1108 int commit;
1110 // _dprintf("tomato.cgi\n");
1112 red = webcgi_safeget("_redirect", "");
1113 if (!*red) send_header(200, NULL, mime_html, 0);
1115 commit = atoi(webcgi_safeget("_commit", "1"));
1116 ajax = atoi(webcgi_safeget("_ajax", "0"));
1118 nvset = atoi(webcgi_safeget("_nvset", "1"));
1119 if (nvset) {
1120 if (!save_variables(0)) {
1121 if (ajax) {
1122 web_printf("@msg:%s", resmsg_get());
1124 else {
1125 parse_asp("error.asp");
1127 return;
1129 commit = save_variables(1) && commit;
1131 resmsg_set("Settings saved.");
1134 rboot = atoi(webcgi_safeget("_reboot", "0"));
1135 if (rboot) {
1136 parse_asp("reboot.asp");
1138 else {
1139 if (ajax) {
1140 web_printf("@msg:%s", resmsg_get());
1142 else if (atoi(webcgi_safeget("_moveip", "0"))) {
1143 parse_asp("saved-moved.asp");
1145 else if (!*red) {
1146 parse_asp("saved.asp");
1150 if (commit) {
1151 _dprintf("commit from tomato.cgi\n");
1152 nvram_commit_x();
1155 if ((v = webcgi_get("_service")) != NULL && *v != 0) {
1156 if (!*red) {
1157 if (ajax) web_printf(" Some services are being restarted...");
1158 web_close();
1160 sleep(1);
1162 if (*v == '*') {
1163 kill(1, SIGHUP);
1165 else {
1166 exec_service(v);
1170 for (i = atoi(webcgi_safeget("_sleep", "0")); i > 0; --i) sleep(1);
1172 if (*red) redirect(red);
1174 if (rboot) {
1175 web_close();
1176 sleep(1);
1177 kill(1, SIGTERM);
1182 // ----------------------------------------------------------------------------
1185 static void wo_update(char *url)
1187 const aspapi_t *api;
1188 const char *name;
1189 int argc;
1190 char *argv[16];
1191 char s[32];
1193 if ((name = webcgi_get("exec")) != NULL) {
1194 for (api = aspapi; api->name; ++api) {
1195 if (strcmp(api->name, name) == 0) {
1196 for (argc = 0; argc < 16; ++argc) {
1197 sprintf(s, "arg%d", argc);
1198 if ((argv[argc] = (char *)webcgi_get(s)) == NULL) break;
1200 api->exec(argc, argv);
1201 break;
1207 static void wo_service(char *url)
1209 int n;
1211 exec_service(webcgi_safeget("_service", ""));
1213 if ((n = atoi(webcgi_safeget("_sleep", "2"))) <= 0) n = 2;
1214 sleep(n);
1216 common_redirect();
1219 static void wo_shutdown(char *url)
1221 parse_asp("shutdown.asp");
1222 web_close();
1223 sleep(1);
1225 kill(1, SIGQUIT);
1228 static void wo_nvcommit(char *url)
1230 parse_asp("saved.asp");
1231 web_close();
1232 nvram_commit();