aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2019-04-17 12:02:10 +0100
committerRon Yorston <rmy@pobox.com>2019-04-17 12:02:10 +0100
commite4bc2cb29c5465cbec2dec1ba3b325139007d03a (patch)
tree3556d0a31ca4f75807345aef3f8a377bebf725f7
parent9752b1d082e6bdb51f8fbec5e751087a687c0062 (diff)
parent1d37186fe2361f80c821e334cc61f41e2f4eeb72 (diff)
downloadbusybox-w32-e4bc2cb29c5465cbec2dec1ba3b325139007d03a.tar.gz
busybox-w32-e4bc2cb29c5465cbec2dec1ba3b325139007d03a.tar.bz2
busybox-w32-e4bc2cb29c5465cbec2dec1ba3b325139007d03a.zip
Merge branch 'busybox' into merge
-rw-r--r--coreutils/stat.c96
-rwxr-xr-xexamples/udhcp/simple.script4
-rwxr-xr-xexamples/var_service/dhcp_if/run4
-rwxr-xr-xexamples/var_service/dhcpd_if/run4
-rwxr-xr-xexamples/var_service/ifplugd_if/run2
-rwxr-xr-xexamples/var_service/supplicant_if/run2
-rwxr-xr-xexamples/var_service/zcip_if/run4
-rw-r--r--networking/brctl.c506
-rw-r--r--networking/httpd.c376
-rw-r--r--networking/libiproute/ipaddress.c4
-rw-r--r--networking/telnetd.c14
-rw-r--r--networking/udhcp/common.c4
-rw-r--r--networking/udhcp/common.h2
-rw-r--r--networking/udhcp/d6_common.h7
-rw-r--r--networking/udhcp/d6_dhcpc.c8
-rw-r--r--networking/udhcp/d6_socket.c27
-rw-r--r--procps/top.c19
-rw-r--r--shell/ash.c79
-rw-r--r--shell/hush.c20
-rw-r--r--util-linux/chrt.c73
20 files changed, 700 insertions, 555 deletions
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 78b60603d..d9287b34e 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -168,6 +168,43 @@ static const char *human_time(time_t t)
168} 168}
169 169
170#if ENABLE_FEATURE_STAT_FILESYSTEM 170#if ENABLE_FEATURE_STAT_FILESYSTEM
171#define FS_TYPE_LIST \
172FS_TYPE(0xADFF, "affs") \
173FS_TYPE(0x1CD1, "devpts") \
174FS_TYPE(0x137D, "ext") \
175FS_TYPE(0xEF51, "ext2") \
176FS_TYPE(0xEF53, "ext2/ext3") \
177FS_TYPE(0x3153464a, "jfs") \
178FS_TYPE(0x58465342, "xfs") \
179FS_TYPE(0xF995E849, "hpfs") \
180FS_TYPE(0x9660, "isofs") \
181FS_TYPE(0x4000, "isofs") \
182FS_TYPE(0x4004, "isofs") \
183FS_TYPE(0x137F, "minix") \
184FS_TYPE(0x138F, "minix (30 char.)") \
185FS_TYPE(0x2468, "minix v2") \
186FS_TYPE(0x2478, "minix v2 (30 char.)") \
187FS_TYPE(0x4d44, "msdos") \
188FS_TYPE(0x4006, "fat") \
189FS_TYPE(0x564c, "novell") \
190FS_TYPE(0x6969, "nfs") \
191FS_TYPE(0x9fa0, "proc") \
192FS_TYPE(0x517B, "smb") \
193FS_TYPE(0x012FF7B4, "xenix") \
194FS_TYPE(0x012FF7B5, "sysv4") \
195FS_TYPE(0x012FF7B6, "sysv2") \
196FS_TYPE(0x012FF7B7, "coh") \
197IF_PLATFORM_MINGW32(FS_TYPE(0x15013346, "udf")) \
198FS_TYPE(0x00011954, "ufs") \
199FS_TYPE(0x012FD16D, "xia") \
200FS_TYPE(0x5346544e, "ntfs") \
201FS_TYPE(0x1021994, "tmpfs") \
202FS_TYPE(0x52654973, "reiserfs") \
203FS_TYPE(0x28cd3d45, "cramfs") \
204FS_TYPE(0x7275, "romfs") \
205FS_TYPE(0x858458f6, "ramfs") \
206FS_TYPE(0x73717368, "squashfs") \
207FS_TYPE(0x62656572, "sysfs")
171/* Return the type of the specified file system. 208/* Return the type of the specified file system.
172 * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris) 209 * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
173 * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2) 210 * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
@@ -175,57 +212,22 @@ static const char *human_time(time_t t)
175 */ 212 */
176static const char *human_fstype(uint32_t f_type) 213static const char *human_fstype(uint32_t f_type)
177{ 214{
178 static const struct types { 215# define FS_TYPE(type, name) type,
179 uint32_t type; 216 static const uint32_t fstype[] = {
180 const char *const fs; 217 FS_TYPE_LIST
181 } humantypes[] = {
182 { 0xADFF, "affs" },
183 { 0x1Cd1, "devpts" },
184 { 0x137D, "ext" },
185 { 0xEF51, "ext2" },
186 { 0xEF53, "ext2/ext3" },
187 { 0x3153464a, "jfs" },
188 { 0x58465342, "xfs" },
189 { 0xF995E849, "hpfs" },
190 { 0x9660, "isofs" },
191 { 0x4000, "isofs" },
192 { 0x4004, "isofs" },
193 { 0x137F, "minix" },
194 { 0x138F, "minix (30 char.)" },
195 { 0x2468, "minix v2" },
196 { 0x2478, "minix v2 (30 char.)" },
197 { 0x4d44, "msdos" },
198 { 0x4006, "fat" },
199 { 0x564c, "novell" },
200 { 0x6969, "nfs" },
201 { 0x9fa0, "proc" },
202 { 0x517B, "smb" },
203 { 0x012FF7B4, "xenix" },
204 { 0x012FF7B5, "sysv4" },
205 { 0x012FF7B6, "sysv2" },
206 { 0x012FF7B7, "coh" },
207#if ENABLE_PLATFORM_MINGW32
208 { 0x15013346, "udf" },
209#endif
210 { 0x00011954, "ufs" },
211 { 0x012FD16D, "xia" },
212 { 0x5346544e, "ntfs" },
213 { 0x1021994, "tmpfs" },
214 { 0x52654973, "reiserfs" },
215 { 0x28cd3d45, "cramfs" },
216 { 0x7275, "romfs" },
217 { 0x858458f6, "ramfs" },
218 { 0x73717368, "squashfs" },
219 { 0x62656572, "sysfs" },
220 { 0, "UNKNOWN" }
221 }; 218 };
222 219# undef FS_TYPE
220# define FS_TYPE(type, name) name"\0"
221 static const char humanname[] ALIGN1 =
222 FS_TYPE_LIST
223 "UNKNOWN";
224# undef FS_TYPE
223 int i; 225 int i;
224 226
225 for (i = 0; humantypes[i].type; ++i) 227 for (i = 0; i < ARRAY_SIZE(fstype); ++i)
226 if (humantypes[i].type == f_type) 228 if (fstype[i] == f_type)
227 break; 229 break;
228 return humantypes[i].fs; 230 return nth_string(humanname, i);
229} 231}
230 232
231/* "man statfs" says that statfsbuf->f_fsid is a mess */ 233/* "man statfs" says that statfsbuf->f_fsid is a mess */
diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script
index 44aa46ece..53974e6d6 100755
--- a/examples/udhcp/simple.script
+++ b/examples/udhcp/simple.script
@@ -55,6 +55,10 @@ case "$1" in
55 echo "Recreating $RESOLV_CONF" 55 echo "Recreating $RESOLV_CONF"
56 # If the file is a symlink somewhere (like /etc/resolv.conf 56 # If the file is a symlink somewhere (like /etc/resolv.conf
57 # pointing to /run/resolv.conf), make sure things work. 57 # pointing to /run/resolv.conf), make sure things work.
58 if test -L "$RESOLV_CONF"; then
59 # If it's a dangling symlink, try to create the target.
60 test -e "$RESOLV_CONF" || touch "$RESOLV_CONF"
61 fi
58 realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") 62 realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF")
59 tmpfile="$realconf-$$" 63 tmpfile="$realconf-$$"
60 > "$tmpfile" 64 > "$tmpfile"
diff --git a/examples/var_service/dhcp_if/run b/examples/var_service/dhcp_if/run
index aec79e027..d8f343586 100755
--- a/examples/var_service/dhcp_if/run
+++ b/examples/var_service/dhcp_if/run
@@ -8,9 +8,9 @@ pwd="$PWD"
8if="${PWD##*/dhcp_}" 8if="${PWD##*/dhcp_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev "$if" up 11ip link set dev "$if" up || { sleep 5; exit; }
12 12
13echo "* Starting udhcpc" 13echo "* Starting udhcpc on $if [$$]"
14exec \ 14exec \
15env - PATH="$PATH" \ 15env - PATH="$PATH" \
16softlimit \ 16softlimit \
diff --git a/examples/var_service/dhcpd_if/run b/examples/var_service/dhcpd_if/run
index a603bdc71..e3d1b00f4 100755
--- a/examples/var_service/dhcpd_if/run
+++ b/examples/var_service/dhcpd_if/run
@@ -8,12 +8,12 @@ pwd="$PWD"
8if="${PWD##*/dhcpd_}" 8if="${PWD##*/dhcpd_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev $if up 11ip link set dev $if up || { sleep 5; exit; }
12 12
13>>udhcpd.leases 13>>udhcpd.leases
14sed 's/^interface.*$/interface '"$if/" -i udhcpd.conf 14sed 's/^interface.*$/interface '"$if/" -i udhcpd.conf
15 15
16echo "* Starting udhcpd" 16echo "* Starting udhcpd on $if [$$]"
17exec \ 17exec \
18env - PATH="$PATH" \ 18env - PATH="$PATH" \
19softlimit \ 19softlimit \
diff --git a/examples/var_service/ifplugd_if/run b/examples/var_service/ifplugd_if/run
index 5c662f298..e7816619d 100755
--- a/examples/var_service/ifplugd_if/run
+++ b/examples/var_service/ifplugd_if/run
@@ -9,7 +9,7 @@ pwd="$PWD"
9if="${PWD##*/ifplugd_}" 9if="${PWD##*/ifplugd_}"
10 10
11echo "* Upping iface $if" 11echo "* Upping iface $if"
12ip link set dev "$if" up 12ip link set dev "$if" up || { sleep 5; exit; }
13 13
14echo "* Starting ifplugd on $if [$$]" 14echo "* Starting ifplugd on $if [$$]"
15exec \ 15exec \
diff --git a/examples/var_service/supplicant_if/run b/examples/var_service/supplicant_if/run
index 279d18af5..bc16fb606 100755
--- a/examples/var_service/supplicant_if/run
+++ b/examples/var_service/supplicant_if/run
@@ -14,7 +14,7 @@ ip link set dev "$if" up || { sleep 5; exit; }
14##echo "* Powersave disable on $if" 14##echo "* Powersave disable on $if"
15##iw dev "$if" set power_save off 15##iw dev "$if" set power_save off
16 16
17echo "* Starting wpa_supplicant" 17echo "* Starting wpa_supplicant on $if [$$]"
18exec \ 18exec \
19env - PATH="$PATH" \ 19env - PATH="$PATH" \
20softlimit \ 20softlimit \
diff --git a/examples/var_service/zcip_if/run b/examples/var_service/zcip_if/run
index 94a875465..699823246 100755
--- a/examples/var_service/zcip_if/run
+++ b/examples/var_service/zcip_if/run
@@ -8,9 +8,9 @@ pwd="$PWD"
8if="${PWD##*/zcip_}" 8if="${PWD##*/zcip_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev "$if" up 11ip link set dev "$if" up || { sleep 5; exit; }
12 12
13echo "* Starting zcip" 13echo "* Starting zcip on $if [$$]"
14exec \ 14exec \
15env - PATH="$PATH" \ 15env - PATH="$PATH" \
16softlimit \ 16softlimit \
diff --git a/networking/brctl.c b/networking/brctl.c
index ba4a714f8..f44ad9c8d 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -9,9 +9,6 @@
9 * 9 *
10 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 */ 11 */
12/* This applet currently uses only the ioctl interface and no sysfs at all.
13 * At the time of this writing this was considered a feature.
14 */
15//config:config BRCTL 12//config:config BRCTL
16//config: bool "brctl (4.7 kb)" 13//config: bool "brctl (4.7 kb)"
17//config: default y 14//config: default y
@@ -44,29 +41,34 @@
44//kbuild:lib-$(CONFIG_BRCTL) += brctl.o 41//kbuild:lib-$(CONFIG_BRCTL) += brctl.o
45 42
46//usage:#define brctl_trivial_usage 43//usage:#define brctl_trivial_usage
47//usage: "COMMAND [BRIDGE [INTERFACE]]" 44//usage: "COMMAND [BRIDGE [ARGS]]"
48//usage:#define brctl_full_usage "\n\n" 45//usage:#define brctl_full_usage "\n\n"
49//usage: "Manage ethernet bridges\n" 46//usage: "Manage ethernet bridges"
50//usage: "\nCommands:" 47//usage: "\nCommands:"
51//usage: IF_FEATURE_BRCTL_SHOW( 48//usage: IF_FEATURE_BRCTL_SHOW(
52//usage: "\n show Show a list of bridges" 49//usage: "\n show [BRIDGE]... Show bridges"
53//usage: ) 50//usage: )
54//usage: "\n addbr BRIDGE Create BRIDGE" 51//usage: "\n addbr BRIDGE Create BRIDGE"
55//usage: "\n delbr BRIDGE Delete BRIDGE" 52//usage: "\n delbr BRIDGE Delete BRIDGE"
56//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" 53//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE"
57//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" 54//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE"
58//usage: IF_FEATURE_BRCTL_FANCY( 55//usage: IF_FEATURE_BRCTL_FANCY(
59//usage: "\n setageing BRIDGE TIME Set ageing time" 56//usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off"
60//usage: "\n setfd BRIDGE TIME Set bridge forward delay" 57//usage: "\n setageing BRIDGE SECONDS Set ageing time"
61//usage: "\n sethello BRIDGE TIME Set hello time" 58//usage: "\n setfd BRIDGE SECONDS Set bridge forward delay"
62//usage: "\n setmaxage BRIDGE TIME Set max message age" 59//usage: "\n sethello BRIDGE SECONDS Set hello time"
63//usage: "\n setpathcost BRIDGE COST Set path cost" 60//usage: "\n setmaxage BRIDGE SECONDS Set max message age"
64//usage: "\n setportprio BRIDGE PRIO Set port priority"
65//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" 61//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority"
66//usage: "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off" 62//usage: "\n setportprio BRIDGE IFACE PRIO Set port priority"
63//usage: "\n setpathcost BRIDGE IFACE COST Set path cost"
67//usage: ) 64//usage: )
65// Not yet implemented:
66// hairpin BRIDGE IFACE on|off Hairpin on/off
67// showmacs BRIDGE List mac addrs
68// showstp BRIDGE Show stp info
68 69
69#include "libbb.h" 70#include "libbb.h"
71#include "common_bufsiz.h"
70#include <linux/sockios.h> 72#include <linux/sockios.h>
71#include <net/if.h> 73#include <net/if.h>
72 74
@@ -83,121 +85,114 @@
83# define SIOCBRDELIF BRCTL_DEL_IF 85# define SIOCBRDELIF BRCTL_DEL_IF
84#endif 86#endif
85 87
86
87/* Maximum number of ports supported per bridge interface. */
88#ifndef MAX_PORTS
89# define MAX_PORTS 32
90#endif
91
92/* Use internal number parsing and not the "exact" conversion. */
93/* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
94#define BRCTL_USE_INTERNAL 1
95
96#if ENABLE_FEATURE_BRCTL_FANCY 88#if ENABLE_FEATURE_BRCTL_FANCY
97/* #include <linux/if_bridge.h> 89static unsigned str_to_jiffies(const char *time_str)
98 * breaks on musl: we already included netinet/in.h in libbb.h,
99 * if we include <linux/if_bridge.h> here, we get this:
100 * In file included from /usr/include/linux/if_bridge.h:18,
101 * from networking/brctl.c:67:
102 * /usr/include/linux/in6.h:32: error: redefinition of 'struct in6_addr'
103 * /usr/include/linux/in6.h:49: error: redefinition of 'struct sockaddr_in6'
104 * /usr/include/linux/in6.h:59: error: redefinition of 'struct ipv6_mreq'
105 */
106/* From <linux/if_bridge.h> */
107#define BRCTL_GET_VERSION 0
108#define BRCTL_GET_BRIDGES 1
109#define BRCTL_ADD_BRIDGE 2
110#define BRCTL_DEL_BRIDGE 3
111#define BRCTL_ADD_IF 4
112#define BRCTL_DEL_IF 5
113#define BRCTL_GET_BRIDGE_INFO 6
114#define BRCTL_GET_PORT_LIST 7
115#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
116#define BRCTL_SET_BRIDGE_HELLO_TIME 9
117#define BRCTL_SET_BRIDGE_MAX_AGE 10
118#define BRCTL_SET_AGEING_TIME 11
119#define BRCTL_SET_GC_INTERVAL 12
120#define BRCTL_GET_PORT_INFO 13
121#define BRCTL_SET_BRIDGE_STP_STATE 14
122#define BRCTL_SET_BRIDGE_PRIORITY 15
123#define BRCTL_SET_PORT_PRIORITY 16
124#define BRCTL_SET_PATH_COST 17
125#define BRCTL_GET_FDB_ENTRIES 18
126struct __bridge_info {
127 uint64_t designated_root;
128 uint64_t bridge_id;
129 uint32_t root_path_cost;
130 uint32_t max_age;
131 uint32_t hello_time;
132 uint32_t forward_delay;
133 uint32_t bridge_max_age;
134 uint32_t bridge_hello_time;
135 uint32_t bridge_forward_delay;
136 uint8_t topology_change;
137 uint8_t topology_change_detected;
138 uint8_t root_port;
139 uint8_t stp_enabled;
140 uint32_t ageing_time;
141 uint32_t gc_interval;
142 uint32_t hello_timer_value;
143 uint32_t tcn_timer_value;
144 uint32_t topology_change_timer_value;
145 uint32_t gc_timer_value;
146};
147/* end <linux/if_bridge.h> */
148
149/* FIXME: These 4 funcs are not really clean and could be improved */
150static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv,
151 const char *time_str)
152{ 90{
153 double secs; 91 double dd;
154# if BRCTL_USE_INTERNAL
155 char *endptr; 92 char *endptr;
156 secs = /*bb_*/strtod(time_str, &endptr); 93 dd = /*bb_*/strtod(time_str, &endptr);
157 if (endptr == time_str) 94 if (endptr == time_str || dd < 0)
158# else
159 if (sscanf(time_str, "%lf", &secs) != 1)
160# endif
161 bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec"); 95 bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec");
162 tv->tv_sec = secs;
163 tv->tv_usec = 1000000 * (secs - tv->tv_sec);
164}
165 96
166static ALWAYS_INLINE unsigned long tv_to_jiffies(const struct timeval *tv) 97 dd *= 100;
167{ 98 /* For purposes of brctl,
168 unsigned long long jif; 99 * capping SECONDS by ~20 million seconds is quite enough:
169 100 */
170 jif = 1000000ULL * tv->tv_sec + tv->tv_usec; 101 if (dd > INT_MAX)
102 dd = INT_MAX;
171 103
172 return jif/10000; 104 return dd;
173} 105}
174# if 0 106#endif
175static void jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
176{
177 unsigned long long tvusec;
178 107
179 tvusec = 10000ULL*jiffies; 108#define filedata bb_common_bufsiz1
180 tv->tv_sec = tvusec/1000000; 109
181 tv->tv_usec = tvusec - 1000000 * tv->tv_sec; 110static int read_file(const char *name)
182}
183# endif
184static unsigned long str_to_jiffies(const char *time_str)
185{ 111{
186 struct timeval tv; 112 int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1);
187 bb_strtotimeval(&tv, time_str); 113 if (n < 0) {
188 return tv_to_jiffies(&tv); 114 filedata[0] = '\0';
115 } else {
116 filedata[n] = '\0';
117 if (n != 0 && filedata[n - 1] == '\n')
118 filedata[--n] = '\0';
119 }
120 return n;
189} 121}
190 122
191static void arm_ioctl(unsigned long *args, 123/* NB: we are in /sys/class/net
192 unsigned long arg0, unsigned long arg1, unsigned long arg2) 124 */
125static int show_bridge(const char *name, int need_hdr)
193{ 126{
194 args[0] = arg0; 127/* Output:
195 args[1] = arg1; 128 *bridge name bridge id STP enabled interfaces
196 args[2] = arg2; 129 *br0 8000.000000000000 no eth0
197 args[3] = 0; 130 */
198} 131 char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
132 int tabs;
133 DIR *ifaces;
134 struct dirent *ent;
135 char *sfx;
136
137#if IFNAMSIZ == 16
138 sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name);
139#else
140 sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name);
199#endif 141#endif
142 strcpy(sfx, "bridge_id");
143 if (read_file(pathbuf) < 0)
144 return -1; /* this iface is not a bridge */
145
146 if (need_hdr)
147 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
148 printf("%s\t\t", name);
149 printf("%s\t", filedata);
150
151 strcpy(sfx, "stp_state");
152 read_file(pathbuf);
153 if (LONE_CHAR(filedata, '0'))
154 strcpy(filedata, "no");
155 else
156 if (LONE_CHAR(filedata, '1'))
157 strcpy(filedata, "yes");
158 fputs(filedata, stdout);
159
160 strcpy(sfx - (sizeof("bridge/")-1), "brif");
161 tabs = 0;
162 ifaces = opendir(pathbuf);
163 if (ifaces) {
164 while ((ent = readdir(ifaces)) != NULL) {
165 if (DOT_OR_DOTDOT(ent->d_name))
166 continue; /* . or .. */
167 if (tabs)
168 printf("\t\t\t\t\t");
169 else
170 tabs = 1;
171 printf("\t\t%s\n", ent->d_name);
172 }
173 closedir(ifaces);
174 }
175 if (!tabs) /* bridge has no interfaces */
176 bb_putchar('\n');
177 return 0;
178}
200 179
180static void write_uint(const char *name, const char *leaf, unsigned val)
181{
182 char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
183 int fd, n;
184
185#if IFNAMSIZ == 16
186 sprintf(pathbuf, "%.16s/%s", name, leaf);
187#else
188 sprintf(pathbuf, "%.*s/%s", (int)IFNAMSIZ, name, leaf);
189#endif
190 fd = xopen(pathbuf, O_WRONLY);
191 n = sprintf(filedata, "%u\n", val);
192 if (write(fd, filedata, n) < 0)
193 bb_simple_perror_msg_and_die(name);
194 close(fd);
195}
201 196
202int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 197int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
203int brctl_main(int argc UNUSED_PARAM, char **argv) 198int brctl_main(int argc UNUSED_PARAM, char **argv)
@@ -207,90 +202,71 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
207 IF_FEATURE_BRCTL_FANCY( 202 IF_FEATURE_BRCTL_FANCY(
208 "stp\0" 203 "stp\0"
209 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" 204 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
210 "setpathcost\0" "setportprio\0" "setbridgeprio\0" 205 "setpathcost\0" "setportprio\0"
206 "setbridgeprio\0"
211 ) 207 )
212 IF_FEATURE_BRCTL_SHOW("show\0"); 208 IF_FEATURE_BRCTL_SHOW("show\0");
213
214 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif 209 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
215 IF_FEATURE_BRCTL_FANCY(, 210 IF_FEATURE_BRCTL_FANCY(,
216 ARG_stp, 211 ARG_stp,
217 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, 212 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
218 ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio 213 ARG_setpathcost, ARG_setportprio,
214 ARG_setbridgeprio
219 ) 215 )
220 IF_FEATURE_BRCTL_SHOW(, ARG_show) 216 IF_FEATURE_BRCTL_SHOW(, ARG_show)
221 }; 217 };
222 218
223 int fd;
224 smallint key;
225 struct ifreq ifr;
226 char *br, *brif;
227
228 argv++; 219 argv++;
229 while (*argv) { 220 if (!*argv) {
230#if ENABLE_FEATURE_BRCTL_FANCY 221 /* bare "brctl" shows --help */
231 int ifidx[MAX_PORTS]; 222 bb_show_usage();
232 unsigned long args[4]; 223 }
233 ifr.ifr_data = (char *) &args; 224
234#endif 225 xchdir("/sys/class/net");
226
227// while (*argv)
228 {
229 smallint key;
230 char *br;
235 231
236 key = index_in_strings(keywords, *argv); 232 key = index_in_strings(keywords, *argv);
237 if (key == -1) /* no match found in keywords array, bail out. */ 233 if (key == -1) /* no match found in keywords array, bail out. */
238 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); 234 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
239 argv++; 235 argv++;
240 fd = xsocket(AF_INET, SOCK_STREAM, 0);
241 236
242#if ENABLE_FEATURE_BRCTL_SHOW 237#if ENABLE_FEATURE_BRCTL_SHOW
243 if (key == ARG_show) { /* show */ 238 if (key == ARG_show) { /* show [BR]... */
244 char buf[IFNAMSIZ]; 239 DIR *net;
245 int bridx[MAX_PORTS]; 240 struct dirent *ent;
246 int i, num; 241 int need_hdr = 1;
247 arm_ioctl(args, BRCTL_GET_BRIDGES, 242 int exitcode = EXIT_SUCCESS;
248 (unsigned long) bridx, MAX_PORTS); 243
249 num = xioctl(fd, SIOCGIFBR, args); 244 if (*argv) {
250 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); 245 /* "show BR1 BR2 BR3" */
251 for (i = 0; i < num; i++) { 246 do {
252 int j, tabs; 247 if (show_bridge(*argv, need_hdr) >= 0) {
253 struct __bridge_info bi; 248 need_hdr = 0;
254 unsigned char *x; 249 } else {
255 250 bb_error_msg("bridge %s does not exist", *argv);
256 if (!if_indextoname(bridx[i], buf)) 251//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6
257 bb_perror_msg_and_die("can't get bridge name for index %d", i); 252//says this instead: "device eth0 is not a bridge"
258 strncpy_IFNAMSIZ(ifr.ifr_name, buf); 253 exitcode = EXIT_FAILURE;
259 254 }
260 arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, 255 } while (*++argv != NULL);
261 (unsigned long) &bi, 0); 256 return exitcode;
262 xioctl(fd, SIOCDEVPRIVATE, &ifr);
263 printf("%s\t\t", buf);
264
265 /* print bridge id */
266 x = (unsigned char *) &bi.bridge_id;
267 for (j = 0; j < 8; j++) {
268 printf("%02x", x[j]);
269 if (j == 1)
270 bb_putchar('.');
271 }
272 printf(bi.stp_enabled ? "\tyes" : "\tno");
273
274 /* print interface list */
275 arm_ioctl(args, BRCTL_GET_PORT_LIST,
276 (unsigned long) ifidx, MAX_PORTS);
277 xioctl(fd, SIOCDEVPRIVATE, &ifr);
278 tabs = 0;
279 for (j = 0; j < MAX_PORTS; j++) {
280 if (!ifidx[j])
281 continue;
282 if (!if_indextoname(ifidx[j], buf))
283 bb_perror_msg_and_die("can't get interface name for index %d", j);
284 if (tabs)
285 printf("\t\t\t\t\t");
286 else
287 tabs = 1;
288 printf("\t\t%s\n", buf);
289 }
290 if (!tabs) /* bridge has no interfaces */
291 bb_putchar('\n');
292 } 257 }
293 goto done; 258
259 /* "show" (if no ifaces, shows nothing, not even header) */
260 net = xopendir(".");
261 while ((ent = readdir(net)) != NULL) {
262 if (DOT_OR_DOTDOT(ent->d_name))
263 continue; /* . or .. */
264 if (show_bridge(ent->d_name, need_hdr) >= 0)
265 need_hdr = 0;
266 }
267 if (ENABLE_FEATURE_CLEAN_UP)
268 closedir(net);
269 return exitcode;
294 } 270 }
295#endif 271#endif
296 272
@@ -299,28 +275,29 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
299 275
300 br = *argv++; 276 br = *argv++;
301 277
302 if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */ 278 if (key == ARG_addbr || key == ARG_delbr) {
279 /* addbr or delbr */
280 /* brctl from bridge-utils 1.6 still uses ioctl
281 * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses
282 */
283 int fd = xsocket(AF_INET, SOCK_STREAM, 0);
303 ioctl_or_perror_and_die(fd, 284 ioctl_or_perror_and_die(fd,
304 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, 285 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
305 br, "bridge %s", br); 286 br, "bridge %s", br
306 goto done; 287 );
288 //close(fd);
289 //goto done;
290 /* bridge-utils 1.6 simply ignores trailing args:
291 * "brctl addbr BR1 ARGS" ignores ARGS
292 */
293 if (ENABLE_FEATURE_CLEAN_UP)
294 close(fd);
295 return EXIT_SUCCESS;
307 } 296 }
308 297
309 if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ 298 if (!*argv) /* all but 'addbr/delbr' need at least two arguments */
310 bb_show_usage(); 299 bb_show_usage();
311 300
312 strncpy_IFNAMSIZ(ifr.ifr_name, br);
313 if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
314 brif = *argv;
315 ifr.ifr_ifindex = if_nametoindex(brif);
316 if (!ifr.ifr_ifindex) {
317 bb_perror_msg_and_die("iface %s", brif);
318 }
319 ioctl_or_perror_and_die(fd,
320 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
321 &ifr, "bridge %s", br);
322 goto done_next_argv;
323 }
324#if ENABLE_FEATURE_BRCTL_FANCY 301#if ENABLE_FEATURE_BRCTL_FANCY
325 if (key == ARG_stp) { /* stp */ 302 if (key == ARG_stp) { /* stp */
326 static const char no_yes[] ALIGN1 = 303 static const char no_yes[] ALIGN1 =
@@ -330,65 +307,102 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
330 if (onoff < 0) 307 if (onoff < 0)
331 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); 308 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
332 onoff = (unsigned)onoff / 4; 309 onoff = (unsigned)onoff / 4;
333 arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0); 310 write_uint(br, "bridge/stp_state", onoff);
334 goto fire; 311 //goto done_next_argv;
312 return EXIT_SUCCESS;
335 } 313 }
314
336 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ 315 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
337 static const uint8_t ops[] ALIGN1 = { 316 /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time
338 BRCTL_SET_AGEING_TIME, /* ARG_setageing */ 317 * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay
339 BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd */ 318 * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time
340 BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */ 319 * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age
341 BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */ 320 */
342 }; 321 write_uint(br,
343 arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0); 322 nth_string(
344 goto fire; 323 "bridge/ageing_time" "\0" /* ARG_setageing */
324 "bridge/forward_delay""\0" /* ARG_setfd */
325 "bridge/hello_time" "\0" /* ARG_sethello */
326 "bridge/max_age", /* ARG_setmaxage */
327 key - ARG_setageing
328 ),
329 str_to_jiffies(*argv)
330 );
331 //goto done_next_argv;
332 return EXIT_SUCCESS;
345 } 333 }
334
335 if (key == ARG_setbridgeprio) {
336 write_uint(br, "bridge/priority", xatoi_positive(*argv));
337 //goto done_next_argv;
338 return EXIT_SUCCESS;
339 }
340
346 if (key == ARG_setpathcost 341 if (key == ARG_setpathcost
347 || key == ARG_setportprio 342 || key == ARG_setportprio
348 || key == ARG_setbridgeprio
349 ) { 343 ) {
350 static const uint8_t ops[] ALIGN1 = { 344 if (!argv[1])
351 BRCTL_SET_PATH_COST, /* ARG_setpathcost */ 345 bb_show_usage();
352 BRCTL_SET_PORT_PRIORITY, /* ARG_setportprio */ 346 /* BR is not used (and ignored!) for these commands:
353 BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */ 347 * "setpathcost BR PORT N" writes "N\n" to
354 }; 348 * /sys/class/net/PORT/brport/path_cost
355 int port = -1; 349 * "setportprio BR PORT N" writes "N\n" to
356 unsigned arg1, arg2; 350 * /sys/class/net/PORT/brport/priority
357 351 */
358 if (key != ARG_setbridgeprio) { 352 write_uint(argv[0],
359 /* get portnum */ 353 nth_string(
360 unsigned i; 354 "brport/path_cost" "\0" /* ARG_setpathcost */
361 355 "brport/priority", /* ARG_setportprio */
362 port = if_nametoindex(*argv++); 356 key - ARG_setpathcost
363 if (!port) 357 ),
364 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, "port"); 358 xatoi_positive(argv[1])
365 memset(ifidx, 0, sizeof ifidx); 359 );
366 arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx, 360 //argv++;
367 MAX_PORTS); 361 //goto done_next_argv;
368 xioctl(fd, SIOCDEVPRIVATE, &ifr); 362 return EXIT_SUCCESS;
369 for (i = 0; i < MAX_PORTS; i++) {
370 if (ifidx[i] == port) {
371 port = i;
372 break;
373 }
374 }
375 }
376 arg1 = port;
377 arg2 = xatoi_positive(*argv);
378 if (key == ARG_setbridgeprio) {
379 arg1 = arg2;
380 arg2 = 0;
381 }
382 arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2);
383 } 363 }
384 fire: 364
385 /* Execute the previously set command */ 365/* TODO: "showmacs BR"
386 xioctl(fd, SIOCDEVPRIVATE, &ifr); 366 * port no\tmac addr\t\tis local?\tageing timer
367 * <sp><sp>1\txx:xx:xx:xx:xx:xx\tno\t\t<sp><sp><sp>1.31
368 * port no mac addr is local? ageing timer
369 * 1 xx:xx:xx:xx:xx:xx no 1.31
370 * Read fixed-sized records from /sys/class/net/BR/brforward:
371 * struct __fdb_entry {
372 * uint8_t mac_addr[ETH_ALEN];
373 * uint8_t port_no; //lsb
374 * uint8_t is_local;
375 * uint32_t ageing_timer_value;
376 * uint8_t port_hi;
377 * uint8_t pad0;
378 * uint16_t unused;
379 * };
380 */
387#endif 381#endif
388 done_next_argv: 382 /* always true: if (key == ARG_addif || key == ARG_delif) */ {
389 argv++; 383 /* addif or delif */
390 done: 384 struct ifreq ifr;
391 close(fd); 385 int fd = xsocket(AF_INET, SOCK_STREAM, 0);
386
387 strncpy_IFNAMSIZ(ifr.ifr_name, br);
388 ifr.ifr_ifindex = if_nametoindex(*argv);
389 if (ifr.ifr_ifindex == 0) {
390 bb_perror_msg_and_die("iface %s", *argv);
391 }
392 ioctl_or_perror_and_die(fd,
393 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
394 &ifr, "bridge %s", br
395 );
396 //close(fd);
397 //goto done_next_argv;
398 if (ENABLE_FEATURE_CLEAN_UP)
399 close(fd);
400 return EXIT_SUCCESS;
401 }
402
403// done_next_argv:
404// argv++;
405// done:
392 } 406 }
393 407
394 return EXIT_SUCCESS; 408 return EXIT_SUCCESS;
diff --git a/networking/httpd.c b/networking/httpd.c
index b52526a78..2b0acd7dc 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -95,9 +95,7 @@
95 * If -c is not set, an attempt will be made to open the default 95 * If -c is not set, an attempt will be made to open the default
96 * root configuration file. If -c is set and the file is not found, the 96 * root configuration file. If -c is set and the file is not found, the
97 * server exits with an error. 97 * server exits with an error.
98 *
99 */ 98 */
100 /* TODO: use TCP_CORK, parse_config() */
101//config:config HTTPD 99//config:config HTTPD
102//config: bool "httpd (32 kb)" 100//config: bool "httpd (32 kb)"
103//config: default y 101//config: default y
@@ -246,6 +244,8 @@
246//usage: "\n -e STRING HTML encode STRING" 244//usage: "\n -e STRING HTML encode STRING"
247//usage: "\n -d STRING URL decode STRING" 245//usage: "\n -d STRING URL decode STRING"
248 246
247/* TODO: use TCP_CORK, parse_config() */
248
249#include "libbb.h" 249#include "libbb.h"
250#include "common_bufsiz.h" 250#include "common_bufsiz.h"
251#if ENABLE_PAM 251#if ENABLE_PAM
@@ -267,6 +267,7 @@
267#define DEBUG 0 267#define DEBUG 0
268 268
269#define IOBUF_SIZE 8192 269#define IOBUF_SIZE 8192
270#define MAX_HTTP_HEADERS_SIZE ((8*1024) - 16)
270#if PIPE_BUF >= IOBUF_SIZE 271#if PIPE_BUF >= IOBUF_SIZE
271# error "PIPE_BUF >= IOBUF_SIZE" 272# error "PIPE_BUF >= IOBUF_SIZE"
272#endif 273#endif
@@ -305,6 +306,13 @@ typedef struct Htaccess_Proxy {
305 char *url_to; 306 char *url_to;
306} Htaccess_Proxy; 307} Htaccess_Proxy;
307 308
309typedef enum CGI_type {
310 CGI_NONE = 0,
311 CGI_NORMAL,
312 CGI_INDEX,
313 CGI_INTERPRETER,
314} CGI_type;
315
308enum { 316enum {
309 HTTP_OK = 200, 317 HTTP_OK = 200,
310 HTTP_PARTIAL_CONTENT = 206, 318 HTTP_PARTIAL_CONTENT = 206,
@@ -316,6 +324,7 @@ enum {
316 HTTP_REQUEST_TIMEOUT = 408, 324 HTTP_REQUEST_TIMEOUT = 408,
317 HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */ 325 HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */
318 HTTP_INTERNAL_SERVER_ERROR = 500, 326 HTTP_INTERNAL_SERVER_ERROR = 500,
327 HTTP_ENTITY_TOO_LARGE = 413,
319 HTTP_CONTINUE = 100, 328 HTTP_CONTINUE = 100,
320#if 0 /* future use */ 329#if 0 /* future use */
321 HTTP_SWITCHING_PROTOCOLS = 101, 330 HTTP_SWITCHING_PROTOCOLS = 101,
@@ -347,6 +356,7 @@ static const uint16_t http_response_type[] ALIGN2 = {
347 HTTP_BAD_REQUEST, 356 HTTP_BAD_REQUEST,
348 HTTP_FORBIDDEN, 357 HTTP_FORBIDDEN,
349 HTTP_INTERNAL_SERVER_ERROR, 358 HTTP_INTERNAL_SERVER_ERROR,
359 HTTP_ENTITY_TOO_LARGE,
350#if 0 /* not implemented */ 360#if 0 /* not implemented */
351 HTTP_CREATED, 361 HTTP_CREATED,
352 HTTP_ACCEPTED, 362 HTTP_ACCEPTED,
@@ -377,6 +387,7 @@ static const struct {
377 { "Bad Request", "Unsupported method" }, 387 { "Bad Request", "Unsupported method" },
378 { "Forbidden", "" }, 388 { "Forbidden", "" },
379 { "Internal Server Error", "Internal Server Error" }, 389 { "Internal Server Error", "Internal Server Error" },
390 { "Entity Too Large", "Entity Too Large" },
380#if 0 /* not implemented */ 391#if 0 /* not implemented */
381 { "Created" }, 392 { "Created" },
382 { "Accepted" }, 393 { "Accepted" },
@@ -396,12 +407,11 @@ struct globals {
396 /* client can handle gzip / we are going to send gzip */ 407 /* client can handle gzip / we are going to send gzip */
397 smallint content_gzip; 408 smallint content_gzip;
398#endif 409#endif
399 unsigned rmt_ip; /* used for IP-based allow/deny rules */
400 time_t last_mod; 410 time_t last_mod;
401 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ 411 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */
402 const char *bind_addr_or_port; 412 const char *bind_addr_or_port;
403 413
404 const char *g_query; 414 char *g_query;
405 const char *opt_c_configFile; 415 const char *opt_c_configFile;
406 const char *home_httpd; 416 const char *home_httpd;
407 const char *index_page; 417 const char *index_page;
@@ -412,11 +422,6 @@ struct globals {
412 422
413 IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;) 423 IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
414 IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) 424 IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
415 IF_FEATURE_HTTPD_CGI(char *referer;)
416 IF_FEATURE_HTTPD_CGI(char *user_agent;)
417 IF_FEATURE_HTTPD_CGI(char *host;)
418 IF_FEATURE_HTTPD_CGI(char *http_accept;)
419 IF_FEATURE_HTTPD_CGI(char *http_accept_language;)
420 425
421 off_t file_size; /* -1 - unknown */ 426 off_t file_size; /* -1 - unknown */
422#if ENABLE_FEATURE_HTTPD_RANGES 427#if ENABLE_FEATURE_HTTPD_RANGES
@@ -452,7 +457,6 @@ struct globals {
452#else 457#else
453# define content_gzip 0 458# define content_gzip 0
454#endif 459#endif
455#define rmt_ip (G.rmt_ip )
456#define bind_addr_or_port (G.bind_addr_or_port) 460#define bind_addr_or_port (G.bind_addr_or_port)
457#define g_query (G.g_query ) 461#define g_query (G.g_query )
458#define opt_c_configFile (G.opt_c_configFile ) 462#define opt_c_configFile (G.opt_c_configFile )
@@ -1194,37 +1198,39 @@ static void send_headers_and_exit(int responseNum)
1194} 1198}
1195 1199
1196/* 1200/*
1197 * Read from the socket until '\n' or EOF. '\r' chars are removed. 1201 * Read from the socket until '\n' or EOF.
1202 * '\r' chars are removed.
1198 * '\n' is replaced with NUL. 1203 * '\n' is replaced with NUL.
1199 * Return number of characters read or 0 if nothing is read 1204 * Return number of characters read or 0 if nothing is read
1200 * ('\r' and '\n' are not counted). 1205 * ('\r' and '\n' are not counted).
1201 * Data is returned in iobuf. 1206 * Data is returned in iobuf.
1202 */ 1207 */
1203static int get_line(void) 1208static unsigned get_line(void)
1204{ 1209{
1205 int count = 0; 1210 unsigned count;
1206 char c; 1211 char c;
1207 1212
1208 alarm(HEADER_READ_TIMEOUT); 1213 alarm(HEADER_READ_TIMEOUT);
1214 count = 0;
1209 while (1) { 1215 while (1) {
1210 if (hdr_cnt <= 0) { 1216 if (hdr_cnt <= 0) {
1211 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); 1217 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf);
1212 if (hdr_cnt <= 0) 1218 if (hdr_cnt <= 0)
1213 break; 1219 goto ret;
1214 hdr_ptr = hdr_buf; 1220 hdr_ptr = hdr_buf;
1215 } 1221 }
1216 iobuf[count] = c = *hdr_ptr++;
1217 hdr_cnt--; 1222 hdr_cnt--;
1218 1223 c = *hdr_ptr++;
1219 if (c == '\r') 1224 if (c == '\r')
1220 continue; 1225 continue;
1221 if (c == '\n') { 1226 if (c == '\n')
1222 iobuf[count] = '\0';
1223 break; 1227 break;
1224 } 1228 iobuf[count] = c;
1225 if (count < (IOBUF_SIZE - 1)) /* check overflow */ 1229 if (count < (IOBUF_SIZE - 1)) /* check overflow */
1226 count++; 1230 count++;
1227 } 1231 }
1232 ret:
1233 iobuf[count] = '\0';
1228 return count; 1234 return count;
1229} 1235}
1230 1236
@@ -1437,23 +1443,17 @@ static void setenv1(const char *name, const char *value)
1437 * const char *url The requested URL (with leading /). 1443 * const char *url The requested URL (with leading /).
1438 * const char *orig_uri The original URI before rewriting (if any) 1444 * const char *orig_uri The original URI before rewriting (if any)
1439 * int post_len Length of the POST body. 1445 * int post_len Length of the POST body.
1440 * const char *cookie For set HTTP_COOKIE.
1441 * const char *content_type For set CONTENT_TYPE.
1442 */ 1446 */
1443static void send_cgi_and_exit( 1447static void send_cgi_and_exit(
1444 const char *url, 1448 const char *url,
1445 const char *orig_uri, 1449 const char *orig_uri,
1446 const char *request, 1450 const char *request,
1447 int post_len, 1451 int post_len) NORETURN;
1448 const char *cookie,
1449 const char *content_type) NORETURN;
1450static void send_cgi_and_exit( 1452static void send_cgi_and_exit(
1451 const char *url, 1453 const char *url,
1452 const char *orig_uri, 1454 const char *orig_uri,
1453 const char *request, 1455 const char *request,
1454 int post_len, 1456 int post_len)
1455 const char *cookie,
1456 const char *content_type)
1457{ 1457{
1458 struct fd_pair fromCgi; /* CGI -> httpd pipe */ 1458 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1459 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1459 struct fd_pair toCgi; /* httpd -> CGI pipe */
@@ -1531,26 +1531,14 @@ static void send_cgi_and_exit(
1531#endif 1531#endif
1532 } 1532 }
1533 } 1533 }
1534 setenv1("HTTP_USER_AGENT", G.user_agent);
1535 if (G.http_accept)
1536 setenv1("HTTP_ACCEPT", G.http_accept);
1537 if (G.http_accept_language)
1538 setenv1("HTTP_ACCEPT_LANGUAGE", G.http_accept_language);
1539 if (post_len) 1534 if (post_len)
1540 putenv(xasprintf("CONTENT_LENGTH=%u", post_len)); 1535 putenv(xasprintf("CONTENT_LENGTH=%u", post_len));
1541 if (cookie)
1542 setenv1("HTTP_COOKIE", cookie);
1543 if (content_type)
1544 setenv1("CONTENT_TYPE", content_type);
1545#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1536#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
1546 if (remoteuser) { 1537 if (remoteuser) {
1547 setenv1("REMOTE_USER", remoteuser); 1538 setenv1("REMOTE_USER", remoteuser);
1548 putenv((char*)"AUTH_TYPE=Basic"); 1539 putenv((char*)"AUTH_TYPE=Basic");
1549 } 1540 }
1550#endif 1541#endif
1551 if (G.referer)
1552 setenv1("HTTP_REFERER", G.referer);
1553 setenv1("HTTP_HOST", G.host); /* set to "" if NULL */
1554 /* setenv1("SERVER_NAME", safe_gethostname()); - don't do this, 1542 /* setenv1("SERVER_NAME", safe_gethostname()); - don't do this,
1555 * just run "env SERVER_NAME=xyz httpd ..." instead */ 1543 * just run "env SERVER_NAME=xyz httpd ..." instead */
1556 1544
@@ -1817,7 +1805,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1817 log_and_exit(); 1805 log_and_exit();
1818} 1806}
1819 1807
1820static int checkPermIP(void) 1808static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
1821{ 1809{
1822 Htaccess_IP *cur; 1810 Htaccess_IP *cur;
1823 1811
@@ -1836,11 +1824,15 @@ static int checkPermIP(void)
1836 (unsigned char)(cur->mask) 1824 (unsigned char)(cur->mask)
1837 ); 1825 );
1838#endif 1826#endif
1839 if ((rmt_ip & cur->mask) == cur->ip) 1827 if ((remote_ip & cur->mask) == cur->ip) {
1840 return (cur->allow_deny == 'A'); /* A -> 1 */ 1828 if (cur->allow_deny == 'A')
1829 return;
1830 send_headers_and_exit(HTTP_FORBIDDEN);
1831 }
1841 } 1832 }
1842 1833
1843 return !flg_deny_all; /* depends on whether we saw "D:*" */ 1834 if (flg_deny_all) /* depends on whether we saw "D:*" */
1835 send_headers_and_exit(HTTP_FORBIDDEN);
1844} 1836}
1845 1837
1846#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1838#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -2077,12 +2069,15 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2077 char *urlcopy; 2069 char *urlcopy;
2078 char *urlp; 2070 char *urlp;
2079 char *tptr; 2071 char *tptr;
2072 unsigned remote_ip;
2073#if ENABLE_FEATURE_HTTPD_CGI
2074 unsigned total_headers_len;
2075#endif
2080#if ENABLE_FEATURE_HTTPD_CGI 2076#if ENABLE_FEATURE_HTTPD_CGI
2081 static const char request_HEAD[] ALIGN1 = "HEAD"; 2077 static const char request_HEAD[] ALIGN1 = "HEAD";
2082 const char *prequest; 2078 const char *prequest;
2083 char *cookie = NULL;
2084 char *content_type = NULL;
2085 unsigned long length = 0; 2079 unsigned long length = 0;
2080 enum CGI_type cgi_type = CGI_NONE;
2086#elif ENABLE_FEATURE_HTTPD_PROXY 2081#elif ENABLE_FEATURE_HTTPD_PROXY
2087#define prequest request_GET 2082#define prequest request_GET
2088 unsigned long length = 0; 2083 unsigned long length = 0;
@@ -2090,29 +2085,23 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2090#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2085#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
2091 smallint authorized = -1; 2086 smallint authorized = -1;
2092#endif 2087#endif
2093 smallint ip_allowed;
2094 char http_major_version; 2088 char http_major_version;
2095#if ENABLE_FEATURE_HTTPD_PROXY 2089 char *HTTP_slash;
2096 char http_minor_version;
2097 char *header_buf = header_buf; /* for gcc */
2098 char *header_ptr = header_ptr;
2099 Htaccess_Proxy *proxy_entry;
2100#endif
2101 2090
2102 /* Allocation of iobuf is postponed until now 2091 /* Allocation of iobuf is postponed until now
2103 * (IOW, server process doesn't need to waste 8k) */ 2092 * (IOW, server process doesn't need to waste 8k) */
2104 iobuf = xmalloc(IOBUF_SIZE); 2093 iobuf = xmalloc(IOBUF_SIZE);
2105 2094
2106 rmt_ip = 0; 2095 remote_ip = 0;
2107 if (fromAddr->u.sa.sa_family == AF_INET) { 2096 if (fromAddr->u.sa.sa_family == AF_INET) {
2108 rmt_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); 2097 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
2109 } 2098 }
2110#if ENABLE_FEATURE_IPV6 2099#if ENABLE_FEATURE_IPV6
2111 if (fromAddr->u.sa.sa_family == AF_INET6 2100 if (fromAddr->u.sa.sa_family == AF_INET6
2112 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 2101 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
2113 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 2102 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
2114 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) 2103 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
2115 rmt_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); 2104 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
2116#endif 2105#endif
2117 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { 2106 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
2118 /* NB: can be NULL (user runs httpd -i by hand?) */ 2107 /* NB: can be NULL (user runs httpd -i by hand?) */
@@ -2125,6 +2114,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2125 if (verbose > 2) 2114 if (verbose > 2)
2126 bb_error_msg("connected"); 2115 bb_error_msg("connected");
2127 } 2116 }
2117 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
2128 2118
2129 /* Install timeout handler. get_line() needs it. */ 2119 /* Install timeout handler. get_line() needs it. */
2130 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); 2120 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
@@ -2159,30 +2149,58 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2159 send_headers_and_exit(HTTP_BAD_REQUEST); 2149 send_headers_and_exit(HTTP_BAD_REQUEST);
2160 2150
2161 /* Find end of URL and parse HTTP version, if any */ 2151 /* Find end of URL and parse HTTP version, if any */
2162 http_major_version = '0'; 2152//TODO: maybe just reject all queries which have no " HTTP/xyz" suffix?
2163 IF_FEATURE_HTTPD_PROXY(http_minor_version = '0';) 2153//Then 'http_major_version' can be deleted
2164 tptr = strchrnul(urlp, ' '); 2154 http_major_version = ('0' - 1); /* "less than 0th" version */
2155 HTTP_slash = strchrnul(urlp, ' ');
2165 /* Is it " HTTP/"? */ 2156 /* Is it " HTTP/"? */
2166 if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0) { 2157 if (HTTP_slash[0] && strncmp(HTTP_slash + 1, HTTP_200, 5) == 0) {
2167 http_major_version = tptr[6]; 2158 http_major_version = HTTP_slash[6];
2168 IF_FEATURE_HTTPD_PROXY(http_minor_version = tptr[8];) 2159 *HTTP_slash++ = '\0';
2169 } 2160 }
2170 *tptr = '\0';
2171 2161
2172 /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ 2162 /* Copy URL from after "GET "/"POST " to stack-allocated char[] */
2173 urlcopy = alloca((tptr - urlp) + 2 + strlen(index_page)); 2163 urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page));
2174 /*if (urlcopy == NULL) 2164 /*if (urlcopy == NULL)
2175 * send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/ 2165 * send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/
2176 strcpy(urlcopy, urlp); 2166 strcpy(urlcopy, urlp);
2177 /* NB: urlcopy ptr is never changed after this */ 2167 /* NB: urlcopy ptr is never changed after this */
2178 2168
2179 /* Extract url args if present */ 2169#if ENABLE_FEATURE_HTTPD_PROXY
2180 /* g_query = NULL; - already is */ 2170 {
2181 tptr = strchr(urlcopy, '?'); 2171 int proxy_fd;
2182 if (tptr) { 2172 len_and_sockaddr *lsa;
2183 *tptr++ = '\0'; 2173 Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy);
2184 g_query = tptr; 2174
2175 if (proxy_entry) {
2176 lsa = host2sockaddr(proxy_entry->host_port, 80);
2177 if (!lsa)
2178 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2179 proxy_fd = socket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
2180 if (proxy_fd < 0)
2181 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2182 if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0)
2183 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2184 /* Config directive was of the form:
2185 * P:/url:[http://]hostname[:port]/new/path
2186 * When /urlSFX is requested, reverse proxy it
2187 * to http://hostname[:port]/new/pathSFX
2188 */
2189 fdprintf(proxy_fd, "%s %s%s %s\r\n",
2190 prequest, /* "GET" or "POST" */
2191 proxy_entry->url_to, /* "/new/path" */
2192 urlcopy + strlen(proxy_entry->url_from), /* "SFX" */
2193 HTTP_slash /* HTTP/xyz" or "" */
2194 );
2195 cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX);
2196 }
2185 } 2197 }
2198#endif
2199
2200 /* Extract url args if present */
2201 g_query = strchr(urlcopy, '?');
2202 if (g_query)
2203 *g_query++ = '\0';
2186 2204
2187 /* Decode URL escape sequences */ 2205 /* Decode URL escape sequences */
2188 tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1); 2206 tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1);
@@ -2222,7 +2240,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2222 } 2240 }
2223 } 2241 }
2224 *++urlp = *tptr; 2242 *++urlp = *tptr;
2225 if (*urlp == '\0') 2243 if (*tptr == '\0')
2226 break; 2244 break;
2227 next_char: 2245 next_char:
2228 tptr++; 2246 tptr++;
@@ -2240,47 +2258,87 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2240 bb_error_msg("url:%s", urlcopy); 2258 bb_error_msg("url:%s", urlcopy);
2241 2259
2242 tptr = urlcopy; 2260 tptr = urlcopy;
2243 ip_allowed = checkPermIP(); 2261 while ((tptr = strchr(tptr + 1, '/')) != NULL) {
2244 while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) {
2245 /* have path1/path2 */ 2262 /* have path1/path2 */
2246 *tptr = '\0'; 2263 *tptr = '\0';
2247 if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { 2264 if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) {
2248 /* may have subdir config */ 2265 /* may have subdir config */
2249 parse_conf(urlcopy + 1, SUBDIR_PARSE); 2266 parse_conf(urlcopy + 1, SUBDIR_PARSE);
2250 ip_allowed = checkPermIP(); 2267 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
2251 } 2268 }
2252 *tptr = '/'; 2269 *tptr = '/';
2253 } 2270 }
2254 2271
2255#if ENABLE_FEATURE_HTTPD_PROXY 2272 tptr = urlcopy + 1; /* skip first '/' */
2256 proxy_entry = find_proxy_entry(urlcopy); 2273
2257 if (proxy_entry) 2274#if ENABLE_FEATURE_HTTPD_CGI
2258 header_buf = header_ptr = xmalloc(IOBUF_SIZE); 2275 if (is_prefixed_with(tptr, "cgi-bin/")) {
2276 if (tptr[8] == '\0') {
2277 /* protect listing "cgi-bin/" */
2278 send_headers_and_exit(HTTP_FORBIDDEN);
2279 }
2280 cgi_type = CGI_NORMAL;
2281 }
2282#endif
2283
2284 if (urlp[-1] == '/') {
2285 /* When index_page string is appended to <dir>/ URL, it overwrites
2286 * the query string. If we fall back to call /cgi-bin/index.cgi,
2287 * query string would be lost and not available to the CGI.
2288 * Work around it by making a deep copy.
2289 */
2290 if (ENABLE_FEATURE_HTTPD_CGI)
2291 g_query = xstrdup(g_query); /* ok for NULL too */
2292 strcpy(urlp, index_page);
2293 }
2294 if (stat(tptr, &sb) == 0) {
2295#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
2296 char *suffix = strrchr(tptr, '.');
2297 if (suffix) {
2298 Htaccess *cur;
2299 for (cur = script_i; cur; cur = cur->next) {
2300 if (strcmp(cur->before_colon + 1, suffix) == 0) {
2301 cgi_type = CGI_INTERPRETER;
2302 break;
2303 }
2304 }
2305 }
2306#endif
2307 if (!found_moved_temporarily) {
2308 file_size = sb.st_size;
2309 last_mod = sb.st_mtime;
2310 }
2311 }
2312#if ENABLE_FEATURE_HTTPD_CGI
2313 else if (urlp[-1] == '/') {
2314 /* It's a dir URL and there is no index.html
2315 * Try cgi-bin/index.cgi */
2316 if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
2317 cgi_type = CGI_INDEX;
2318 }
2319 }
2259#endif 2320#endif
2321 urlp[0] = '\0';
2260 2322
2323#if ENABLE_FEATURE_HTTPD_CGI
2324 total_headers_len = 0;
2325#endif
2261 if (http_major_version >= '0') { 2326 if (http_major_version >= '0') {
2262 /* Request was with "... HTTP/nXXX", and n >= 0 */ 2327 /* Request was with "... HTTP/nXXX", and n >= 0 */
2263 2328
2264 /* Read until blank line */ 2329 /* Read until blank line */
2265 while (1) { 2330 while (1) {
2266 if (!get_line()) 2331 unsigned iobuf_len = get_line();
2332 if (!iobuf_len)
2267 break; /* EOF or error or empty line */ 2333 break; /* EOF or error or empty line */
2334#if ENABLE_FEATURE_HTTPD_CGI
2335 /* Prevent unlimited growth of HTTP_xyz envvars */
2336 total_headers_len += iobuf_len;
2337 if (total_headers_len >= MAX_HTTP_HEADERS_SIZE)
2338 send_headers_and_exit(HTTP_ENTITY_TOO_LARGE);
2339#endif
2268 if (DEBUG) 2340 if (DEBUG)
2269 bb_error_msg("header: '%s'", iobuf); 2341 bb_error_msg("header: '%s'", iobuf);
2270
2271#if ENABLE_FEATURE_HTTPD_PROXY
2272 /* We need 2 more bytes for yet another "\r\n" -
2273 * see near fdprintf(proxy_fd...) further below */
2274 if (proxy_entry && (header_ptr - header_buf) < IOBUF_SIZE - 4) {
2275 int len = strnlen(iobuf, IOBUF_SIZE - (header_ptr - header_buf) - 4);
2276 memcpy(header_ptr, iobuf, len);
2277 header_ptr += len;
2278 header_ptr[0] = '\r';
2279 header_ptr[1] = '\n';
2280 header_ptr += 2;
2281 }
2282#endif
2283
2284#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY 2342#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
2285 /* Try and do our best to parse more lines */ 2343 /* Try and do our best to parse more lines */
2286 if ((STRNCASECMP(iobuf, "Content-Length:") == 0)) { 2344 if ((STRNCASECMP(iobuf, "Content-Length:") == 0)) {
@@ -2299,30 +2357,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2299 if (errno || length > INT_MAX) 2357 if (errno || length > INT_MAX)
2300 send_headers_and_exit(HTTP_BAD_REQUEST); 2358 send_headers_and_exit(HTTP_BAD_REQUEST);
2301 } 2359 }
2302 } 2360 continue;
2303#endif
2304#if ENABLE_FEATURE_HTTPD_CGI
2305 else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
2306 if (!cookie) /* in case they send millions of these, do not OOM */
2307 cookie = xstrdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
2308 } else if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
2309 if (!content_type)
2310 content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
2311 } else if (STRNCASECMP(iobuf, "Referer:") == 0) {
2312 if (!G.referer)
2313 G.referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
2314 } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) {
2315 if (!G.user_agent)
2316 G.user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
2317 } else if (STRNCASECMP(iobuf, "Host:") == 0) {
2318 if (!G.host)
2319 G.host = xstrdup(skip_whitespace(iobuf + sizeof("Host:")-1));
2320 } else if (STRNCASECMP(iobuf, "Accept:") == 0) {
2321 if (!G.http_accept)
2322 G.http_accept = xstrdup(skip_whitespace(iobuf + sizeof("Accept:")-1));
2323 } else if (STRNCASECMP(iobuf, "Accept-Language:") == 0) {
2324 if (!G.http_accept_language)
2325 G.http_accept_language = xstrdup(skip_whitespace(iobuf + sizeof("Accept-Language:")-1));
2326 } 2361 }
2327#endif 2362#endif
2328#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2363#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -2338,6 +2373,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2338 /* decodeBase64() skips whitespace itself */ 2373 /* decodeBase64() skips whitespace itself */
2339 decodeBase64(tptr); 2374 decodeBase64(tptr);
2340 authorized = check_user_passwd(urlcopy, tptr); 2375 authorized = check_user_passwd(urlcopy, tptr);
2376 continue;
2341 } 2377 }
2342#endif 2378#endif
2343#if ENABLE_FEATURE_HTTPD_RANGES 2379#if ENABLE_FEATURE_HTTPD_RANGES
@@ -2355,6 +2391,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2355 range_start = -1; 2391 range_start = -1;
2356 } 2392 }
2357 } 2393 }
2394 continue;
2358 } 2395 }
2359#endif 2396#endif
2360#if ENABLE_FEATURE_HTTPD_GZIP 2397#if ENABLE_FEATURE_HTTPD_GZIP
@@ -2372,6 +2409,35 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2372 content_gzip = 1; 2409 content_gzip = 1;
2373 //} 2410 //}
2374 } 2411 }
2412 continue;
2413 }
2414#endif
2415#if ENABLE_FEATURE_HTTPD_CGI
2416 if (cgi_type != CGI_NONE) {
2417 bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0);
2418 char *cp;
2419 char *colon = strchr(iobuf, ':');
2420
2421 if (!colon)
2422 continue;
2423 cp = iobuf;
2424 while (cp < colon) {
2425 /* a-z => A-Z, not-alnum => _ */
2426 char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */
2427 if ((unsigned)(c - 'A') <= ('Z' - 'A')) {
2428 *cp++ = c;
2429 continue;
2430 }
2431 if (!isdigit(*cp))
2432 *cp = '_';
2433 cp++;
2434 }
2435 /* "Content-Type:" gets no HTTP_ prefix, all others do */
2436 cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s",
2437 (int)(colon - iobuf), iobuf,
2438 skip_whitespace(colon + 1)
2439 );
2440 putenv(cp);
2375 } 2441 }
2376#endif 2442#endif
2377 } /* while extra header reading */ 2443 } /* while extra header reading */
@@ -2380,7 +2446,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2380 /* We are done reading headers, disable peer timeout */ 2446 /* We are done reading headers, disable peer timeout */
2381 alarm(0); 2447 alarm(0);
2382 2448
2383 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0 || !ip_allowed) { 2449 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2384 /* protect listing [/path]/httpd.conf or IP deny */ 2450 /* protect listing [/path]/httpd.conf or IP deny */
2385 send_headers_and_exit(HTTP_FORBIDDEN); 2451 send_headers_and_exit(HTTP_FORBIDDEN);
2386 } 2452 }
@@ -2398,83 +2464,23 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2398 send_headers_and_exit(HTTP_MOVED_TEMPORARILY); 2464 send_headers_and_exit(HTTP_MOVED_TEMPORARILY);
2399 } 2465 }
2400 2466
2401#if ENABLE_FEATURE_HTTPD_PROXY
2402 if (proxy_entry != NULL) {
2403 int proxy_fd;
2404 len_and_sockaddr *lsa;
2405
2406 lsa = host2sockaddr(proxy_entry->host_port, 80);
2407 if (lsa == NULL)
2408 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2409 proxy_fd = socket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
2410 if (proxy_fd < 0)
2411 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2412 if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0)
2413 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
2414 fdprintf(proxy_fd, "%s %s%s%s%s HTTP/%c.%c\r\n",
2415 prequest, /* GET or POST */
2416 proxy_entry->url_to, /* url part 1 */
2417 urlcopy + strlen(proxy_entry->url_from), /* url part 2 */
2418 (g_query ? "?" : ""), /* "?" (maybe) */
2419 (g_query ? g_query : ""), /* query string (maybe) */
2420 http_major_version, http_minor_version);
2421 header_ptr[0] = '\r';
2422 header_ptr[1] = '\n';
2423 header_ptr += 2;
2424 write(proxy_fd, header_buf, header_ptr - header_buf);
2425 free(header_buf); /* on the order of 8k, free it */
2426 cgi_io_loop_and_exit(proxy_fd, proxy_fd, length);
2427 }
2428#endif
2429
2430 tptr = urlcopy + 1; /* skip first '/' */ 2467 tptr = urlcopy + 1; /* skip first '/' */
2431 2468
2432#if ENABLE_FEATURE_HTTPD_CGI 2469#if ENABLE_FEATURE_HTTPD_CGI
2433 if (is_prefixed_with(tptr, "cgi-bin/")) { 2470 if (cgi_type != CGI_NONE) {
2434 if (tptr[8] == '\0') { 2471 send_cgi_and_exit(
2435 /* protect listing "cgi-bin/" */ 2472 (cgi_type == CGI_INDEX) ? "/cgi-bin/index.cgi"
2436 send_headers_and_exit(HTTP_FORBIDDEN); 2473 /*CGI_NORMAL or CGI_INTERPRETER*/ : urlcopy,
2437 } 2474 urlcopy, prequest, length
2438 send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); 2475 );
2439 } 2476 }
2440#endif 2477#endif
2441 2478
2442 if (urlp[-1] == '/') { 2479 if (urlp[-1] == '/') {
2443 /* When index_page string is appended to <dir>/ URL, it overwrites
2444 * the query string. If we fall back to call /cgi-bin/index.cgi,
2445 * query string would be lost and not available to the CGI.
2446 * Work around it by making a deep copy.
2447 */
2448 if (ENABLE_FEATURE_HTTPD_CGI)
2449 g_query = xstrdup(g_query); /* ok for NULL too */
2450 strcpy(urlp, index_page); 2480 strcpy(urlp, index_page);
2451 } 2481 }
2452 if (stat(tptr, &sb) == 0) {
2453#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
2454 char *suffix = strrchr(tptr, '.');
2455 if (suffix) {
2456 Htaccess *cur;
2457 for (cur = script_i; cur; cur = cur->next) {
2458 if (strcmp(cur->before_colon + 1, suffix) == 0) {
2459 send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
2460 }
2461 }
2462 }
2463#endif
2464 file_size = sb.st_size;
2465 last_mod = sb.st_mtime;
2466 }
2467#if ENABLE_FEATURE_HTTPD_CGI
2468 else if (urlp[-1] == '/') {
2469 /* It's a dir URL and there is no index.html
2470 * Try cgi-bin/index.cgi */
2471 if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
2472 urlp[0] = '\0'; /* remove index_page */
2473 send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type);
2474 }
2475 }
2476 /* else fall through to send_file, it errors out if open fails: */
2477 2482
2483#if ENABLE_FEATURE_HTTPD_CGI
2478 if (prequest != request_GET && prequest != request_HEAD) { 2484 if (prequest != request_GET && prequest != request_HEAD) {
2479 /* POST for files does not make sense */ 2485 /* POST for files does not make sense */
2480 send_headers_and_exit(HTTP_NOT_IMPLEMENTED); 2486 send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
@@ -2593,7 +2599,9 @@ static void mini_httpd_inetd(void)
2593 2599
2594static void sighup_handler(int sig UNUSED_PARAM) 2600static void sighup_handler(int sig UNUSED_PARAM)
2595{ 2601{
2602 int sv = errno;
2596 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); 2603 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE);
2604 errno = sv;
2597} 2605}
2598 2606
2599enum { 2607enum {
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 0a1b5d798..8364f6a3e 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -424,7 +424,6 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
424 struct nlmsg_list *l; 424 struct nlmsg_list *l;
425 struct rtnl_handle rth; 425 struct rtnl_handle rth;
426 char *filter_dev = NULL; 426 char *filter_dev = NULL;
427 int no_link = 0;
428 427
429 ipaddr_reset_filter(oneline); 428 ipaddr_reset_filter(oneline);
430 G_filter.showqueue = 1; 429 G_filter.showqueue = 1;
@@ -516,9 +515,6 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
516 struct nlmsg_list **lp; 515 struct nlmsg_list **lp;
517 lp = &linfo; 516 lp = &linfo;
518 517
519 if (G_filter.oneline)
520 no_link = 1;
521
522 while ((l = *lp) != NULL) { 518 while ((l = *lp) != NULL) {
523 int ok = 0; 519 int ok = 0;
524 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 520 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
diff --git a/networking/telnetd.c b/networking/telnetd.c
index caef15181..6abecbde2 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -249,7 +249,7 @@ safe_write_to_pty_decode_iac(struct tsession *ts)
249 * IAC SE (240) End of subnegotiation. Treated as NOP. 249 * IAC SE (240) End of subnegotiation. Treated as NOP.
250 * IAC NOP (241) NOP. Supported. 250 * IAC NOP (241) NOP. Supported.
251 * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()? 251 * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()?
252 * IAC AYT (246) Are you there. Send back evidence that AYT was seen. TODO (send NOP back)? 252 * IAC AYT (246) Are you there.
253 * These don't look useful: 253 * These don't look useful:
254 * IAC DM (242) Data mark. What is this? 254 * IAC DM (242) Data mark. What is this?
255 * IAC IP (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C). 255 * IAC IP (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C).
@@ -277,6 +277,18 @@ safe_write_to_pty_decode_iac(struct tsession *ts)
277 rc = 2; 277 rc = 2;
278 goto update_and_return; 278 goto update_and_return;
279 } 279 }
280 if (buf[1] == AYT) {
281 if (ts->size2 == 0) { /* if nothing buffered yet... */
282 /* Send back evidence that AYT was seen */
283 unsigned char *buf2 = TS_BUF2(ts);
284 buf2[0] = IAC;
285 buf2[1] = NOP;
286 ts->wridx2 = 0;
287 ts->rdidx2 = ts->size2 = 2;
288 }
289 rc = 2;
290 goto update_and_return;
291 }
280 if (buf[1] >= 240 && buf[1] <= 249) { 292 if (buf[1] >= 240 && buf[1] <= 249) {
281 /* NOP (241). Ignore (putty keepalive, etc) */ 293 /* NOP (241). Ignore (putty keepalive, etc) */
282 /* All other 2-byte commands also treated as NOPs here */ 294 /* All other 2-byte commands also treated as NOPs here */
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index fc4de5716..59cf723ee 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -54,6 +54,8 @@ const struct dhcp_optflag dhcp_optflags[] = {
54 { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ 54 { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */
55//TODO: not a string, but a set of LASCII strings: 55//TODO: not a string, but a set of LASCII strings:
56// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ 56// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */
57 { OPTION_STRING , 0x64 }, /* DHCP_PCODE */
58 { OPTION_STRING , 0x65 }, /* DHCP_TCODE */
57#if ENABLE_FEATURE_UDHCP_RFC3397 59#if ENABLE_FEATURE_UDHCP_RFC3397
58 { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ 60 { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */
59 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ 61 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
@@ -121,6 +123,8 @@ const char dhcp_option_strings[] ALIGN1 =
121 "tftp" "\0" /* DHCP_TFTP_SERVER_NAME*/ 123 "tftp" "\0" /* DHCP_TFTP_SERVER_NAME*/
122 "bootfile" "\0" /* DHCP_BOOT_FILE */ 124 "bootfile" "\0" /* DHCP_BOOT_FILE */
123// "userclass" "\0" /* DHCP_USER_CLASS */ 125// "userclass" "\0" /* DHCP_USER_CLASS */
126 "tzstr" "\0" /* DHCP_PCODE */
127 "tzdbstr" "\0" /* DHCP_TCODE */
124#if ENABLE_FEATURE_UDHCP_RFC3397 128#if ENABLE_FEATURE_UDHCP_RFC3397
125 "search" "\0" /* DHCP_DOMAIN_SEARCH */ 129 "search" "\0" /* DHCP_DOMAIN_SEARCH */
126// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS 130// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index b68f9394e..9d1f71aae 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -149,6 +149,8 @@ enum {
149//#define DHCP_BOOT_FILE 0x43 /* 67: same as 'file' field */ 149//#define DHCP_BOOT_FILE 0x43 /* 67: same as 'file' field */
150//#define DHCP_USER_CLASS 0x4d /* 77: RFC 3004. set of LASCII strings. "I am a printer" etc */ 150//#define DHCP_USER_CLASS 0x4d /* 77: RFC 3004. set of LASCII strings. "I am a printer" etc */
151#define DHCP_FQDN 0x51 /* 81: client asks to update DNS to map its FQDN to its new IP */ 151#define DHCP_FQDN 0x51 /* 81: client asks to update DNS to map its FQDN to its new IP */
152//#define DHCP_PCODE 0x64 /* 100: RFC 4833. IEEE 1003.1 TZ string */
153//#define DHCP_TCODE 0x65 /* 101: RFC 4833. Reference to the TZ database string */
152//#define DHCP_DOMAIN_SEARCH 0x77 /* 119: RFC 3397. set of ASCIZ string, DNS-style compressed */ 154//#define DHCP_DOMAIN_SEARCH 0x77 /* 119: RFC 3397. set of ASCIZ string, DNS-style compressed */
153//#define DHCP_SIP_SERVERS 0x78 /* 120: RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ 155//#define DHCP_SIP_SERVERS 0x78 /* 120: RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
154//#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */ 156//#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index d0506e2bb..2178cb9d6 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -145,7 +145,12 @@ struct client6_data_t {
145 145
146#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)])) 146#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)]))
147 147
148int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_addr *nip6, uint8_t *mac); 148int FAST_FUNC d6_read_interface(
149 const char *interface,
150 int *ifindex,
151 struct in6_addr *nip6,
152 uint8_t *mac
153);
149 154
150int FAST_FUNC d6_listen_socket(int port, const char *inf); 155int FAST_FUNC d6_listen_socket(int port, const char *inf);
151 156
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 8a4a4b7a5..3562988fd 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -2,15 +2,13 @@
2/* 2/*
3 * DHCPv6 client. 3 * DHCPv6 client.
4 * 4 *
5 * WARNING: THIS CODE IS INCOMPLETE.
6 *
7 * Copyright (C) 2011-2017 Denys Vlasenko. 5 * Copyright (C) 2011-2017 Denys Vlasenko.
8 * 6 *
9 * Licensed under GPLv2, see file LICENSE in this source tree. 7 * Licensed under GPLv2, see file LICENSE in this source tree.
10 */ 8 */
11//config:config UDHCPC6 9//config:config UDHCPC6
12//config: bool "udhcpc6 (21 kb)" 10//config: bool "udhcpc6 (21 kb)"
13//config: default n # not yet ready 11//config: default y
14//config: depends on FEATURE_IPV6 12//config: depends on FEATURE_IPV6
15//config: help 13//config: help
16//config: udhcpc6 is a DHCPv6 client 14//config: udhcpc6 is a DHCPv6 client
@@ -206,7 +204,6 @@ static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code)
206 return xmemdup(opt, opt[3] + 4); 204 return xmemdup(opt, opt[3] + 4);
207} 205}
208 206
209
210/*** Script execution code ***/ 207/*** Script execution code ***/
211 208
212static char** new_env(void) 209static char** new_env(void)
@@ -533,6 +530,7 @@ static uint8_t *add_d6_client_options(uint8_t *ptr)
533 530
534static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) 531static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end)
535{ 532{
533 /* FF02::1:2 is "All_DHCP_Relay_Agents_and_Servers" address */
536 static const uint8_t FF02__1_2[16] = { 534 static const uint8_t FF02__1_2[16] = {
537 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 535 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 536 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
@@ -903,7 +901,6 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_pac
903 return bytes; 901 return bytes;
904} 902}
905 903
906
907/*** Main ***/ 904/*** Main ***/
908 905
909static int sockfd = -1; 906static int sockfd = -1;
@@ -1147,7 +1144,6 @@ static void client_background(void)
1147//usage: "\n USR1 Renew lease" 1144//usage: "\n USR1 Renew lease"
1148//usage: "\n USR2 Release lease" 1145//usage: "\n USR2 Release lease"
1149 1146
1150
1151int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1147int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1152int udhcpc6_main(int argc UNUSED_PARAM, char **argv) 1148int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1153{ 1149{
diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c
index 6ad53a9c2..25e622d6f 100644
--- a/networking/udhcp/d6_socket.c
+++ b/networking/udhcp/d6_socket.c
@@ -10,7 +10,11 @@
10#include <ifaddrs.h> 10#include <ifaddrs.h>
11#include <netpacket/packet.h> 11#include <netpacket/packet.h>
12 12
13int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_addr *nip6, uint8_t *mac) 13int FAST_FUNC d6_read_interface(
14 const char *interface,
15 int *ifindex,
16 struct in6_addr *nip6,
17 uint8_t *mac)
14{ 18{
15 int retval = 3; 19 int retval = 3;
16 struct ifaddrs *ifap, *ifa; 20 struct ifaddrs *ifap, *ifa;
@@ -22,12 +26,12 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
22 if (!ifa->ifa_addr || (strcmp(ifa->ifa_name, interface) != 0)) 26 if (!ifa->ifa_addr || (strcmp(ifa->ifa_name, interface) != 0))
23 continue; 27 continue;
24 28
25 sip6 = (struct sockaddr_in6*)(ifa->ifa_addr);
26
27 if (ifa->ifa_addr->sa_family == AF_PACKET) { 29 if (ifa->ifa_addr->sa_family == AF_PACKET) {
28 struct sockaddr_ll *sll = (struct sockaddr_ll*)(ifa->ifa_addr); 30 struct sockaddr_ll *sll = (void*)(ifa->ifa_addr);
29 memcpy(mac, sll->sll_addr, 6); 31 memcpy(mac, sll->sll_addr, 6);
30 log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 32 log2("MAC %02x:%02x:%02x:%02x:%02x:%02x",
33 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
34 );
31 *ifindex = sll->sll_ifindex; 35 *ifindex = sll->sll_ifindex;
32 log2("ifindex %d", *ifindex); 36 log2("ifindex %d", *ifindex);
33 retval &= (3 - (1<<0)); 37 retval &= (3 - (1<<0));
@@ -38,6 +42,17 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
38 log1("IP %s", inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr)); 42 log1("IP %s", inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr));
39 } 43 }
40#endif 44#endif
45/* RFC 3315
46 * 16. Client Source Address and Interface Selection
47 *
48 * "When a client sends a DHCP message to the
49 * All_DHCP_Relay_Agents_and_Servers address, ... ... The client
50 * MUST use a link-local address assigned to the interface for which it
51 * is requesting configuration information as the source address in the
52 * header of the IP datagram."
53 */
54 sip6 = (void*)(ifa->ifa_addr);
55
41 if (ifa->ifa_addr->sa_family == AF_INET6 56 if (ifa->ifa_addr->sa_family == AF_INET6
42 && IN6_IS_ADDR_LINKLOCAL(&sip6->sin6_addr) 57 && IN6_IS_ADDR_LINKLOCAL(&sip6->sin6_addr)
43 ) { 58 ) {
@@ -87,7 +102,7 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
87 bb_error_msg("can't get %s", "MAC"); 102 bb_error_msg("can't get %s", "MAC");
88 if (retval & (1<<1)) 103 if (retval & (1<<1))
89 bb_error_msg("can't get %s", "link-local IPv6 address"); 104 bb_error_msg("can't get %s", "link-local IPv6 address");
90 return -1; 105 return retval;
91} 106}
92 107
93int FAST_FUNC d6_listen_socket(int port, const char *inf) 108int FAST_FUNC d6_listen_socket(int port, const char *inf)
diff --git a/procps/top.c b/procps/top.c
index 625409755..89f9d23f4 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -222,8 +222,9 @@ enum {
222 OPT_d = (1 << 0), 222 OPT_d = (1 << 0),
223 OPT_n = (1 << 1), 223 OPT_n = (1 << 1),
224 OPT_b = (1 << 2), 224 OPT_b = (1 << 2),
225 OPT_m = (1 << 3), 225 OPT_H = (1 << 3),
226 OPT_EOF = (1 << 4), /* pseudo: "we saw EOF in stdin" */ 226 OPT_m = (1 << 4),
227 OPT_EOF = (1 << 5), /* pseudo: "we saw EOF in stdin" */
227}; 228};
228#define OPT_BATCH_MODE (option_mask32 & OPT_b) 229#define OPT_BATCH_MODE (option_mask32 & OPT_b)
229 230
@@ -1043,7 +1044,8 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval)
1043//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) 1044//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...)
1044//usage:#endif 1045//usage:#endif
1045//usage:#define top_trivial_usage 1046//usage:#define top_trivial_usage
1046//usage: "[-b"IF_FEATURE_TOPMEM("m")"] [-n COUNT] [-d SECONDS]" 1047//usage: "[-b"IF_FEATURE_TOPMEM("m")IF_FEATURE_SHOW_THREADS("H")"]"
1048//usage: " [-n COUNT] [-d SECONDS]"
1047//usage:#define top_full_usage "\n\n" 1049//usage:#define top_full_usage "\n\n"
1048//usage: "Provide a view of process activity in real time." 1050//usage: "Provide a view of process activity in real time."
1049//usage: "\n""Read the status of all processes from /proc each SECONDS" 1051//usage: "\n""Read the status of all processes from /proc each SECONDS"
@@ -1076,6 +1078,9 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval)
1076//usage: IF_FEATURE_TOPMEM( 1078//usage: IF_FEATURE_TOPMEM(
1077//usage: "\n"" -m Same as 's' key" 1079//usage: "\n"" -m Same as 's' key"
1078//usage: ) 1080//usage: )
1081//usage: IF_FEATURE_SHOW_THREADS(
1082//usage: "\n"" -H Show threads"
1083//usage: )
1079 1084
1080/* Interactive testing: 1085/* Interactive testing:
1081 * echo sss | ./busybox top 1086 * echo sss | ./busybox top
@@ -1110,7 +1115,8 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1110 1115
1111 /* all args are options; -n NUM */ 1116 /* all args are options; -n NUM */
1112 make_all_argv_opts(argv); /* options can be specified w/o dash */ 1117 make_all_argv_opts(argv); /* options can be specified w/o dash */
1113 col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); 1118 col = getopt32(argv, "d:n:bHm", &str_interval, &str_iterations);
1119 /* NB: -m and -H are accepted even if not configured */
1114#if ENABLE_FEATURE_TOPMEM 1120#if ENABLE_FEATURE_TOPMEM
1115 if (col & OPT_m) /* -m (busybox specific) */ 1121 if (col & OPT_m) /* -m (busybox specific) */
1116 scan_mask = TOPMEM_MASK; 1122 scan_mask = TOPMEM_MASK;
@@ -1129,6 +1135,11 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1129 str_iterations++; 1135 str_iterations++;
1130 iterations = xatou(str_iterations); 1136 iterations = xatou(str_iterations);
1131 } 1137 }
1138#if ENABLE_FEATURE_SHOW_THREADS
1139 if (col & OPT_H) {
1140 scan_mask |= PSSCAN_TASKS;
1141 }
1142#endif
1132 1143
1133 /* change to /proc */ 1144 /* change to /proc */
1134 xchdir("/proc"); 1145 xchdir("/proc");
diff --git a/shell/ash.c b/shell/ash.c
index c4f0880c8..ad7b8f4dd 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -254,6 +254,7 @@
254#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT 254#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
255#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT 255#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
256#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT 256#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
257#define BASH_EPOCH_VARS ENABLE_ASH_BASH_COMPAT
257#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT 258#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
258#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT 259#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
259#define BASH_READ_D ENABLE_ASH_BASH_COMPAT 260#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
@@ -2194,6 +2195,10 @@ static void changepath(const char *) FAST_FUNC;
2194#if ENABLE_ASH_RANDOM_SUPPORT 2195#if ENABLE_ASH_RANDOM_SUPPORT
2195static void change_random(const char *) FAST_FUNC; 2196static void change_random(const char *) FAST_FUNC;
2196#endif 2197#endif
2198#if BASH_EPOCH_VARS
2199static void change_seconds(const char *) FAST_FUNC;
2200static void change_realtime(const char *) FAST_FUNC;
2201#endif
2197 2202
2198static const struct { 2203static const struct {
2199 int flags; 2204 int flags;
@@ -2220,6 +2225,10 @@ static const struct {
2220#if ENABLE_ASH_RANDOM_SUPPORT 2225#if ENABLE_ASH_RANDOM_SUPPORT
2221 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, 2226 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2222#endif 2227#endif
2228#if BASH_EPOCH_VARS
2229 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2230 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2231#endif
2223#if ENABLE_LOCALE_SUPPORT 2232#if ENABLE_LOCALE_SUPPORT
2224 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all }, 2233 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2225 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype }, 2234 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
@@ -2251,26 +2260,26 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2251#define linenovar (G_var.linenovar ) 2260#define linenovar (G_var.linenovar )
2252#define vifs varinit[0] 2261#define vifs varinit[0]
2253#if ENABLE_ASH_MAIL 2262#if ENABLE_ASH_MAIL
2254# define vmail (&vifs)[1] 2263# define vmail varinit[1]
2255# define vmpath (&vmail)[1] 2264# define vmpath varinit[2]
2256# define vpath (&vmpath)[1] 2265#endif
2257#else 2266#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2258# define vpath (&vifs)[1] 2267#define vpath varinit[VAR_OFFSET1 + 1]
2259#endif 2268#define vps1 varinit[VAR_OFFSET1 + 2]
2260#define vps1 (&vpath)[1] 2269#define vps2 varinit[VAR_OFFSET1 + 3]
2261#define vps2 (&vps1)[1] 2270#define vps4 varinit[VAR_OFFSET1 + 4]
2262#define vps4 (&vps2)[1]
2263#if ENABLE_ASH_GETOPTS 2271#if ENABLE_ASH_GETOPTS
2264# define voptind (&vps4)[1] 2272# define voptind varinit[VAR_OFFSET1 + 5]
2265# define vlineno (&voptind)[1] 2273#endif
2266# if ENABLE_ASH_RANDOM_SUPPORT 2274#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2267# define vrandom (&vlineno)[1] 2275#define vlineno varinit[VAR_OFFSET2 + 5]
2268# endif 2276#if ENABLE_ASH_RANDOM_SUPPORT
2269#else 2277# define vrandom varinit[VAR_OFFSET2 + 6]
2270# define vlineno (&vps4)[1] 2278#endif
2271# if ENABLE_ASH_RANDOM_SUPPORT 2279#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2272# define vrandom (&vlineno)[1] 2280#if BASH_EPOCH_VARS
2273# endif 2281# define vepochs varinit[VAR_OFFSET3 + 6]
2282# define vepochr varinit[VAR_OFFSET3 + 7]
2274#endif 2283#endif
2275#define INIT_G_var() do { \ 2284#define INIT_G_var() do { \
2276 unsigned i; \ 2285 unsigned i; \
@@ -2409,7 +2418,7 @@ lookupvar(const char *name)
2409 2418
2410 v = *findvar(hashvar(name), name); 2419 v = *findvar(hashvar(name), name);
2411 if (v) { 2420 if (v) {
2412#if ENABLE_ASH_RANDOM_SUPPORT 2421#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2413 /* 2422 /*
2414 * Dynamic variables are implemented roughly the same way they are 2423 * Dynamic variables are implemented roughly the same way they are
2415 * in bash. Namely, they're "special" so long as they aren't unset. 2424 * in bash. Namely, they're "special" so long as they aren't unset.
@@ -2562,6 +2571,10 @@ setvareq(char *s, int flags)
2562 } 2571 }
2563 2572
2564 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 2573 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2574#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2575 if (flags & VUNSET)
2576 flags &= ~VDYNAMIC;
2577#endif
2565 } else { 2578 } else {
2566 /* variable s is not found */ 2579 /* variable s is not found */
2567 if (flags & VNOSET) 2580 if (flags & VNOSET)
@@ -11950,6 +11963,32 @@ change_random(const char *value)
11950} 11963}
11951#endif 11964#endif
11952 11965
11966#if BASH_EPOCH_VARS
11967static void FAST_FUNC
11968change_epoch(struct var *vepoch, const char *fmt)
11969{
11970 struct timeval tv;
11971 char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3];
11972
11973 gettimeofday(&tv, NULL);
11974 sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec);
11975 setvar(vepoch->var_text, buffer, VNOFUNC);
11976 vepoch->flags &= ~VNOFUNC;
11977}
11978
11979static void FAST_FUNC
11980change_seconds(const char *value UNUSED_PARAM)
11981{
11982 change_epoch(&vepochs, "%lu");
11983}
11984
11985static void FAST_FUNC
11986change_realtime(const char *value UNUSED_PARAM)
11987{
11988 change_epoch(&vepochr, "%lu.%06u");
11989}
11990#endif
11991
11953#if ENABLE_ASH_GETOPTS 11992#if ENABLE_ASH_GETOPTS
11954static int 11993static int
11955getopts(char *optstr, char *optvar, char **optfirst) 11994getopts(char *optstr, char *optvar, char **optfirst)
diff --git a/shell/hush.c b/shell/hush.c
index fa9afa38e..d745148f4 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -379,6 +379,7 @@
379#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT 379#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
380#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT 380#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
381#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT 381#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
382#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
382#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) 383#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
383#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT 384#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
384 385
@@ -1011,6 +1012,9 @@ struct globals {
1011 int debug_indent; 1012 int debug_indent;
1012#endif 1013#endif
1013 struct sigaction sa; 1014 struct sigaction sa;
1015#if BASH_EPOCH_VARS
1016 char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3];
1017#endif
1014#if ENABLE_FEATURE_EDITING 1018#if ENABLE_FEATURE_EDITING
1015 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN]; 1019 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
1016#endif 1020#endif
@@ -2228,6 +2232,22 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
2228 if (strcmp(name, "RANDOM") == 0) 2232 if (strcmp(name, "RANDOM") == 0)
2229 return utoa(next_random(&G.random_gen)); 2233 return utoa(next_random(&G.random_gen));
2230#endif 2234#endif
2235#if BASH_EPOCH_VARS
2236 {
2237 const char *fmt = NULL;
2238 if (strcmp(name, "EPOCHSECONDS") == 0)
2239 fmt = "%lu";
2240 else if (strcmp(name, "EPOCHREALTIME") == 0)
2241 fmt = "%lu.%06u";
2242 if (fmt) {
2243 struct timeval tv;
2244 gettimeofday(&tv, NULL);
2245 sprintf(G.epoch_buf, fmt, (unsigned long)tv.tv_sec,
2246 (unsigned)tv.tv_usec);
2247 return G.epoch_buf;
2248 }
2249 }
2250#endif
2231 return NULL; 2251 return NULL;
2232} 2252}
2233 2253
diff --git a/util-linux/chrt.c b/util-linux/chrt.c
index 28e65457c..4dd78dabf 100644
--- a/util-linux/chrt.c
+++ b/util-linux/chrt.c
@@ -17,16 +17,16 @@
17//kbuild:lib-$(CONFIG_CHRT) += chrt.o 17//kbuild:lib-$(CONFIG_CHRT) += chrt.o
18 18
19//usage:#define chrt_trivial_usage 19//usage:#define chrt_trivial_usage
20//usage: "[-prfombi] [PRIO] [PID | PROG ARGS]" 20//usage: "-m | -p [PRIO] PID | [-rfobi] PRIO PROG [ARGS]"
21//usage:#define chrt_full_usage "\n\n" 21//usage:#define chrt_full_usage "\n\n"
22//usage: "Change scheduling priority and class for a process\n" 22//usage: "Change scheduling priority and class for a process\n"
23//usage: "\n -m Show min/max priorities"
23//usage: "\n -p Operate on PID" 24//usage: "\n -p Operate on PID"
24//usage: "\n -r Set SCHED_RR class" 25//usage: "\n -r Set SCHED_RR class"
25//usage: "\n -f Set SCHED_FIFO class" 26//usage: "\n -f Set SCHED_FIFO class"
26//usage: "\n -o Set SCHED_OTHER class" 27//usage: "\n -o Set SCHED_OTHER class"
27//usage: "\n -b Set SCHED_BATCH class" 28//usage: "\n -b Set SCHED_BATCH class"
28//usage: "\n -i Set SCHED_IDLE class" 29//usage: "\n -i Set SCHED_IDLE class"
29//usage: "\n -m Show min/max priorities"
30//usage: 30//usage:
31//usage:#define chrt_example_usage 31//usage:#define chrt_example_usage
32//usage: "$ chrt -r 4 sleep 900; x=$!\n" 32//usage: "$ chrt -r 4 sleep 900; x=$!\n"
@@ -39,28 +39,32 @@
39# define SCHED_IDLE 5 39# define SCHED_IDLE 5
40#endif 40#endif
41 41
42static const struct { 42static const char *policy_name(int pol)
43 char name[sizeof("SCHED_OTHER")]; 43{
44} policies[] = { 44 if (pol > 6)
45 { "SCHED_OTHER" }, /* 0:SCHED_OTHER */ 45 return utoa(pol);
46 { "SCHED_FIFO" }, /* 1:SCHED_FIFO */ 46 return nth_string(
47 { "SCHED_RR" }, /* 2:SCHED_RR */ 47 "OTHER" "\0" /* 0:SCHED_OTHER */
48 { "SCHED_BATCH" }, /* 3:SCHED_BATCH */ 48 "FIFO" "\0" /* 1:SCHED_FIFO */
49 { "" }, /* 4:SCHED_ISO */ 49 "RR" "\0" /* 2:SCHED_RR */
50 { "SCHED_IDLE" }, /* 5:SCHED_IDLE */ 50 "BATCH" "\0" /* 3:SCHED_BATCH */
51 /* 6:SCHED_DEADLINE */ 51 "ISO" "\0" /* 4:SCHED_ISO */
52}; 52 "IDLE" "\0" /* 5:SCHED_IDLE */
53 "DEADLINE", /* 6:SCHED_DEADLINE */
54 pol
55 );
56}
53 57
54static void show_min_max(int pol) 58static void show_min_max(int pol)
55{ 59{
56 const char *fmt = "%s min/max priority\t: %u/%u\n"; 60 const char *fmt = "SCHED_%s min/max priority\t: %u/%u\n";
57 int max, min; 61 int max, min;
58 62
59 max = sched_get_priority_max(pol); 63 max = sched_get_priority_max(pol);
60 min = sched_get_priority_min(pol); 64 min = sched_get_priority_min(pol);
61 if ((max|min) < 0) 65 if ((max|min) < 0)
62 fmt = "%s not supported\n"; 66 fmt = "SCHED_%s not supported\n";
63 printf(fmt, policies[pol].name, min, max); 67 printf(fmt, policy_name(pol), min, max);
64} 68}
65 69
66#define OPT_m (1<<0) 70#define OPT_m (1<<0)
@@ -112,11 +116,11 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
112 bb_show_usage(); 116 bb_show_usage();
113 if (opt & OPT_p) { 117 if (opt & OPT_p) {
114 pid_str = *argv++; 118 pid_str = *argv++;
115 if (*argv) { /* "-p <priority> <pid> [...]" */ 119 if (*argv) { /* "-p PRIO PID [...]" */
116 priority = pid_str; 120 priority = pid_str;
117 pid_str = *argv; 121 pid_str = *argv;
118 } 122 }
119 /* else "-p <pid>", and *argv == NULL */ 123 /* else "-p PID", and *argv == NULL */
120 pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1); 124 pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
121 } else { 125 } else {
122 priority = *argv++; 126 priority = *argv++;
@@ -130,16 +134,29 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
130 print_rt_info: 134 print_rt_info:
131 pol = sched_getscheduler(pid); 135 pol = sched_getscheduler(pid);
132 if (pol < 0) 136 if (pol < 0)
133 bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid); 137 bb_perror_msg_and_die("can't %cet pid %u's policy", 'g', (int)pid);
134 printf("pid %d's %s scheduling policy: %s\n", 138#ifdef SCHED_RESET_ON_FORK
135 pid, current_new, policies[pol].name); 139 /* "Since Linux 2.6.32, the SCHED_RESET_ON_FORK flag
140 * can be ORed in policy when calling sched_setscheduler().
141 * As a result of including this flag, children created by
142 * fork(2) do not inherit privileged scheduling policies"
143 *
144 * This bit is also returned by sched_getscheduler()!
145 * (TODO: do we want to show it?)
146 */
147 pol &= ~SCHED_RESET_ON_FORK;
148#endif
149 printf("pid %u's %s scheduling policy: SCHED_%s\n",
150 pid, current_new, policy_name(pol)
151 );
136 if (sched_getparam(pid, &sp)) 152 if (sched_getparam(pid, &sp))
137 bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid); 153 bb_perror_msg_and_die("can't get pid %u's attributes", (int)pid);
138 printf("pid %d's %s scheduling priority: %d\n", 154 printf("pid %u's %s scheduling priority: %d\n",
139 (int)pid, current_new, sp.sched_priority); 155 (int)pid, current_new, sp.sched_priority
156 );
140 if (!*argv) { 157 if (!*argv) {
141 /* Either it was just "-p <pid>", 158 /* Either it was just "-p PID",
142 * or it was "-p <priority> <pid>" and we came here 159 * or it was "-p PRIO PID" and we came here
143 * for the second time (see goto below) */ 160 * for the second time (see goto below) */
144 return EXIT_SUCCESS; 161 return EXIT_SUCCESS;
145 } 162 }
@@ -152,9 +169,9 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
152 ); 169 );
153 170
154 if (sched_setscheduler(pid, policy, &sp) < 0) 171 if (sched_setscheduler(pid, policy, &sp) < 0)
155 bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid); 172 bb_perror_msg_and_die("can't %cet pid %u's policy", 's', (int)pid);
156 173
157 if (!argv[0]) /* "-p <priority> <pid> [...]" */ 174 if (!argv[0]) /* "-p PRIO PID [...]" */
158 goto print_rt_info; 175 goto print_rt_info;
159 176
160 BB_EXECVP_or_die(argv); 177 BB_EXECVP_or_die(argv);