aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2014-10-06 12:50:22 +0100
committerRon Yorston <rmy@pobox.com>2014-10-06 12:50:22 +0100
commitb04d11dcbadda2620743a1dd923938f2f3043a38 (patch)
tree971afe425a81304b79e44122e220c7a69efe2616
parent124bbf02948b7ac0babb4ead04acd1559db182d3 (diff)
parent760d035699c4a878f9109544c1d35ea0d5f6b76c (diff)
downloadbusybox-w32-b04d11dcbadda2620743a1dd923938f2f3043a38.tar.gz
busybox-w32-b04d11dcbadda2620743a1dd923938f2f3043a38.tar.bz2
busybox-w32-b04d11dcbadda2620743a1dd923938f2f3043a38.zip
Merge branch 'busybox' into merge
-rw-r--r--applets/applet_tables.c17
-rw-r--r--console-tools/setlogcons.c4
-rw-r--r--coreutils/df.c36
-rw-r--r--coreutils/install.c37
-rw-r--r--coreutils/test.c69
-rw-r--r--editors/sed.c13
-rw-r--r--editors/vi.c79
-rw-r--r--findutils/find.c8
-rw-r--r--findutils/grep.c2
-rw-r--r--include/applets.src.h1
-rw-r--r--include/libbb.h5
-rw-r--r--libbb/Kbuild.src1
-rw-r--r--libbb/appletlib.c29
-rw-r--r--libbb/bb_askpass.c5
-rw-r--r--libbb/correct_password.c96
-rw-r--r--libbb/hash_md5_sha.c317
-rw-r--r--libbb/xfuncs.c10
-rw-r--r--loginutils/addgroup.c4
-rw-r--r--loginutils/getty.c17
-rw-r--r--miscutils/Config.src16
-rw-r--r--miscutils/Kbuild.src1
-rw-r--r--miscutils/less.c69
-rw-r--r--miscutils/taskset.c86
-rw-r--r--miscutils/ubi_tools.c23
-rw-r--r--modutils/modinfo.c7
-rw-r--r--networking/Config.src7
-rw-r--r--networking/ftpd.c63
-rw-r--r--networking/ntpd.c270
-rw-r--r--networking/ping.c25
-rw-r--r--networking/tftp.c21
-rw-r--r--networking/udhcp/common.c2
-rw-r--r--networking/udhcp/common.h1
-rw-r--r--networking/zcip.c38
-rw-r--r--procps/top.c197
-rw-r--r--shell/ash.c65
-rw-r--r--shell/hush.c33
-rw-r--r--shell/hush_test/hush-misc/unicode1.right3
-rwxr-xr-xshell/hush_test/hush-misc/unicode1.tests13
-rw-r--r--sysklogd/syslogd.c105
-rwxr-xr-xtestsuite/grep.tests20
-rwxr-xr-xtestsuite/sed.tests4
-rwxr-xr-xtestsuite/test.tests20
-rw-r--r--util-linux/fatattr.c4
-rw-r--r--util-linux/mdev.c2
44 files changed, 1226 insertions, 619 deletions
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 94b974e09..92bf1e447 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -14,6 +14,7 @@
14#include <string.h> 14#include <string.h>
15#include <stdio.h> 15#include <stdio.h>
16#include <unistd.h> 16#include <unistd.h>
17#include <ctype.h>
17 18
18#undef ARRAY_SIZE 19#undef ARRAY_SIZE
19#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) 20#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
@@ -49,6 +50,16 @@ static int cmp_name(const void *a, const void *b)
49 return strcmp(aa->name, bb->name); 50 return strcmp(aa->name, bb->name);
50} 51}
51 52
53static int str_isalnum_(const char *s)
54{
55 while (*s) {
56 if (!isalnum(*s) && *s != '_')
57 return 0;
58 s++;
59 }
60 return 1;
61}
62
52int main(int argc, char **argv) 63int main(int argc, char **argv)
53{ 64{
54 int i; 65 int i;
@@ -94,6 +105,12 @@ int main(int argc, char **argv)
94 } 105 }
95 printf(";\n\n"); 106 printf(";\n\n");
96 107
108 for (i = 0; i < NUM_APPLETS; i++) {
109 if (str_isalnum_(applets[i].name))
110 printf("#define APPLET_NO_%s %d\n", applets[i].name, i);
111 }
112 printf("\n");
113
97 printf("#ifndef SKIP_applet_main\n"); 114 printf("#ifndef SKIP_applet_main\n");
98 printf("int (*const applet_main[])(int argc, char **argv) = {\n"); 115 printf("int (*const applet_main[])(int argc, char **argv) = {\n");
99 for (i = 0; i < NUM_APPLETS; i++) { 116 for (i = 0; i < NUM_APPLETS; i++) {
diff --git a/console-tools/setlogcons.c b/console-tools/setlogcons.c
index c76a5a42b..2a11da329 100644
--- a/console-tools/setlogcons.c
+++ b/console-tools/setlogcons.c
@@ -10,9 +10,9 @@
10 */ 10 */
11 11
12//usage:#define setlogcons_trivial_usage 12//usage:#define setlogcons_trivial_usage
13//usage: "N" 13//usage: "[N]"
14//usage:#define setlogcons_full_usage "\n\n" 14//usage:#define setlogcons_full_usage "\n\n"
15//usage: "Redirect the kernel output to console N (0 for current)" 15//usage: "Redirect the kernel output to console N. Default:0 (current console)"
16 16
17#include "libbb.h" 17#include "libbb.h"
18 18
diff --git a/coreutils/df.c b/coreutils/df.c
index 5e9a8670f..d79c11a6c 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -25,6 +25,7 @@
25//usage:#define df_trivial_usage 25//usage:#define df_trivial_usage
26//usage: "[-Pk" 26//usage: "[-Pk"
27//usage: IF_FEATURE_HUMAN_READABLE("mh") 27//usage: IF_FEATURE_HUMAN_READABLE("mh")
28//usage: "T"
28//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") 29//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE")
29//usage: "] [FILESYSTEM]..." 30//usage: "] [FILESYSTEM]..."
30//usage:#define df_full_usage "\n\n" 31//usage:#define df_full_usage "\n\n"
@@ -35,6 +36,7 @@
35//usage: "\n -m 1M-byte blocks" 36//usage: "\n -m 1M-byte blocks"
36//usage: "\n -h Human readable (e.g. 1K 243M 2G)" 37//usage: "\n -h Human readable (e.g. 1K 243M 2G)"
37//usage: ) 38//usage: )
39//usage: "\n -T Print filesystem type"
38//usage: IF_FEATURE_DF_FANCY( 40//usage: IF_FEATURE_DF_FANCY(
39//usage: "\n -a Show all filesystems" 41//usage: "\n -a Show all filesystems"
40//usage: "\n -i Inodes" 42//usage: "\n -i Inodes"
@@ -83,11 +85,12 @@ int df_main(int argc UNUSED_PARAM, char **argv)
83 enum { 85 enum {
84 OPT_KILO = (1 << 0), 86 OPT_KILO = (1 << 0),
85 OPT_POSIX = (1 << 1), 87 OPT_POSIX = (1 << 1),
86 OPT_ALL = (1 << 2) * ENABLE_FEATURE_DF_FANCY, 88 OPT_FSTYPE = (1 << 2),
87 OPT_INODE = (1 << 3) * ENABLE_FEATURE_DF_FANCY, 89 OPT_ALL = (1 << 3) * ENABLE_FEATURE_DF_FANCY,
88 OPT_BSIZE = (1 << 4) * ENABLE_FEATURE_DF_FANCY, 90 OPT_INODE = (1 << 4) * ENABLE_FEATURE_DF_FANCY,
89 OPT_HUMAN = (1 << (2 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 91 OPT_BSIZE = (1 << 5) * ENABLE_FEATURE_DF_FANCY,
90 OPT_MEGA = (1 << (3 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 92 OPT_HUMAN = (1 << (3 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
93 OPT_MEGA = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
91 }; 94 };
92 const char *disp_units_hdr = NULL; 95 const char *disp_units_hdr = NULL;
93 char *chp; 96 char *chp;
@@ -99,7 +102,7 @@ int df_main(int argc UNUSED_PARAM, char **argv)
99#elif ENABLE_FEATURE_HUMAN_READABLE 102#elif ENABLE_FEATURE_HUMAN_READABLE
100 opt_complementary = "k-m:m-k"; 103 opt_complementary = "k-m:m-k";
101#endif 104#endif
102 opt = getopt32(argv, "kP" 105 opt = getopt32(argv, "kPT"
103 IF_FEATURE_DF_FANCY("aiB:") 106 IF_FEATURE_DF_FANCY("aiB:")
104 IF_FEATURE_HUMAN_READABLE("hm") 107 IF_FEATURE_HUMAN_READABLE("hm")
105 IF_FEATURE_DF_FANCY(, &chp)); 108 IF_FEATURE_DF_FANCY(, &chp));
@@ -134,8 +137,11 @@ int df_main(int argc UNUSED_PARAM, char **argv)
134 disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr); 137 disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr);
135#endif 138#endif
136 } 139 }
137 printf("Filesystem %-15sUsed Available %s Mounted on\n", 140
138 disp_units_hdr, (opt & OPT_POSIX) ? "Capacity" : "Use%"); 141 printf("Filesystem %s%-15sUsed Available %s Mounted on\n",
142 (opt & OPT_FSTYPE) ? "Type " : "",
143 disp_units_hdr,
144 (opt & OPT_POSIX) ? "Capacity" : "Use%");
139 145
140 mount_table = NULL; 146 mount_table = NULL;
141 argv += optind; 147 argv += optind;
@@ -148,6 +154,7 @@ int df_main(int argc UNUSED_PARAM, char **argv)
148 while (1) { 154 while (1) {
149 const char *device; 155 const char *device;
150 const char *mount_point; 156 const char *mount_point;
157 const char *fs_type;
151 158
152 if (mount_table) { 159 if (mount_table) {
153 mount_entry = getmntent(mount_table); 160 mount_entry = getmntent(mount_table);
@@ -170,6 +177,7 @@ int df_main(int argc UNUSED_PARAM, char **argv)
170 177
171 device = mount_entry->mnt_fsname; 178 device = mount_entry->mnt_fsname;
172 mount_point = mount_entry->mnt_dir; 179 mount_point = mount_entry->mnt_dir;
180 fs_type = mount_entry->mnt_type;
173 181
174 if (statfs(mount_point, &s) != 0) { 182 if (statfs(mount_point, &s) != 0) {
175 bb_simple_perror_msg(mount_point); 183 bb_simple_perror_msg(mount_point);
@@ -218,10 +226,22 @@ int df_main(int argc UNUSED_PARAM, char **argv)
218 printf("%s%*s", uni_dev, 20 - (int)uni_stat.unicode_width, ""); 226 printf("%s%*s", uni_dev, 20 - (int)uni_stat.unicode_width, "");
219 } 227 }
220 free(uni_dev); 228 free(uni_dev);
229 if (opt & OPT_FSTYPE) {
230 char *uni_type = unicode_conv_to_printable(&uni_stat, fs_type);
231 if (uni_stat.unicode_width > 10 && !(opt & OPT_POSIX))
232 printf(" %s\n%31s", uni_type, "");
233 else
234 printf(" %s%*s", uni_type, 10 - (int)uni_stat.unicode_width, "");
235 free(uni_type);
236 }
221 } 237 }
222#else 238#else
223 if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX)) 239 if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX))
224 printf("\n%-20s", ""); 240 printf("\n%-20s", "");
241 if (opt & OPT_FSTYPE) {
242 if (printf(" %-10s", fs_type) > 11 && !(opt & OPT_POSIX))
243 printf("\n%-30s", "");
244 }
225#endif 245#endif
226 246
227#if ENABLE_FEATURE_HUMAN_READABLE 247#if ENABLE_FEATURE_HUMAN_READABLE
diff --git a/coreutils/install.c b/coreutils/install.c
index 6c88ae11c..73f9c70d5 100644
--- a/coreutils/install.c
+++ b/coreutils/install.c
@@ -8,7 +8,7 @@
8 8
9/* -v, -b, -c are ignored */ 9/* -v, -b, -c are ignored */
10//usage:#define install_trivial_usage 10//usage:#define install_trivial_usage
11//usage: "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [SOURCE]... DEST" 11//usage: "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [-t DIR] [SOURCE]... DEST"
12//usage:#define install_full_usage "\n\n" 12//usage:#define install_full_usage "\n\n"
13//usage: "Copy files and set attributes\n" 13//usage: "Copy files and set attributes\n"
14//usage: "\n -c Just copy (default)" 14//usage: "\n -c Just copy (default)"
@@ -19,6 +19,7 @@
19//usage: "\n -o USER Set ownership" 19//usage: "\n -o USER Set ownership"
20//usage: "\n -g GRP Set group ownership" 20//usage: "\n -g GRP Set group ownership"
21//usage: "\n -m MODE Set permissions" 21//usage: "\n -m MODE Set permissions"
22//usage: "\n -t DIR Install to DIR"
22//usage: IF_SELINUX( 23//usage: IF_SELINUX(
23//usage: "\n -Z Set security context" 24//usage: "\n -Z Set security context"
24//usage: ) 25//usage: )
@@ -37,6 +38,7 @@ static const char install_longopts[] ALIGN1 =
37 "group\0" Required_argument "g" 38 "group\0" Required_argument "g"
38 "mode\0" Required_argument "m" 39 "mode\0" Required_argument "m"
39 "owner\0" Required_argument "o" 40 "owner\0" Required_argument "o"
41 "target-directory\0" Required_argument "t"
40/* autofs build insists of using -b --suffix=.orig */ 42/* autofs build insists of using -b --suffix=.orig */
41/* TODO? (short option for --suffix is -S) */ 43/* TODO? (short option for --suffix is -S) */
42#if ENABLE_SELINUX 44#if ENABLE_SELINUX
@@ -95,9 +97,8 @@ int install_main(int argc, char **argv)
95 int mkdir_flags = FILEUTILS_RECUR; 97 int mkdir_flags = FILEUTILS_RECUR;
96 int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE; 98 int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
97 int opts; 99 int opts;
98 int min_args = 1;
99 int ret = EXIT_SUCCESS; 100 int ret = EXIT_SUCCESS;
100 int isdir = 0; 101 int isdir;
101#if ENABLE_SELINUX 102#if ENABLE_SELINUX
102 security_context_t scontext; 103 security_context_t scontext;
103 bool use_default_selinux_context = 1; 104 bool use_default_selinux_context = 1;
@@ -113,20 +114,22 @@ int install_main(int argc, char **argv)
113 OPT_GROUP = 1 << 7, 114 OPT_GROUP = 1 << 7,
114 OPT_MODE = 1 << 8, 115 OPT_MODE = 1 << 8,
115 OPT_OWNER = 1 << 9, 116 OPT_OWNER = 1 << 9,
117 OPT_TARGET = 1 << 10,
116#if ENABLE_SELINUX 118#if ENABLE_SELINUX
117 OPT_SET_SECURITY_CONTEXT = 1 << 10, 119 OPT_SET_SECURITY_CONTEXT = 1 << 11,
118 OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11, 120 OPT_PRESERVE_SECURITY_CONTEXT = 1 << 12,
119#endif 121#endif
120 }; 122 };
121 123
122#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS 124#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
123 applet_long_options = install_longopts; 125 applet_long_options = install_longopts;
124#endif 126#endif
125 opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); 127 opt_complementary = "t--d:d--t:s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z"));
126 /* -c exists for backwards compatibility, it's needed */ 128 /* -c exists for backwards compatibility, it's needed */
127 /* -b is ignored ("make a backup of each existing destination file") */ 129 /* -b is ignored ("make a backup of each existing destination file") */
128 opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"), 130 opts = getopt32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"),
129 &gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext)); 131 &gid_str, &mode_str, &uid_str, &last
132 IF_SELINUX(, &scontext));
130 argc -= optind; 133 argc -= optind;
131 argv += optind; 134 argv += optind;
132 135
@@ -160,20 +163,23 @@ int install_main(int argc, char **argv)
160 uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); 163 uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
161 gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); 164 gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
162 165
163 last = argv[argc - 1]; 166 /* If -t DIR is in use, then isdir=true, last="DIR" */
164 if (!(opts & OPT_DIRECTORY)) { 167 isdir = (opts & OPT_TARGET);
165 argv[argc - 1] = NULL; 168 if (!(opts & (OPT_TARGET|OPT_DIRECTORY))) {
166 min_args++; 169 /* Neither -t DIR nor -d is in use */
167 170 argc--;
171 last = argv[argc];
172 argv[argc] = NULL;
168 /* coreutils install resolves link in this case, don't use lstat */ 173 /* coreutils install resolves link in this case, don't use lstat */
169 isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode); 174 isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
170 } 175 }
171 176
172 if (argc < min_args) 177 if (argc < 1)
173 bb_show_usage(); 178 bb_show_usage();
174 179
175 while ((arg = *argv++) != NULL) { 180 while ((arg = *argv++) != NULL) {
176 char *dest = last; 181 char *dest;
182
177 if (opts & OPT_DIRECTORY) { 183 if (opts & OPT_DIRECTORY) {
178 dest = arg; 184 dest = arg;
179 /* GNU coreutils 6.9 does not set uid:gid 185 /* GNU coreutils 6.9 does not set uid:gid
@@ -184,6 +190,7 @@ int install_main(int argc, char **argv)
184 goto next; 190 goto next;
185 } 191 }
186 } else { 192 } else {
193 dest = last;
187 if (opts & OPT_MKDIR_LEADING) { 194 if (opts & OPT_MKDIR_LEADING) {
188 char *ddir = xstrdup(dest); 195 char *ddir = xstrdup(dest);
189 bb_make_directory(dirname(ddir), 0755, mkdir_flags); 196 bb_make_directory(dirname(ddir), 0755, mkdir_flags);
diff --git a/coreutils/test.c b/coreutils/test.c
index ba1dbaa2f..6b16ffeb1 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -845,7 +845,6 @@ int test_main(int argc, char **argv)
845{ 845{
846 int res; 846 int res;
847 const char *arg0; 847 const char *arg0;
848// bool negate = 0;
849 848
850 arg0 = bb_basename(argv[0]); 849 arg0 = bb_basename(argv[0]);
851 if (arg0[0] == '[') { 850 if (arg0[0] == '[') {
@@ -863,6 +862,7 @@ int test_main(int argc, char **argv)
863 } 862 }
864 argv[argc] = NULL; 863 argv[argc] = NULL;
865 } 864 }
865 /* argc is unused after this point */
866 866
867 /* We must do DEINIT_S() prior to returning */ 867 /* We must do DEINIT_S() prior to returning */
868 INIT_S(); 868 INIT_S();
@@ -881,43 +881,45 @@ int test_main(int argc, char **argv)
881 */ 881 */
882 /*ngroups = 0; - done by INIT_S() */ 882 /*ngroups = 0; - done by INIT_S() */
883 883
884 //argc--;
885 argv++; 884 argv++;
885 args = argv;
886 886
887 /* Implement special cases from POSIX.2, section 4.62.4 */ 887 /* Implement special cases from POSIX.2, section 4.62.4.
888 if (!argv[0]) { /* "test" */ 888 * Testcase: "test '(' = '('"
889 res = 1; 889 * The general parser would misinterpret '(' as group start.
890 goto ret; 890 */
891 } 891 if (1) {
892#if 0 892 int negate = 0;
893// Now it's fixed in the parser and should not be needed 893 again:
894 if (LONE_CHAR(argv[0], '!') && argv[1]) { 894 if (!argv[0]) {
895 negate = 1; 895 /* "test" */
896 //argc--; 896 res = 1;
897 argv++; 897 goto ret_special;
898 } 898 }
899 if (!argv[1]) { /* "test [!] arg" */ 899 if (!argv[1]) {
900 res = (*argv[0] == '\0'); 900 /* "test [!] arg" */
901 goto ret; 901 res = (argv[0][0] == '\0');
902 } 902 goto ret_special;
903 if (argv[2] && !argv[3]) { 903 }
904 check_operator(argv[1]); 904 if (argv[2] && !argv[3]) {
905 if (last_operator->op_type == BINOP) { 905 check_operator(argv[1]);
906 /* "test [!] arg1 <binary_op> arg2" */ 906 if (last_operator->op_type == BINOP) {
907 args = argv; 907 /* "test [!] arg1 <binary_op> arg2" */
908 res = (binop() == 0); 908 args = argv;
909 goto ret; 909 res = (binop() == 0);
910 ret_special:
911 /* If there was leading "!" op... */
912 res ^= negate;
913 goto ret;
914 }
915 }
916 if (LONE_CHAR(argv[0], '!')) {
917 argv++;
918 negate ^= 1;
919 goto again;
910 } 920 }
911 } 921 }
912 922
913 /* Some complex expression. Undo '!' removal */
914 if (negate) {
915 negate = 0;
916 //argc++;
917 argv--;
918 }
919#endif
920 args = argv;
921 res = !oexpr(check_operator(*args)); 923 res = !oexpr(check_operator(*args));
922 924
923 if (*args != NULL && *++args != NULL) { 925 if (*args != NULL && *++args != NULL) {
@@ -930,6 +932,5 @@ int test_main(int argc, char **argv)
930 } 932 }
931 ret: 933 ret:
932 DEINIT_S(); 934 DEINIT_S();
933// return negate ? !res : res;
934 return res; 935 return res;
935} 936}
diff --git a/editors/sed.c b/editors/sed.c
index e18e48ab5..2c64ad500 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -395,7 +395,9 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
395 /* process the flags */ 395 /* process the flags */
396 396
397 sed_cmd->which_match = 1; 397 sed_cmd->which_match = 1;
398 dbg("s flags:'%s'", substr + idx + 1);
398 while (substr[++idx]) { 399 while (substr[++idx]) {
400 dbg("s flag:'%c'", substr[idx]);
399 /* Parse match number */ 401 /* Parse match number */
400 if (isdigit(substr[idx])) { 402 if (isdigit(substr[idx])) {
401 if (match[0] != '^') { 403 if (match[0] != '^') {
@@ -403,7 +405,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
403 const char *pos = substr + idx; 405 const char *pos = substr + idx;
404/* FIXME: error check? */ 406/* FIXME: error check? */
405 sed_cmd->which_match = (unsigned)strtol(substr+idx, (char**) &pos, 10); 407 sed_cmd->which_match = (unsigned)strtol(substr+idx, (char**) &pos, 10);
406 idx = pos - substr; 408 idx = pos - substr - 1;
407 } 409 }
408 continue; 410 continue;
409 } 411 }
@@ -443,6 +445,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
443 case '}': 445 case '}':
444 goto out; 446 goto out;
445 default: 447 default:
448 dbg("s bad flags:'%s'", substr + idx);
446 bb_error_msg_and_die("bad option in substitution expression"); 449 bb_error_msg_and_die("bad option in substitution expression");
447 } 450 }
448 } 451 }
@@ -1519,12 +1522,16 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1519 1522
1520 /* -i: process each FILE separately: */ 1523 /* -i: process each FILE separately: */
1521 1524
1525 if (stat(*argv, &statbuf) != 0) {
1526 bb_simple_perror_msg(*argv);
1527 G.exitcode = EXIT_FAILURE;
1528 G.current_input_file++;
1529 continue;
1530 }
1522 G.outname = xasprintf("%sXXXXXX", *argv); 1531 G.outname = xasprintf("%sXXXXXX", *argv);
1523 nonstdoutfd = xmkstemp(G.outname); 1532 nonstdoutfd = xmkstemp(G.outname);
1524 G.nonstdout = xfdopen_for_write(nonstdoutfd); 1533 G.nonstdout = xfdopen_for_write(nonstdoutfd);
1525
1526 /* Set permissions/owner of output file */ 1534 /* Set permissions/owner of output file */
1527 stat(*argv, &statbuf);
1528 /* chmod'ing AFTER chown would preserve suid/sgid bits, 1535 /* chmod'ing AFTER chown would preserve suid/sgid bits,
1529 * but GNU sed 4.2.1 does not preserve them either */ 1536 * but GNU sed 4.2.1 does not preserve them either */
1530 fchmod(nonstdoutfd, statbuf.st_mode); 1537 fchmod(nonstdoutfd, statbuf.st_mode);
diff --git a/editors/vi.c b/editors/vi.c
index a6505e0bf..0c6906c6b 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -566,8 +566,7 @@ static void redraw(int); // force a full screen refresh
566static char* format_line(char* /*, int*/); 566static char* format_line(char* /*, int*/);
567static void refresh(int); // update the terminal from screen[] 567static void refresh(int); // update the terminal from screen[]
568 568
569static void Indicate_Error(void); // use flash or beep to indicate error 569static void indicate_error(void); // use flash or beep to indicate error
570#define indicate_error(c) Indicate_Error()
571static void Hit_Return(void); 570static void Hit_Return(void);
572 571
573#if ENABLE_FEATURE_VI_SEARCH 572#if ENABLE_FEATURE_VI_SEARCH
@@ -1840,11 +1839,11 @@ static char *bound_dot(char *p) // make sure text[0] <= P < "end"
1840{ 1839{
1841 if (p >= end && end > text) { 1840 if (p >= end && end > text) {
1842 p = end - 1; 1841 p = end - 1;
1843 indicate_error('1'); 1842 indicate_error();
1844 } 1843 }
1845 if (p < text) { 1844 if (p < text) {
1846 p = text; 1845 p = text;
1847 indicate_error('2'); 1846 indicate_error();
1848 } 1847 }
1849 return p; 1848 return p;
1850} 1849}
@@ -2023,16 +2022,9 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
2023 p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); // shrink buffer 1 char 2022 p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); // shrink buffer 1 char
2024 } 2023 }
2025 } else { 2024 } else {
2026#if ENABLE_FEATURE_VI_SETOPTS
2027 // insert a char into text[] 2025 // insert a char into text[]
2028 char *sp; // "save p"
2029#endif
2030
2031 if (c == 13) 2026 if (c == 13)
2032 c = '\n'; // translate \r to \n 2027 c = '\n'; // translate \r to \n
2033#if ENABLE_FEATURE_VI_SETOPTS
2034 sp = p; // remember addr of insert
2035#endif
2036#if ENABLE_FEATURE_VI_UNDO 2028#if ENABLE_FEATURE_VI_UNDO
2037# if ENABLE_FEATURE_VI_UNDO_QUEUE 2029# if ENABLE_FEATURE_VI_UNDO_QUEUE
2038 if (c == '\n') 2030 if (c == '\n')
@@ -2056,8 +2048,8 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
2056#endif /* ENABLE_FEATURE_VI_UNDO */ 2048#endif /* ENABLE_FEATURE_VI_UNDO */
2057 p += 1 + stupid_insert(p, c); // insert the char 2049 p += 1 + stupid_insert(p, c); // insert the char
2058#if ENABLE_FEATURE_VI_SETOPTS 2050#if ENABLE_FEATURE_VI_SETOPTS
2059 if (showmatch && strchr(")]}", *sp) != NULL) { 2051 if (showmatch && strchr(")]}", c) != NULL) {
2060 showmatching(sp); 2052 showmatching(p - 1);
2061 } 2053 }
2062 if (autoindent && c == '\n') { // auto indent the new line 2054 if (autoindent && c == '\n') { // auto indent the new line
2063 char *q; 2055 char *q;
@@ -2217,34 +2209,32 @@ static char *skip_thing(char *p, int linecnt, int dir, int type)
2217} 2209}
2218 2210
2219// find matching char of pair () [] {} 2211// find matching char of pair () [] {}
2212// will crash if c is not one of these
2220static char *find_pair(char *p, const char c) 2213static char *find_pair(char *p, const char c)
2221{ 2214{
2222 char match, *q; 2215 const char *braces = "()[]{}";
2216 char match;
2223 int dir, level; 2217 int dir, level;
2224 2218
2225 match = ')'; 2219 dir = strchr(braces, c) - braces;
2220 dir ^= 1;
2221 match = braces[dir];
2222 dir = ((dir & 1) << 1) - 1; /* 1 for ([{, -1 for )\} */
2223
2224 // look for match, count levels of pairs (( ))
2226 level = 1; 2225 level = 1;
2227 dir = 1; // assume forward 2226 for (;;) {
2228 switch (c) { 2227 p += dir;
2229 case '(': match = ')'; break; 2228 if (p < text || p >= end)
2230 case '[': match = ']'; break; 2229 return NULL;
2231 case '{': match = '}'; break; 2230 if (*p == c)
2232 case ')': match = '('; dir = -1; break;
2233 case ']': match = '['; dir = -1; break;
2234 case '}': match = '{'; dir = -1; break;
2235 }
2236 for (q = p + dir; text <= q && q < end; q += dir) {
2237 // look for match, count levels of pairs (( ))
2238 if (*q == c)
2239 level++; // increase pair levels 2231 level++; // increase pair levels
2240 if (*q == match) 2232 if (*p == match) {
2241 level--; // reduce pair level 2233 level--; // reduce pair level
2242 if (level == 0) 2234 if (level == 0)
2243 break; // found matching pair 2235 return p; // found matching pair
2236 }
2244 } 2237 }
2245 if (level != 0)
2246 q = NULL; // indicate no match
2247 return q;
2248} 2238}
2249 2239
2250#if ENABLE_FEATURE_VI_SETOPTS 2240#if ENABLE_FEATURE_VI_SETOPTS
@@ -2256,7 +2246,7 @@ static void showmatching(char *p)
2256 // we found half of a pair 2246 // we found half of a pair
2257 q = find_pair(p, *p); // get loc of matching char 2247 q = find_pair(p, *p); // get loc of matching char
2258 if (q == NULL) { 2248 if (q == NULL) {
2259 indicate_error('3'); // no matching char 2249 indicate_error(); // no matching char
2260 } else { 2250 } else {
2261 // "q" now points to matching pair 2251 // "q" now points to matching pair
2262 save_dot = dot; // remember where we are 2252 save_dot = dot; // remember where we are
@@ -2823,6 +2813,9 @@ static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2823#else 2813#else
2824 struct pollfd pfd[1]; 2814 struct pollfd pfd[1];
2825 2815
2816 if (hund != 0)
2817 fflush_all();
2818
2826 pfd[0].fd = STDIN_FILENO; 2819 pfd[0].fd = STDIN_FILENO;
2827 pfd[0].events = POLLIN; 2820 pfd[0].events = POLLIN;
2828 return safe_poll(pfd, 1, hund*10) > 0; 2821 return safe_poll(pfd, 1, hund*10) > 0;
@@ -3106,7 +3099,7 @@ static void flash(int h)
3106 redraw(TRUE); 3099 redraw(TRUE);
3107} 3100}
3108 3101
3109static void Indicate_Error(void) 3102static void indicate_error(void)
3110{ 3103{
3111#if ENABLE_FEATURE_VI_CRASHME 3104#if ENABLE_FEATURE_VI_CRASHME
3112 if (crashme > 0) 3105 if (crashme > 0)
@@ -3649,7 +3642,7 @@ static void do_cmd(int c)
3649 break; 3642 break;
3650 case 27: // esc 3643 case 27: // esc
3651 if (cmd_mode == 0) 3644 if (cmd_mode == 0)
3652 indicate_error(c); 3645 indicate_error();
3653 cmd_mode = 0; // stop insrting 3646 cmd_mode = 0; // stop insrting
3654 undo_queue_commit(); 3647 undo_queue_commit();
3655 end_cmd_q(); 3648 end_cmd_q();
@@ -3668,7 +3661,7 @@ static void do_cmd(int c)
3668 if ((unsigned)c1 <= 25) { // a-z? 3661 if ((unsigned)c1 <= 25) { // a-z?
3669 YDreg = c1; 3662 YDreg = c1;
3670 } else { 3663 } else {
3671 indicate_error(c); 3664 indicate_error();
3672 } 3665 }
3673 break; 3666 break;
3674 case '\'': // '- goto a specific mark 3667 case '\'': // '- goto a specific mark
@@ -3686,7 +3679,7 @@ static void do_cmd(int c)
3686 dot_begin(); // go to B-o-l 3679 dot_begin(); // go to B-o-l
3687 dot_skip_over_ws(); 3680 dot_skip_over_ws();
3688 } else { 3681 } else {
3689 indicate_error(c); 3682 indicate_error();
3690 } 3683 }
3691 break; 3684 break;
3692 case 'm': // m- Mark a line 3685 case 'm': // m- Mark a line
@@ -3699,7 +3692,7 @@ static void do_cmd(int c)
3699 // remember the line 3692 // remember the line
3700 mark[c1] = dot; 3693 mark[c1] = dot;
3701 } else { 3694 } else {
3702 indicate_error(c); 3695 indicate_error();
3703 } 3696 }
3704 break; 3697 break;
3705 case 'P': // P- Put register before 3698 case 'P': // P- Put register before
@@ -3760,7 +3753,7 @@ static void do_cmd(int c)
3760 // we found half of a pair 3753 // we found half of a pair
3761 p = find_pair(q, *q); 3754 p = find_pair(q, *q);
3762 if (p == NULL) { 3755 if (p == NULL) {
3763 indicate_error(c); 3756 indicate_error();
3764 } else { 3757 } else {
3765 dot = p; 3758 dot = p;
3766 } 3759 }
@@ -3768,7 +3761,7 @@ static void do_cmd(int c)
3768 } 3761 }
3769 } 3762 }
3770 if (*q == '\n') 3763 if (*q == '\n')
3771 indicate_error(c); 3764 indicate_error();
3772 break; 3765 break;
3773 case 'f': // f- forward to a user specified char 3766 case 'f': // f- forward to a user specified char
3774 last_forward_char = get_one_char(); // get the search char 3767 last_forward_char = get_one_char(); // get the search char
@@ -4101,7 +4094,7 @@ static void do_cmd(int c)
4101 // ZZ means to save file (if necessary), then exit 4094 // ZZ means to save file (if necessary), then exit
4102 c1 = get_one_char(); 4095 c1 = get_one_char();
4103 if (c1 != 'Z') { 4096 if (c1 != 'Z') {
4104 indicate_error(c); 4097 indicate_error();
4105 break; 4098 break;
4106 } 4099 }
4107 if (modified_count) { 4100 if (modified_count) {
@@ -4185,7 +4178,7 @@ static void do_cmd(int c)
4185 // could not recognize object 4178 // could not recognize object
4186 c = c1 = 27; // error- 4179 c = c1 = 27; // error-
4187 ml = 0; 4180 ml = 0;
4188 indicate_error(c); 4181 indicate_error();
4189 } 4182 }
4190 if (ml && whole) { 4183 if (ml && whole) {
4191 if (c == 'c') { 4184 if (c == 'c') {
diff --git a/findutils/find.c b/findutils/find.c
index 56a7ed3ab..83aa63f92 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -558,8 +558,8 @@ ACTF(type)
558#if ENABLE_FEATURE_FIND_PERM 558#if ENABLE_FEATURE_FIND_PERM
559ACTF(perm) 559ACTF(perm)
560{ 560{
561 /* -perm +mode: at least one of perm_mask bits are set */ 561 /* -perm [+/]mode: at least one of perm_mask bits are set */
562 if (ap->perm_char == '+') 562 if (ap->perm_char == '+' || ap->perm_char == '/')
563 return (statbuf->st_mode & ap->perm_mask) != 0; 563 return (statbuf->st_mode & ap->perm_mask) != 0;
564 /* -perm -mode: all of perm_mask are set */ 564 /* -perm -mode: all of perm_mask are set */
565 if (ap->perm_char == '-') 565 if (ap->perm_char == '-')
@@ -1252,14 +1252,14 @@ static action*** parse_params(char **argv)
1252/* -perm BITS File's mode bits are exactly BITS (octal or symbolic). 1252/* -perm BITS File's mode bits are exactly BITS (octal or symbolic).
1253 * Symbolic modes use mode 0 as a point of departure. 1253 * Symbolic modes use mode 0 as a point of departure.
1254 * -perm -BITS All of the BITS are set in file's mode. 1254 * -perm -BITS All of the BITS are set in file's mode.
1255 * -perm +BITS At least one of the BITS is set in file's mode. 1255 * -perm [+/]BITS At least one of the BITS is set in file's mode.
1256 */ 1256 */
1257 else if (parm == PARM_perm) { 1257 else if (parm == PARM_perm) {
1258 action_perm *ap; 1258 action_perm *ap;
1259 dbg("%d", __LINE__); 1259 dbg("%d", __LINE__);
1260 ap = ALLOC_ACTION(perm); 1260 ap = ALLOC_ACTION(perm);
1261 ap->perm_char = arg1[0]; 1261 ap->perm_char = arg1[0];
1262 arg1 = plus_minus_num(arg1); 1262 arg1 = (arg1[0] == '/' ? arg1+1 : plus_minus_num(arg1));
1263 /*ap->perm_mask = 0; - ALLOC_ACTION did it */ 1263 /*ap->perm_mask = 0; - ALLOC_ACTION did it */
1264 if (!bb_parse_mode(arg1, &ap->perm_mask)) 1264 if (!bb_parse_mode(arg1, &ap->perm_mask))
1265 bb_error_msg_and_die("invalid mode '%s'", arg1); 1265 bb_error_msg_and_die("invalid mode '%s'", arg1);
diff --git a/findutils/grep.c b/findutils/grep.c
index 615cacac4..0336b2927 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -676,7 +676,7 @@ static int grep_dir(const char *dir)
676 int matched = 0; 676 int matched = 0;
677 recursive_action(dir, 677 recursive_action(dir,
678 /* recurse=yes */ ACTION_RECURSE | 678 /* recurse=yes */ ACTION_RECURSE |
679 /* followLinks=no */ 679 /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 |
680 /* depthFirst=yes */ ACTION_DEPTHFIRST, 680 /* depthFirst=yes */ ACTION_DEPTHFIRST,
681 /* fileAction= */ file_action_grep, 681 /* fileAction= */ file_action_grep,
682 /* dirAction= */ NULL, 682 /* dirAction= */ NULL,
diff --git a/include/applets.src.h b/include/applets.src.h
index cb36628b5..b80c4f4e8 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -342,7 +342,6 @@ IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP))
342IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP)) 342IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP))
343IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) 343IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac))
344IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) 344IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP))
345IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP))
346/* IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP)) */ 345/* IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP)) */
347IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd)) 346IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd))
348IF_TEE(APPLET(tee, BB_DIR_USR_BIN, BB_SUID_DROP)) 347IF_TEE(APPLET(tee, BB_DIR_USR_BIN, BB_SUID_DROP))
diff --git a/include/libbb.h b/include/libbb.h
index f5ecc025f..21a56d78f 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -403,8 +403,8 @@ const char *bb_basename(const char *name) FAST_FUNC;
403char *last_char_is(const char *s, int c) FAST_FUNC; 403char *last_char_is(const char *s, int c) FAST_FUNC;
404const char* endofname(const char *name) FAST_FUNC; 404const char* endofname(const char *name) FAST_FUNC;
405 405
406void ndelay_on(int fd) FAST_FUNC; 406int ndelay_on(int fd) FAST_FUNC;
407void ndelay_off(int fd) FAST_FUNC; 407int ndelay_off(int fd) FAST_FUNC;
408void close_on_exec_on(int fd) FAST_FUNC; 408void close_on_exec_on(int fd) FAST_FUNC;
409void xdup2(int, int) FAST_FUNC; 409void xdup2(int, int) FAST_FUNC;
410void xmove_fd(int, int) FAST_FUNC; 410void xmove_fd(int, int) FAST_FUNC;
@@ -1332,6 +1332,7 @@ int sd_listen_fds(void);
1332#define SETUP_ENV_NO_CHDIR (1 << 4) 1332#define SETUP_ENV_NO_CHDIR (1 << 4)
1333void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; 1333void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC;
1334void nuke_str(char *str) FAST_FUNC; 1334void nuke_str(char *str) FAST_FUNC;
1335int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC;
1335int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; 1336int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC;
1336int ask_and_check_password(const struct passwd *pw) FAST_FUNC; 1337int ask_and_check_password(const struct passwd *pw) FAST_FUNC;
1337/* Returns a malloced string */ 1338/* Returns a malloced string */
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index d7ab1b129..1f2ed36d9 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -152,6 +152,7 @@ lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o
152lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o 152lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o
153lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o 153lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o
154lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o 154lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o
155lib-$(CONFIG_FEATURE_FTP_AUTHENTICATION) += pw_encrypt.o
155 156
156lib-$(CONFIG_DF) += find_mount_point.o 157lib-$(CONFIG_DF) += find_mount_point.o
157lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o 158lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 1d0a8f711..2c85062b4 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -184,8 +184,7 @@ void lbb_prepare(const char *applet
184#endif 184#endif
185 applet_name = applet; 185 applet_name = applet;
186 186
187 /* Set locale for everybody except 'init' */ 187 if (ENABLE_LOCALE_SUPPORT)
188 if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
189 setlocale(LC_ALL, ""); 188 setlocale(LC_ALL, "");
190 189
191#if ENABLE_PLATFORM_MINGW32 190#if ENABLE_PLATFORM_MINGW32
@@ -759,15 +758,25 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
759 758
760 /* Reinit some shared global data */ 759 /* Reinit some shared global data */
761 xfunc_error_retval = EXIT_FAILURE; 760 xfunc_error_retval = EXIT_FAILURE;
762
763 applet_name = APPLET_NAME(applet_no); 761 applet_name = APPLET_NAME(applet_no);
764 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 762
765 /* Special case. POSIX says "test --help" 763#if defined APPLET_NO_test
766 * should be no different from e.g. "test --foo". */ 764 /* Special case. POSIX says "test --help"
767//TODO: just compare applet_no with APPLET_NO_test 765 * should be no different from e.g. "test --foo".
768 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { 766 * Thus for "test", we skip --help check.
769 /* If you want "foo --help" to return 0: */ 767 */
770 xfunc_error_retval = 0; 768 if (applet_no != APPLET_NO_test)
769#endif
770 {
771 if (argc == 2 && strcmp(argv[1], "--help") == 0) {
772#if defined APPLET_NO_false
773 /* Someone insisted that "false --help" must exit 1. Sigh */
774 if (applet_no != APPLET_NO_false)
775#endif
776 {
777 /* Make "foo --help" exit with 0: */
778 xfunc_error_retval = 0;
779 }
771 bb_show_usage(); 780 bb_show_usage();
772 } 781 }
773 } 782 }
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
index 77c1bcd95..1927ba9e9 100644
--- a/libbb/bb_askpass.c
+++ b/libbb/bb_askpass.c
@@ -30,9 +30,12 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
30 struct sigaction sa, oldsa; 30 struct sigaction sa, oldsa;
31 struct termios tio, oldtio; 31 struct termios tio, oldtio;
32 32
33 tcflush(fd, TCIFLUSH);
34 /* Was buggy: was printing prompt *before* flushing input,
35 * which was upsetting "expect" based scripts of some users.
36 */
33 fputs(prompt, stdout); 37 fputs(prompt, stdout);
34 fflush_all(); 38 fflush_all();
35 tcflush(fd, TCIFLUSH);
36 39
37 tcgetattr(fd, &oldtio); 40 tcgetattr(fd, &oldtio);
38 tio = oldtio; 41 tio = oldtio;
diff --git a/libbb/correct_password.c b/libbb/correct_password.c
index acadf3914..513c93028 100644
--- a/libbb/correct_password.c
+++ b/libbb/correct_password.c
@@ -30,6 +30,63 @@
30 30
31#include "libbb.h" 31#include "libbb.h"
32 32
33#define SHADOW_BUFSIZE 256
34
35/* Retrieve encrypted password string for pw.
36 * If pw == NULL, return a string which fails password check against any
37 * password.
38 */
39#if !ENABLE_FEATURE_SHADOWPASSWDS
40#define get_passwd(pw, buffer) get_passwd(pw)
41#endif
42static const char *get_passwd(const struct passwd *pw, char buffer[SHADOW_BUFSIZE])
43{
44 const char *pass;
45
46 if (!pw)
47 return "aa"; /* "aa" will never match */
48
49 pass = pw->pw_passwd;
50#if ENABLE_FEATURE_SHADOWPASSWDS
51 /* Using _r function to avoid pulling in static buffers */
52 if ((pass[0] == 'x' || pass[0] == '*') && !pass[1]) {
53 struct spwd spw;
54 int r;
55 /* getspnam_r may return 0 yet set result to NULL.
56 * At least glibc 2.4 does this. Be extra paranoid here. */
57 struct spwd *result = NULL;
58 r = getspnam_r(pw->pw_name, &spw, buffer, SHADOW_BUFSIZE, &result);
59 pass = (r || !result) ? "aa" : result->sp_pwdp;
60 }
61#endif
62 return pass;
63}
64
65/*
66 * Return 1 if PW has an empty password.
67 * Return 1 if the user gives the correct password for entry PW,
68 * 0 if not.
69 * NULL pw means "just fake it for login with bad username"
70 */
71int FAST_FUNC check_password(const struct passwd *pw, const char *plaintext)
72{
73 IF_FEATURE_SHADOWPASSWDS(char buffer[SHADOW_BUFSIZE];)
74 char *encrypted;
75 const char *pw_pass;
76 int r;
77
78 pw_pass = get_passwd(pw, buffer);
79 if (!pw_pass[0]) { /* empty password field? */
80 return 1;
81 }
82
83 encrypted = pw_encrypt(plaintext, /*salt:*/ pw_pass, 1);
84 r = (strcmp(encrypted, pw_pass) == 0);
85 free(encrypted);
86 return r;
87}
88
89
33/* Ask the user for a password. 90/* Ask the user for a password.
34 * Return 1 without asking if PW has an empty password. 91 * Return 1 without asking if PW has an empty password.
35 * Return -1 on EOF, error while reading input, or timeout. 92 * Return -1 on EOF, error while reading input, or timeout.
@@ -41,42 +98,23 @@
41int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw, 98int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw,
42 int timeout, const char *prompt) 99 int timeout, const char *prompt)
43{ 100{
44 char *unencrypted, *encrypted; 101 IF_FEATURE_SHADOWPASSWDS(char buffer[SHADOW_BUFSIZE];)
45 const char *correct; 102 char *plaintext;
103 const char *pw_pass;
46 int r; 104 int r;
47 /* fake salt. crypt() can choke otherwise. */
48 correct = "aa";
49 if (!pw) {
50 /* "aa" will never match */
51 goto fake_it;
52 }
53 correct = pw->pw_passwd;
54#if ENABLE_FEATURE_SHADOWPASSWDS
55 /* Using _r function to avoid pulling in static buffers */
56 if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
57 struct spwd spw;
58 char buffer[256];
59 /* getspnam_r may return 0 yet set result to NULL.
60 * At least glibc 2.4 does this. Be extra paranoid here. */
61 struct spwd *result = NULL;
62 r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
63 correct = (r || !result) ? "aa" : result->sp_pwdp;
64 }
65#endif
66 105
67 if (!correct[0]) /* empty password field? */ 106 pw_pass = get_passwd(pw, buffer);
107 if (!pw_pass[0]) /* empty password field? */
68 return 1; 108 return 1;
69 109
70 fake_it: 110 plaintext = bb_ask(STDIN_FILENO, timeout, prompt);
71 unencrypted = bb_ask(STDIN_FILENO, timeout, prompt); 111 if (!plaintext) {
72 if (!unencrypted) {
73 /* EOF (such as ^D) or error (such as ^C) or timeout */ 112 /* EOF (such as ^D) or error (such as ^C) or timeout */
74 return -1; 113 return -1;
75 } 114 }
76 encrypted = pw_encrypt(unencrypted, correct, 1); 115
77 r = (strcmp(encrypted, correct) == 0); 116 r = check_password(pw, plaintext);
78 free(encrypted); 117 nuke_str(plaintext);
79 nuke_str(unencrypted);
80 return r; 118 return r;
81} 119}
82 120
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 3f743ac75..1f63ccdee 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -926,10 +926,81 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
926# define SHA3_SMALL CONFIG_SHA3_SMALL 926# define SHA3_SMALL CONFIG_SHA3_SMALL
927#endif 927#endif
928 928
929#define OPTIMIZE_SHA3_FOR_32 0
930/*
931 * SHA3 can be optimized for 32-bit CPUs with bit-slicing:
932 * every 64-bit word of state[] can be split into two 32-bit words
933 * by even/odd bits. In this form, all rotations of sha3 round
934 * are 32-bit - and there are lots of them.
935 * However, it requires either splitting/combining state words
936 * before/after sha3 round (code does this now)
937 * or shuffling bits before xor'ing them into state and in sha3_end.
938 * Without shuffling, bit-slicing results in -130 bytes of code
939 * and marginal speedup (but of course it gives wrong result).
940 * With shuffling it works, but +260 code bytes, and slower.
941 * Disabled for now:
942 */
943#if 0 /* LONG_MAX == 0x7fffffff */
944# undef OPTIMIZE_SHA3_FOR_32
945# define OPTIMIZE_SHA3_FOR_32 1
946#endif
947
929enum { 948enum {
930 SHA3_IBLK_BYTES = 72, /* 576 bits / 8 */ 949 SHA3_IBLK_BYTES = 72, /* 576 bits / 8 */
931}; 950};
932 951
952#if OPTIMIZE_SHA3_FOR_32
953/* This splits every 64-bit word into a pair of 32-bit words,
954 * even bits go into first word, odd bits go to second one.
955 * The conversion is done in-place.
956 */
957static void split_halves(uint64_t *state)
958{
959 /* Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
960 uint32_t *s32 = (uint32_t*)state;
961 uint32_t t, x0, x1;
962 int i;
963 for (i = 24; i >= 0; --i) {
964 x0 = s32[0];
965 t = (x0 ^ (x0 >> 1)) & 0x22222222; x0 = x0 ^ t ^ (t << 1);
966 t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0C; x0 = x0 ^ t ^ (t << 2);
967 t = (x0 ^ (x0 >> 4)) & 0x00F000F0; x0 = x0 ^ t ^ (t << 4);
968 t = (x0 ^ (x0 >> 8)) & 0x0000FF00; x0 = x0 ^ t ^ (t << 8);
969 x1 = s32[1];
970 t = (x1 ^ (x1 >> 1)) & 0x22222222; x1 = x1 ^ t ^ (t << 1);
971 t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0C; x1 = x1 ^ t ^ (t << 2);
972 t = (x1 ^ (x1 >> 4)) & 0x00F000F0; x1 = x1 ^ t ^ (t << 4);
973 t = (x1 ^ (x1 >> 8)) & 0x0000FF00; x1 = x1 ^ t ^ (t << 8);
974 *s32++ = (x0 & 0x0000FFFF) | (x1 << 16);
975 *s32++ = (x0 >> 16) | (x1 & 0xFFFF0000);
976 }
977}
978/* The reverse operation */
979static void combine_halves(uint64_t *state)
980{
981 uint32_t *s32 = (uint32_t*)state;
982 uint32_t t, x0, x1;
983 int i;
984 for (i = 24; i >= 0; --i) {
985 x0 = s32[0];
986 x1 = s32[1];
987 t = (x0 & 0x0000FFFF) | (x1 << 16);
988 x1 = (x0 >> 16) | (x1 & 0xFFFF0000);
989 x0 = t;
990 t = (x0 ^ (x0 >> 8)) & 0x0000FF00; x0 = x0 ^ t ^ (t << 8);
991 t = (x0 ^ (x0 >> 4)) & 0x00F000F0; x0 = x0 ^ t ^ (t << 4);
992 t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0C; x0 = x0 ^ t ^ (t << 2);
993 t = (x0 ^ (x0 >> 1)) & 0x22222222; x0 = x0 ^ t ^ (t << 1);
994 *s32++ = x0;
995 t = (x1 ^ (x1 >> 8)) & 0x0000FF00; x1 = x1 ^ t ^ (t << 8);
996 t = (x1 ^ (x1 >> 4)) & 0x00F000F0; x1 = x1 ^ t ^ (t << 4);
997 t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0C; x1 = x1 ^ t ^ (t << 2);
998 t = (x1 ^ (x1 >> 1)) & 0x22222222; x1 = x1 ^ t ^ (t << 1);
999 *s32++ = x1;
1000 }
1001}
1002#endif
1003
933/* 1004/*
934 * In the crypto literature this function is usually called Keccak-f(). 1005 * In the crypto literature this function is usually called Keccak-f().
935 */ 1006 */
@@ -937,12 +1008,179 @@ static void sha3_process_block72(uint64_t *state)
937{ 1008{
938 enum { NROUNDS = 24 }; 1009 enum { NROUNDS = 24 };
939 1010
940 /* Elements should be 64-bit, but top half is always zero or 0x80000000. 1011#if OPTIMIZE_SHA3_FOR_32
941 * We encode 63rd bits in a separate word below. 1012 /*
942 * Same is true for 31th bits, which lets us use 16-bit table instead of 64-bit. 1013 static const uint32_t IOTA_CONST_0[NROUNDS] = {
943 * The speed penalty is lost in the noise. 1014 0x00000001UL,
944 */ 1015 0x00000000UL,
1016 0x00000000UL,
1017 0x00000000UL,
1018 0x00000001UL,
1019 0x00000001UL,
1020 0x00000001UL,
1021 0x00000001UL,
1022 0x00000000UL,
1023 0x00000000UL,
1024 0x00000001UL,
1025 0x00000000UL,
1026 0x00000001UL,
1027 0x00000001UL,
1028 0x00000001UL,
1029 0x00000001UL,
1030 0x00000000UL,
1031 0x00000000UL,
1032 0x00000000UL,
1033 0x00000000UL,
1034 0x00000001UL,
1035 0x00000000UL,
1036 0x00000001UL,
1037 0x00000000UL,
1038 };
1039 ** bits are in lsb: 0101 0000 1111 0100 1111 0001
1040 */
1041 uint32_t IOTA_CONST_0bits = (uint32_t)(0x0050f4f1);
1042 static const uint32_t IOTA_CONST_1[NROUNDS] = {
1043 0x00000000UL,
1044 0x00000089UL,
1045 0x8000008bUL,
1046 0x80008080UL,
1047 0x0000008bUL,
1048 0x00008000UL,
1049 0x80008088UL,
1050 0x80000082UL,
1051 0x0000000bUL,
1052 0x0000000aUL,
1053 0x00008082UL,
1054 0x00008003UL,
1055 0x0000808bUL,
1056 0x8000000bUL,
1057 0x8000008aUL,
1058 0x80000081UL,
1059 0x80000081UL,
1060 0x80000008UL,
1061 0x00000083UL,
1062 0x80008003UL,
1063 0x80008088UL,
1064 0x80000088UL,
1065 0x00008000UL,
1066 0x80008082UL,
1067 };
1068
1069 uint32_t *const s32 = (uint32_t*)state;
1070 unsigned round;
1071
1072 split_halves(state);
1073
1074 for (round = 0; round < NROUNDS; round++) {
1075 unsigned x;
1076
1077 /* Theta */
1078 {
1079 uint32_t BC[20];
1080 for (x = 0; x < 10; ++x) {
1081 BC[x+10] = BC[x] = s32[x]^s32[x+10]^s32[x+20]^s32[x+30]^s32[x+40];
1082 }
1083 for (x = 0; x < 10; x += 2) {
1084 uint32_t ta, tb;
1085 ta = BC[x+8] ^ rotl32(BC[x+3], 1);
1086 tb = BC[x+9] ^ BC[x+2];
1087 s32[x+0] ^= ta;
1088 s32[x+1] ^= tb;
1089 s32[x+10] ^= ta;
1090 s32[x+11] ^= tb;
1091 s32[x+20] ^= ta;
1092 s32[x+21] ^= tb;
1093 s32[x+30] ^= ta;
1094 s32[x+31] ^= tb;
1095 s32[x+40] ^= ta;
1096 s32[x+41] ^= tb;
1097 }
1098 }
1099 /* RhoPi */
1100 {
1101 uint32_t t0a,t0b, t1a,t1b;
1102 t1a = s32[1*2+0];
1103 t1b = s32[1*2+1];
1104
1105#define RhoPi(PI_LANE, ROT_CONST) \
1106 t0a = s32[PI_LANE*2+0];\
1107 t0b = s32[PI_LANE*2+1];\
1108 if (ROT_CONST & 1) {\
1109 s32[PI_LANE*2+0] = rotl32(t1b, ROT_CONST/2+1);\
1110 s32[PI_LANE*2+1] = ROT_CONST == 1 ? t1a : rotl32(t1a, ROT_CONST/2+0);\
1111 } else {\
1112 s32[PI_LANE*2+0] = rotl32(t1a, ROT_CONST/2);\
1113 s32[PI_LANE*2+1] = rotl32(t1b, ROT_CONST/2);\
1114 }\
1115 t1a = t0a; t1b = t0b;
1116
1117 RhoPi(10, 1)
1118 RhoPi( 7, 3)
1119 RhoPi(11, 6)
1120 RhoPi(17,10)
1121 RhoPi(18,15)
1122 RhoPi( 3,21)
1123 RhoPi( 5,28)
1124 RhoPi(16,36)
1125 RhoPi( 8,45)
1126 RhoPi(21,55)
1127 RhoPi(24, 2)
1128 RhoPi( 4,14)
1129 RhoPi(15,27)
1130 RhoPi(23,41)
1131 RhoPi(19,56)
1132 RhoPi(13, 8)
1133 RhoPi(12,25)
1134 RhoPi( 2,43)
1135 RhoPi(20,62)
1136 RhoPi(14,18)
1137 RhoPi(22,39)
1138 RhoPi( 9,61)
1139 RhoPi( 6,20)
1140 RhoPi( 1,44)
1141#undef RhoPi
1142 }
1143 /* Chi */
1144 for (x = 0; x <= 40;) {
1145 uint32_t BC0, BC1, BC2, BC3, BC4;
1146 BC0 = s32[x + 0*2];
1147 BC1 = s32[x + 1*2];
1148 BC2 = s32[x + 2*2];
1149 s32[x + 0*2] = BC0 ^ ((~BC1) & BC2);
1150 BC3 = s32[x + 3*2];
1151 s32[x + 1*2] = BC1 ^ ((~BC2) & BC3);
1152 BC4 = s32[x + 4*2];
1153 s32[x + 2*2] = BC2 ^ ((~BC3) & BC4);
1154 s32[x + 3*2] = BC3 ^ ((~BC4) & BC0);
1155 s32[x + 4*2] = BC4 ^ ((~BC0) & BC1);
1156 x++;
1157 BC0 = s32[x + 0*2];
1158 BC1 = s32[x + 1*2];
1159 BC2 = s32[x + 2*2];
1160 s32[x + 0*2] = BC0 ^ ((~BC1) & BC2);
1161 BC3 = s32[x + 3*2];
1162 s32[x + 1*2] = BC1 ^ ((~BC2) & BC3);
1163 BC4 = s32[x + 4*2];
1164 s32[x + 2*2] = BC2 ^ ((~BC3) & BC4);
1165 s32[x + 3*2] = BC3 ^ ((~BC4) & BC0);
1166 s32[x + 4*2] = BC4 ^ ((~BC0) & BC1);
1167 x += 9;
1168 }
1169 /* Iota */
1170 s32[0] ^= IOTA_CONST_0bits & 1;
1171 IOTA_CONST_0bits >>= 1;
1172 s32[1] ^= IOTA_CONST_1[round];
1173 }
1174
1175 combine_halves(state);
1176#else
1177 /* Native 64-bit algorithm */
945 static const uint16_t IOTA_CONST[NROUNDS] = { 1178 static const uint16_t IOTA_CONST[NROUNDS] = {
1179 /* Elements should be 64-bit, but top half is always zero
1180 * or 0x80000000. We encode 63rd bits in a separate word below.
1181 * Same is true for 31th bits, which lets us use 16-bit table
1182 * instead of 64-bit. The speed penalty is lost in the noise.
1183 */
946 0x0001, 1184 0x0001,
947 0x8082, 1185 0x8082,
948 0x808a, 1186 0x808a,
@@ -983,7 +1221,7 @@ static void sha3_process_block72(uint64_t *state)
983 }; 1221 };
984 /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/ 1222 /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/
985 1223
986 unsigned x, y; 1224 unsigned x;
987 unsigned round; 1225 unsigned round;
988 1226
989 if (BB_BIG_ENDIAN) { 1227 if (BB_BIG_ENDIAN) {
@@ -1045,22 +1283,62 @@ static void sha3_process_block72(uint64_t *state)
1045 RhoPi_twice(20); RhoPi_twice(22); 1283 RhoPi_twice(20); RhoPi_twice(22);
1046#undef RhoPi_twice 1284#undef RhoPi_twice
1047 } 1285 }
1048
1049 /* Chi */ 1286 /* Chi */
1050 for (y = 0; y <= 20; y += 5) { 1287# if LONG_MAX > 0x7fffffff
1288 for (x = 0; x <= 20; x += 5) {
1051 uint64_t BC0, BC1, BC2, BC3, BC4; 1289 uint64_t BC0, BC1, BC2, BC3, BC4;
1052 BC0 = state[y + 0]; 1290 BC0 = state[x + 0];
1053 BC1 = state[y + 1]; 1291 BC1 = state[x + 1];
1054 BC2 = state[y + 2]; 1292 BC2 = state[x + 2];
1055 state[y + 0] = BC0 ^ ((~BC1) & BC2); 1293 state[x + 0] = BC0 ^ ((~BC1) & BC2);
1056 BC3 = state[y + 3]; 1294 BC3 = state[x + 3];
1057 state[y + 1] = BC1 ^ ((~BC2) & BC3); 1295 state[x + 1] = BC1 ^ ((~BC2) & BC3);
1058 BC4 = state[y + 4]; 1296 BC4 = state[x + 4];
1059 state[y + 2] = BC2 ^ ((~BC3) & BC4); 1297 state[x + 2] = BC2 ^ ((~BC3) & BC4);
1060 state[y + 3] = BC3 ^ ((~BC4) & BC0); 1298 state[x + 3] = BC3 ^ ((~BC4) & BC0);
1061 state[y + 4] = BC4 ^ ((~BC0) & BC1); 1299 state[x + 4] = BC4 ^ ((~BC0) & BC1);
1062 } 1300 }
1063 1301# else
1302 /* Reduced register pressure version
1303 * for register-starved 32-bit arches
1304 * (i386: -95 bytes, and it is _faster_)
1305 */
1306 for (x = 0; x <= 40;) {
1307 uint32_t BC0, BC1, BC2, BC3, BC4;
1308 uint32_t *const s32 = (uint32_t*)state;
1309# if SHA3_SMALL
1310 do_half:
1311# endif
1312 BC0 = s32[x + 0*2];
1313 BC1 = s32[x + 1*2];
1314 BC2 = s32[x + 2*2];
1315 s32[x + 0*2] = BC0 ^ ((~BC1) & BC2);
1316 BC3 = s32[x + 3*2];
1317 s32[x + 1*2] = BC1 ^ ((~BC2) & BC3);
1318 BC4 = s32[x + 4*2];
1319 s32[x + 2*2] = BC2 ^ ((~BC3) & BC4);
1320 s32[x + 3*2] = BC3 ^ ((~BC4) & BC0);
1321 s32[x + 4*2] = BC4 ^ ((~BC0) & BC1);
1322 x++;
1323# if SHA3_SMALL
1324 if (x & 1)
1325 goto do_half;
1326 x += 8;
1327# else
1328 BC0 = s32[x + 0*2];
1329 BC1 = s32[x + 1*2];
1330 BC2 = s32[x + 2*2];
1331 s32[x + 0*2] = BC0 ^ ((~BC1) & BC2);
1332 BC3 = s32[x + 3*2];
1333 s32[x + 1*2] = BC1 ^ ((~BC2) & BC3);
1334 BC4 = s32[x + 4*2];
1335 s32[x + 2*2] = BC2 ^ ((~BC3) & BC4);
1336 s32[x + 3*2] = BC3 ^ ((~BC4) & BC0);
1337 s32[x + 4*2] = BC4 ^ ((~BC0) & BC1);
1338 x += 9;
1339# endif
1340 }
1341# endif /* long is 32-bit */
1064 /* Iota */ 1342 /* Iota */
1065 state[0] ^= IOTA_CONST[round] 1343 state[0] ^= IOTA_CONST[round]
1066 | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000) 1344 | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000)
@@ -1072,6 +1350,7 @@ static void sha3_process_block72(uint64_t *state)
1072 state[x] = SWAP_LE64(state[x]); 1350 state[x] = SWAP_LE64(state[x]);
1073 } 1351 }
1074 } 1352 }
1353#endif
1075} 1354}
1076 1355
1077void FAST_FUNC sha3_begin(sha3_ctx_t *ctx) 1356void FAST_FUNC sha3_begin(sha3_ctx_t *ctx)
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 23f27516f..f25ce9446 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -25,20 +25,22 @@
25#include "libbb.h" 25#include "libbb.h"
26 26
27/* Turn on nonblocking I/O on a fd */ 27/* Turn on nonblocking I/O on a fd */
28void FAST_FUNC ndelay_on(int fd) 28int FAST_FUNC ndelay_on(int fd)
29{ 29{
30 int flags = fcntl(fd, F_GETFL); 30 int flags = fcntl(fd, F_GETFL);
31 if (flags & O_NONBLOCK) 31 if (flags & O_NONBLOCK)
32 return; 32 return flags;
33 fcntl(fd, F_SETFL, flags | O_NONBLOCK); 33 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
34 return flags;
34} 35}
35 36
36void FAST_FUNC ndelay_off(int fd) 37int FAST_FUNC ndelay_off(int fd)
37{ 38{
38 int flags = fcntl(fd, F_GETFL); 39 int flags = fcntl(fd, F_GETFL);
39 if (!(flags & O_NONBLOCK)) 40 if (!(flags & O_NONBLOCK))
40 return; 41 return flags;
41 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 42 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
43 return flags;
42} 44}
43 45
44void FAST_FUNC close_on_exec_on(int fd) 46void FAST_FUNC close_on_exec_on(int fd)
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c
index 22cd0e661..260e337f3 100644
--- a/loginutils/addgroup.c
+++ b/loginutils/addgroup.c
@@ -11,9 +11,9 @@
11 */ 11 */
12 12
13//usage:#define addgroup_trivial_usage 13//usage:#define addgroup_trivial_usage
14//usage: "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP" 14//usage: "[-g GID] [-S] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP"
15//usage:#define addgroup_full_usage "\n\n" 15//usage:#define addgroup_full_usage "\n\n"
16//usage: "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" 16//usage: "Add a group" IF_FEATURE_ADDUSER_TO_GROUP(" or add a user to a group") "\n"
17//usage: "\n -g GID Group id" 17//usage: "\n -g GID Group id"
18//usage: "\n -S Create a system group" 18//usage: "\n -S Create a system group"
19 19
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 4b1b73bef..174542841 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -334,18 +334,19 @@ static void finalize_tty_attrs(void)
334 * observed to improve backspacing through Unicode chars 334 * observed to improve backspacing through Unicode chars
335 */ 335 */
336 336
337 /* line buffered input (NL or EOL or EOF chars end a line); 337 /* ICANON line buffered input (NL or EOL or EOF chars end a line);
338 * recognize INT/QUIT/SUSP chars; 338 * ISIG recognize INT/QUIT/SUSP chars;
339 * echo input chars; 339 * ECHO echo input chars;
340 * echo BS-SP-BS on erase character; 340 * ECHOE echo BS-SP-BS on erase character;
341 * echo kill char specially, not as ^c (ECHOKE controls how exactly); 341 * ECHOK echo kill char specially, not as ^c (ECHOKE controls how exactly);
342 * erase all input via BS-SP-BS on kill char (else go to next line) 342 * ECHOKE erase all input via BS-SP-BS on kill char (else go to next line)
343 * ECHOCTL Echo ctrl chars as ^c (else echo verbatim:
344 * e.g. up arrow emits "ESC-something" and thus moves cursor up!)
343 */ 345 */
344 G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; 346 G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL;
345 /* Other bits in c_lflag: 347 /* Other bits in c_lflag:
346 * XCASE Map uppercase to \lowercase [tried, doesn't work] 348 * XCASE Map uppercase to \lowercase [tried, doesn't work]
347 * ECHONL Echo NL even if ECHO is not set 349 * ECHONL Echo NL even if ECHO is not set
348 * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this?
349 * ECHOPRT On erase, echo erased chars 350 * ECHOPRT On erase, echo erased chars
350 * [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen] 351 * [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
351 * NOFLSH Don't flush input buffer after interrupt or quit chars 352 * NOFLSH Don't flush input buffer after interrupt or quit chars
diff --git a/miscutils/Config.src b/miscutils/Config.src
index 1b2a3ae9a..d69abf1a2 100644
--- a/miscutils/Config.src
+++ b/miscutils/Config.src
@@ -499,22 +499,6 @@ config STRINGS
499 strings prints the printable character sequences for each file 499 strings prints the printable character sequences for each file
500 specified. 500 specified.
501 501
502config TASKSET
503 bool "taskset"
504 default n # doesn't build on some non-x86 targets (m68k)
505 help
506 Retrieve or set a processes's CPU affinity.
507 This requires sched_{g,s}etaffinity support in your libc.
508
509config FEATURE_TASKSET_FANCY
510 bool "Fancy output"
511 default y
512 depends on TASKSET
513 help
514 Add code for fancy output. This merely silences a compiler-warning
515 and adds about 135 Bytes. May be needed for machines with alot
516 of CPUs.
517
518config TIME 502config TIME
519 bool "time" 503 bool "time"
520 default y 504 default y
diff --git a/miscutils/Kbuild.src b/miscutils/Kbuild.src
index 8eaa82de9..7b449e6e8 100644
--- a/miscutils/Kbuild.src
+++ b/miscutils/Kbuild.src
@@ -39,7 +39,6 @@ lib-$(CONFIG_RUNLEVEL) += runlevel.o
39lib-$(CONFIG_RX) += rx.o 39lib-$(CONFIG_RX) += rx.o
40lib-$(CONFIG_SETSID) += setsid.o 40lib-$(CONFIG_SETSID) += setsid.o
41lib-$(CONFIG_STRINGS) += strings.o 41lib-$(CONFIG_STRINGS) += strings.o
42lib-$(CONFIG_TASKSET) += taskset.o
43lib-$(CONFIG_TIME) += time.o 42lib-$(CONFIG_TIME) += time.o
44lib-$(CONFIG_TIMEOUT) += timeout.o 43lib-$(CONFIG_TIMEOUT) += timeout.o
45lib-$(CONFIG_TTYSIZE) += ttysize.o 44lib-$(CONFIG_TTYSIZE) += ttysize.o
diff --git a/miscutils/less.c b/miscutils/less.c
index d84df469c..554e54687 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -414,10 +414,10 @@ static void read_lines(void)
414 char *current_line, *p; 414 char *current_line, *p;
415 int w = width; 415 int w = width;
416 char last_terminated = terminated; 416 char last_terminated = terminated;
417 time_t last_time = 0;
418 int retry_EAGAIN = 2;
417#if ENABLE_FEATURE_LESS_REGEXP 419#if ENABLE_FEATURE_LESS_REGEXP
418 unsigned old_max_fline = max_fline; 420 unsigned old_max_fline = max_fline;
419 time_t last_time = 0;
420 int had_progress = 2;
421#endif 421#endif
422 422
423 /* (careful: max_fline can be -1) */ 423 /* (careful: max_fline can be -1) */
@@ -427,17 +427,14 @@ static void read_lines(void)
427 if (option_mask32 & FLAG_N) 427 if (option_mask32 & FLAG_N)
428 w -= 8; 428 w -= 8;
429 429
430 IF_FEATURE_LESS_REGEXP(again0:)
431
432 p = current_line = ((char*)xmalloc(w + 4)) + 4; 430 p = current_line = ((char*)xmalloc(w + 4)) + 4;
433 max_fline += last_terminated;
434 if (!last_terminated) { 431 if (!last_terminated) {
435 const char *cp = flines[max_fline]; 432 const char *cp = flines[max_fline];
436 strcpy(p, cp); 433 p = stpcpy(p, cp);
437 p += strlen(current_line); 434 free(MEMPTR(cp));
438 free(MEMPTR(flines[max_fline]));
439 /* last_line_pos is still valid from previous read_lines() */ 435 /* last_line_pos is still valid from previous read_lines() */
440 } else { 436 } else {
437 max_fline++;
441 last_line_pos = 0; 438 last_line_pos = 0;
442 } 439 }
443 440
@@ -448,15 +445,29 @@ static void read_lines(void)
448 char c; 445 char c;
449 /* if no unprocessed chars left, eat more */ 446 /* if no unprocessed chars left, eat more */
450 if (readpos >= readeof) { 447 if (readpos >= readeof) {
451 errno = 0; 448 int flags = ndelay_on(0);
452 ndelay_on(0); 449
453 eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf)); 450 while (1) {
454 ndelay_off(0); 451 time_t t;
452
453 errno = 0;
454 eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf));
455 if (errno != EAGAIN)
456 break;
457 t = time(NULL);
458 if (t != last_time) {
459 last_time = t;
460 if (--retry_EAGAIN < 0)
461 break;
462 }
463 sched_yield();
464 }
465 fcntl(0, F_SETFL, flags); /* ndelay_off(0) */
455 readpos = 0; 466 readpos = 0;
456 readeof = eof_error; 467 readeof = eof_error;
457 if (eof_error <= 0) 468 if (eof_error <= 0)
458 goto reached_eof; 469 goto reached_eof;
459 IF_FEATURE_LESS_REGEXP(had_progress = 1;) 470 retry_EAGAIN = 1;
460 } 471 }
461 c = readbuf[readpos]; 472 c = readbuf[readpos];
462 /* backspace? [needed for manpages] */ 473 /* backspace? [needed for manpages] */
@@ -491,6 +502,11 @@ static void read_lines(void)
491 *p++ = c; 502 *p++ = c;
492 *p = '\0'; 503 *p = '\0';
493 } /* end of "read chars until we have a line" loop */ 504 } /* end of "read chars until we have a line" loop */
505#if 0
506//BUG: also triggers on this:
507// { printf "\nfoo\n"; sleep 1; printf "\nbar\n"; } | less
508// (resulting in lost empty line between "foo" and "bar" lines)
509// the "terminated" logic needs fixing (or explaining)
494 /* Corner case: linewrap with only "" wrapping to next line */ 510 /* Corner case: linewrap with only "" wrapping to next line */
495 /* Looks ugly on screen, so we do not store this empty line */ 511 /* Looks ugly on screen, so we do not store this empty line */
496 if (!last_terminated && !current_line[0]) { 512 if (!last_terminated && !current_line[0]) {
@@ -498,6 +514,7 @@ static void read_lines(void)
498 max_lineno++; 514 max_lineno++;
499 continue; 515 continue;
500 } 516 }
517#endif
501 reached_eof: 518 reached_eof:
502 last_terminated = terminated; 519 last_terminated = terminated;
503 flines = xrealloc_vector(flines, 8, max_fline); 520 flines = xrealloc_vector(flines, 8, max_fline);
@@ -528,24 +545,7 @@ static void read_lines(void)
528#endif 545#endif
529 } 546 }
530 if (eof_error <= 0) { 547 if (eof_error <= 0) {
531#if !ENABLE_FEATURE_LESS_REGEXP
532 break; 548 break;
533#else
534 if (wanted_match < num_matches) {
535 break;
536 } /* else: goto_match() called us */
537 if (errno == EAGAIN) {
538 time_t t = time(NULL);
539 if (t != last_time) {
540 last_time = t;
541 if (--had_progress < 0)
542 break;
543 }
544 sched_yield();
545 goto again0;
546 }
547 break;
548#endif
549 } 549 }
550 max_fline++; 550 max_fline++;
551 current_line = ((char*)xmalloc(w + 4)) + 4; 551 current_line = ((char*)xmalloc(w + 4)) + 4;
@@ -802,11 +802,18 @@ static void buffer_print(void)
802 unsigned i; 802 unsigned i;
803 803
804 move_cursor(0, 0); 804 move_cursor(0, 0);
805 for (i = 0; i <= max_displayed_line; i++) 805 for (i = 0; i <= max_displayed_line; i++) {
806 if (pattern_valid) 806 if (pattern_valid)
807 print_found(buffer[i]); 807 print_found(buffer[i]);
808 else 808 else
809 print_ascii(buffer[i]); 809 print_ascii(buffer[i]);
810 }
811 if ((option_mask32 & FLAG_E)
812 && eof_error <= 0
813 && (max_fline - cur_fline) <= max_displayed_line
814 ) {
815 less_exit(EXIT_SUCCESS);
816 }
810 status_print(); 817 status_print();
811} 818}
812 819
diff --git a/miscutils/taskset.c b/miscutils/taskset.c
index 4a9e3230d..2646e1dab 100644
--- a/miscutils/taskset.c
+++ b/miscutils/taskset.c
@@ -6,6 +6,25 @@
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */ 7 */
8 8
9//config:config TASKSET
10//config: bool "taskset"
11//config: default n # doesn't build on some non-x86 targets (m68k)
12//config: help
13//config: Retrieve or set a processes's CPU affinity.
14//config: This requires sched_{g,s}etaffinity support in your libc.
15//config:
16//config:config FEATURE_TASKSET_FANCY
17//config: bool "Fancy output"
18//config: default y
19//config: depends on TASKSET
20//config: help
21//config: Add code for fancy output. This merely silences a compiler-warning
22//config: and adds about 135 Bytes. May be needed for machines with alot
23//config: of CPUs.
24
25//applet:IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP))
26//kbuild:lib-$(CONFIG_TASKSET) += taskset.o
27
9//usage:#define taskset_trivial_usage 28//usage:#define taskset_trivial_usage
10//usage: "[-p] [MASK] [PID | PROG ARGS]" 29//usage: "[-p] [MASK] [PID | PROG ARGS]"
11//usage:#define taskset_full_usage "\n\n" 30//usage:#define taskset_full_usage "\n\n"
@@ -22,6 +41,11 @@
22//usage: "pid 6671's new affinity mask: 1\n" 41//usage: "pid 6671's new affinity mask: 1\n"
23//usage: "$ taskset -p 1\n" 42//usage: "$ taskset -p 1\n"
24//usage: "pid 1's current affinity mask: 3\n" 43//usage: "pid 1's current affinity mask: 3\n"
44/*
45 Not yet implemented:
46 * -a/--all-tasks (affect all threads)
47 * -c/--cpu-list (specify CPUs via "1,3,5-7")
48 */
25 49
26#include <sched.h> 50#include <sched.h>
27#include "libbb.h" 51#include "libbb.h"
@@ -128,17 +152,65 @@ int taskset_main(int argc UNUSED_PARAM, char **argv)
128 current_new += 8; /* "new" */ 152 current_new += 8; /* "new" */
129 } 153 }
130 154
131 { /* Affinity was specified, translate it into cpu_set_t */ 155 /* Affinity was specified, translate it into cpu_set_t */
156 CPU_ZERO(&mask);
157 if (!ENABLE_FEATURE_TASKSET_FANCY) {
132 unsigned i; 158 unsigned i;
159 unsigned long long m;
160
133 /* Do not allow zero mask: */ 161 /* Do not allow zero mask: */
134 unsigned long long m = xstrtoull_range(aff, 0, 1, ULLONG_MAX); 162 m = xstrtoull_range(aff, 0, 1, ULLONG_MAX);
135 enum { CNT_BIT = CPU_SETSIZE < sizeof(m)*8 ? CPU_SETSIZE : sizeof(m)*8 }; 163 i = 0;
164 do {
165 if (m & 1)
166 CPU_SET(i, &mask);
167 i++;
168 m >>= 1;
169 } while (m != 0);
170 } else {
171 unsigned i;
172 char *last_byte;
173 char *bin;
174 uint8_t bit_in_byte;
175
176 /* Cheap way to get "long enough" buffer */
177 bin = xstrdup(aff);
178
179 if (aff[0] != '0' || (aff[1]|0x20) != 'x') {
180/* TODO: decimal/octal masks are still limited to 2^64 */
181 unsigned long long m = xstrtoull_range(aff, 0, 1, ULLONG_MAX);
182 bin += strlen(bin);
183 last_byte = bin - 1;
184 while (m) {
185 *--bin = m & 0xff;
186 m >>= 8;
187 }
188 } else {
189 /* aff is "0x.....", we accept very long masks in this form */
190 last_byte = hex2bin(bin, aff + 2, INT_MAX);
191 if (!last_byte) {
192 bad_aff:
193 bb_error_msg_and_die("bad affinity '%s'", aff);
194 }
195 last_byte--; /* now points to the last byte */
196 }
136 197
137 CPU_ZERO(&mask); 198 i = 0;
138 for (i = 0; i < CNT_BIT; i++) { 199 bit_in_byte = 1;
139 unsigned long long bit = (1ULL << i); 200 while (last_byte >= bin) {
140 if (bit & m) 201 if (bit_in_byte & *last_byte) {
202 if (i >= CPU_SETSIZE)
203 goto bad_aff;
141 CPU_SET(i, &mask); 204 CPU_SET(i, &mask);
205 //bb_error_msg("bit %d set", i);
206 }
207 i++;
208 /* bit_in_byte is uint8_t! & 0xff is implied */
209 bit_in_byte = (bit_in_byte << 1);
210 if (!bit_in_byte) {
211 bit_in_byte = 1;
212 last_byte--;
213 }
142 } 214 }
143 } 215 }
144 216
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c
index b71393532..6c09fe534 100644
--- a/miscutils/ubi_tools.c
+++ b/miscutils/ubi_tools.c
@@ -125,12 +125,24 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
125 strcpy(path, "/sys/class/ubi/ubi"); 125 strcpy(path, "/sys/class/ubi/ubi");
126 memset(&req_structs, 0, sizeof(req_structs)); 126 memset(&req_structs, 0, sizeof(req_structs));
127 127
128#define OPTION_m (1 << 0)
129#define OPTION_d (1 << 1)
130#define OPTION_n (1 << 2)
131#define OPTION_N (1 << 3)
132#define OPTION_s (1 << 4)
133#define OPTION_a (1 << 5)
134#define OPTION_t (1 << 6)
128 if (do_mkvol) { 135 if (do_mkvol) {
129 opt_complementary = "-1:d+:n+:a+"; 136 opt_complementary = "-1:d+:n+:a+";
130 opts = getopt32(argv, "md:n:N:s:a:t:", 137 opts = getopt32(argv, "md:n:N:s:a:t:",
131 &dev_num, &vol_id, 138 &dev_num, &vol_id,
132 &vol_name, &size_bytes_str, &alignment, &type 139 &vol_name, &size_bytes_str, &alignment, &type
133 ); 140 );
141 } else
142 if (do_update) {
143 opt_complementary = "-1";
144 opts = getopt32(argv, "s:at", &size_bytes_str);
145 opts *= OPTION_s;
134 } else { 146 } else {
135 opt_complementary = "-1:m+:d+:n+:a+"; 147 opt_complementary = "-1:m+:d+:n+:a+";
136 opts = getopt32(argv, "m:d:n:N:s:a:t:", 148 opts = getopt32(argv, "m:d:n:N:s:a:t:",
@@ -138,13 +150,6 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
138 &vol_name, &size_bytes_str, &alignment, &type 150 &vol_name, &size_bytes_str, &alignment, &type
139 ); 151 );
140 } 152 }
141#define OPTION_m (1 << 0)
142#define OPTION_d (1 << 1)
143#define OPTION_n (1 << 2)
144#define OPTION_N (1 << 3)
145#define OPTION_s (1 << 4)
146#define OPTION_a (1 << 5)
147#define OPTION_t (1 << 6)
148 153
149 if (opts & OPTION_s) 154 if (opts & OPTION_s)
150 size_bytes = xatoull_sfx(size_bytes_str, size_suffixes); 155 size_bytes = xatoull_sfx(size_bytes_str, size_suffixes);
@@ -302,9 +307,9 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
302 if (!(opts & OPTION_s)) { 307 if (!(opts & OPTION_s)) {
303 if (!*argv) 308 if (!*argv)
304 bb_show_usage(); 309 bb_show_usage();
305 xstat(*argv, &st);
306 size_bytes = st.st_size;
307 xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); 310 xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO);
311 xfstat(STDIN_FILENO, &st, *argv);
312 size_bytes = st.st_size;
308 } 313 }
309 314
310 bytes64 = size_bytes; 315 bytes64 = size_bytes;
diff --git a/modutils/modinfo.c b/modutils/modinfo.c
index 7c978d1da..0ab942890 100644
--- a/modutils/modinfo.c
+++ b/modutils/modinfo.c
@@ -34,14 +34,14 @@ struct modinfo_env {
34 int tags; 34 int tags;
35}; 35};
36 36
37static int display(const char *data, const char *pattern, int flag) 37static void display(const char *data, const char *pattern, int flag)
38{ 38{
39 if (flag) { 39 if (flag) {
40 int n = printf("%s:", pattern); 40 int n = printf("%s:", pattern);
41 while (n++ < 16) 41 while (n++ < 16)
42 bb_putchar(' '); 42 bb_putchar(' ');
43 } 43 }
44 return printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n'); 44 printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n');
45} 45}
46 46
47static void modinfo(const char *path, const char *version, 47static void modinfo(const char *path, const char *version,
@@ -104,7 +104,8 @@ static void modinfo(const char *path, const char *version,
104 /* field prefixes are 0x80 or 0x00 */ 104 /* field prefixes are 0x80 or 0x00 */
105 if ((ptr[-1] & 0x7F) == '\0') { 105 if ((ptr[-1] & 0x7F) == '\0') {
106 ptr += length + 1; 106 ptr += length + 1;
107 ptr += display(ptr, pattern, (1<<j) != tags); 107 display(ptr, pattern, (1<<j) != tags);
108 ptr += strlen(ptr);
108 } 109 }
109 } 110 }
110 ++ptr; 111 ++ptr;
diff --git a/networking/Config.src b/networking/Config.src
index fbad7ecb2..e56646917 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -134,6 +134,13 @@ config FEATURE_FTPD_ACCEPT_BROKEN_LIST
134 it increases the code size by ~40 bytes. 134 it increases the code size by ~40 bytes.
135 Most other ftp servers seem to behave similar to this. 135 Most other ftp servers seem to behave similar to this.
136 136
137config FEATURE_FTP_AUTHENTICATION
138 bool "Enable authentication"
139 default y
140 depends on FTPD
141 help
142 Enable basic system login as seen in telnet etc.
143
137config FTPGET 144config FTPGET
138 bool "ftpget" 145 bool "ftpget"
139 default y 146 default y
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 2d2a3a44c..6adcb1dee 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -622,7 +622,7 @@ popen_ls(const char *opt)
622 pid_t pid; 622 pid_t pid;
623 623
624 argv[0] = "ftpd"; 624 argv[0] = "ftpd";
625 argv[1] = opt; /* "-l" or "-1" */ 625 argv[1] = opt; /* "-lA" or "-1A" */
626 argv[2] = "--"; 626 argv[2] = "--";
627 argv[3] = G.ftp_arg; 627 argv[3] = G.ftp_arg;
628 argv[4] = NULL; 628 argv[4] = NULL;
@@ -699,7 +699,7 @@ handle_dir_common(int opts)
699 if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen()) 699 if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen())
700 return; /* port_or_pasv_was_seen emitted error response */ 700 return; /* port_or_pasv_was_seen emitted error response */
701 701
702 ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1"); 702 ls_fd = popen_ls((opts & LONG_LISTING) ? "-lA" : "-1A");
703 ls_fp = xfdopen_for_read(ls_fd); 703 ls_fp = xfdopen_for_read(ls_fd);
704/* FIXME: filenames with embedded newlines are mishandled */ 704/* FIXME: filenames with embedded newlines are mishandled */
705 705
@@ -1102,10 +1102,11 @@ enum {
1102#if !BB_MMU 1102#if !BB_MMU
1103 OPT_l = (1 << 0), 1103 OPT_l = (1 << 0),
1104 OPT_1 = (1 << 1), 1104 OPT_1 = (1 << 1),
1105 OPT_A = (1 << 2),
1105#endif 1106#endif
1106 OPT_v = (1 << ((!BB_MMU) * 2 + 0)), 1107 OPT_v = (1 << ((!BB_MMU) * 3 + 0)),
1107 OPT_S = (1 << ((!BB_MMU) * 2 + 1)), 1108 OPT_S = (1 << ((!BB_MMU) * 3 + 1)),
1108 OPT_w = (1 << ((!BB_MMU) * 2 + 2)) * ENABLE_FEATURE_FTP_WRITE, 1109 OPT_w = (1 << ((!BB_MMU) * 3 + 2)) * ENABLE_FEATURE_FTP_WRITE,
1109}; 1110};
1110 1111
1111int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1112int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -1126,12 +1127,11 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1126 G.timeout = 2 * 60; 1127 G.timeout = 2 * 60;
1127 opt_complementary = "t+:T+:vv:SS"; 1128 opt_complementary = "t+:T+:vv:SS";
1128#if BB_MMU 1129#if BB_MMU
1129 opts = getopt32(argv, "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1130 opts = getopt32(argv, "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
1130#else 1131#else
1131 opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1132 opts = getopt32(argv, "l1AvS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
1132 if (opts & (OPT_l|OPT_1)) { 1133 if (opts & (OPT_l|OPT_1)) {
1133 /* Our secret backdoor to ls */ 1134 /* Our secret backdoor to ls */
1134/* TODO: pass -A? It shows dot files */
1135/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */ 1135/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */
1136 if (fchdir(3) != 0) 1136 if (fchdir(3) != 0)
1137 _exit(127); 1137 _exit(127);
@@ -1172,18 +1172,6 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1172 if (logmode) 1172 if (logmode)
1173 applet_name = xasprintf("%s[%u]", applet_name, (int)getpid()); 1173 applet_name = xasprintf("%s[%u]", applet_name, (int)getpid());
1174 1174
1175#if !BB_MMU
1176 G.root_fd = -1;
1177#endif
1178 argv += optind;
1179 if (argv[0]) {
1180#if !BB_MMU
1181 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
1182 close_on_exec_on(G.root_fd);
1183#endif
1184 xchroot(argv[0]);
1185 }
1186
1187 //umask(077); - admin can set umask before starting us 1175 //umask(077); - admin can set umask before starting us
1188 1176
1189 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ 1177 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
@@ -1199,23 +1187,22 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1199 WRITE_OK(FTP_GREET); 1187 WRITE_OK(FTP_GREET);
1200 signal(SIGALRM, timeout_handler); 1188 signal(SIGALRM, timeout_handler);
1201 1189
1202#ifdef IF_WE_WANT_TO_REQUIRE_LOGIN 1190#if ENABLE_FEATURE_FTP_AUTHENTICATION
1203 { 1191 {
1204 smallint user_was_specified = 0; 1192 struct passwd *pw = NULL;
1193
1205 while (1) { 1194 while (1) {
1206 uint32_t cmdval = cmdio_get_cmd_and_arg(); 1195 uint32_t cmdval = cmdio_get_cmd_and_arg();
1207 1196
1208 if (cmdval == const_USER) { 1197 if (cmdval == const_USER) {
1209 if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0) 1198 pw = getpwnam(G.ftp_arg);
1210 cmdio_write_raw(STR(FTP_LOGINERR)" Server is anonymous only\r\n"); 1199 cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n");
1211 else {
1212 user_was_specified = 1;
1213 cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify the password\r\n");
1214 }
1215 } else if (cmdval == const_PASS) { 1200 } else if (cmdval == const_PASS) {
1216 if (user_was_specified) 1201 if (check_password(pw, G.ftp_arg) > 0) {
1217 break; 1202 break; /* login success */
1218 cmdio_write_raw(STR(FTP_NEEDUSER)" Login with USER\r\n"); 1203 }
1204 cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n");
1205 pw = NULL;
1219 } else if (cmdval == const_QUIT) { 1206 } else if (cmdval == const_QUIT) {
1220 WRITE_OK(FTP_GOODBYE); 1207 WRITE_OK(FTP_GOODBYE);
1221 return 0; 1208 return 0;
@@ -1223,10 +1210,24 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1223 cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); 1210 cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n");
1224 } 1211 }
1225 } 1212 }
1213 change_identity(pw);
1226 } 1214 }
1227 WRITE_OK(FTP_LOGINOK); 1215 WRITE_OK(FTP_LOGINOK);
1228#endif 1216#endif
1229 1217
1218 /* Do this after auth, else /etc/passwd is not accessible */
1219#if !BB_MMU
1220 G.root_fd = -1;
1221#endif
1222 argv += optind;
1223 if (argv[0]) {
1224#if !BB_MMU
1225 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
1226 close_on_exec_on(G.root_fd);
1227#endif
1228 xchroot(argv[0]);
1229 }
1230
1230 /* RFC-959 Section 5.1 1231 /* RFC-959 Section 5.1
1231 * The following commands and options MUST be supported by every 1232 * The following commands and options MUST be supported by every
1232 * server-FTP and user-FTP, except in cases where the underlying 1233 * server-FTP and user-FTP, except in cases where the underlying
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 59607ed23..2d4f076d9 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -29,7 +29,7 @@
29 */ 29 */
30 30
31//usage:#define ntpd_trivial_usage 31//usage:#define ntpd_trivial_usage
32//usage: "[-dnqNw"IF_FEATURE_NTPD_SERVER("l")"] [-S PROG] [-p PEER]..." 32//usage: "[-dnqNw"IF_FEATURE_NTPD_SERVER("l -I IFACE")"] [-S PROG] [-p PEER]..."
33//usage:#define ntpd_full_usage "\n\n" 33//usage:#define ntpd_full_usage "\n\n"
34//usage: "NTP client/server\n" 34//usage: "NTP client/server\n"
35//usage: "\n -d Verbose" 35//usage: "\n -d Verbose"
@@ -39,6 +39,7 @@
39//usage: "\n -w Do not set time (only query peers), implies -n" 39//usage: "\n -w Do not set time (only query peers), implies -n"
40//usage: IF_FEATURE_NTPD_SERVER( 40//usage: IF_FEATURE_NTPD_SERVER(
41//usage: "\n -l Run as server on port 123" 41//usage: "\n -l Run as server on port 123"
42//usage: "\n -I IFACE Bind server to IFACE, implies -l"
42//usage: ) 43//usage: )
43//usage: "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins" 44//usage: "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins"
44//usage: "\n -p PEER Obtain time from PEER (may be repeated)" 45//usage: "\n -p PEER Obtain time from PEER (may be repeated)"
@@ -108,36 +109,44 @@
108 * datapoints after the step. 109 * datapoints after the step.
109 */ 110 */
110 111
111#define RETRY_INTERVAL 5 /* on error, retry in N secs */
112#define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */
113#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ 112#define INITIAL_SAMPLES 4 /* how many samples do we want for init */
114#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */ 113#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */
115 114
116/* Clock discipline parameters and constants */ 115#define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */
116#define NOREPLY_INTERVAL 512 /* sent, but got no reply: cap next query by this many seconds */
117#define RESPONSE_INTERVAL 16 /* wait for reply up to N secs */
117 118
118/* Step threshold (sec). std ntpd uses 0.128. 119/* Step threshold (sec). std ntpd uses 0.128.
119 * Using exact power of 2 (1/8) results in smaller code */ 120 * Using exact power of 2 (1/8) results in smaller code
121 */
120#define STEP_THRESHOLD 0.125 122#define STEP_THRESHOLD 0.125
121#define WATCH_THRESHOLD 128 /* stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */ 123/* Stepout threshold (sec). std ntpd uses 900 (11 mins (!)) */
124#define WATCH_THRESHOLD 128
122/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */ 125/* NB: set WATCH_THRESHOLD to ~60 when debugging to save time) */
123//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ 126//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */
124 127
128/*
129 * If we got |offset| > BIGOFF from a peer, cap next query interval
130 * for this peer by this many seconds:
131 */
132#define BIGOFF (STEP_THRESHOLD * 8)
133#define BIGOFF_INTERVAL (1 << 7) /* 128 s */
134
125#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ 135#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */
126#define BURSTPOLL 0 /* initial poll */ 136#define BURSTPOLL 0 /* initial poll */
127#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ 137#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */
128/* If we got largish offset from a peer, cap next query interval 138/*
129 * for this peer by this many seconds: 139 * If offset > discipline_jitter * POLLADJ_GATE, and poll interval is > 2^BIGPOLL,
130 */ 140 * then it is decreased _at once_. (If <= 2^BIGPOLL, it will be decreased _eventually_).
131#define BIGOFF_INTERVAL (1 << 6)
132/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL,
133 * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_).
134 */ 141 */
135#define BIGPOLL 10 /* 2^10 sec ~= 17 min */ 142#define BIGPOLL 9 /* 2^9 sec ~= 8.5 min */
136#define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ 143#define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */
137/* Actively lower poll when we see such big offsets. 144/*
145 * Actively lower poll when we see such big offsets.
138 * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively 146 * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively
139 * if offset increases over ~0.04 sec */ 147 * if offset increases over ~0.04 sec
140#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) 148 */
149//#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3)
141#define MINDISP 0.01 /* minimum dispersion (sec) */ 150#define MINDISP 0.01 /* minimum dispersion (sec) */
142#define MAXDISP 16 /* maximum dispersion (sec) */ 151#define MAXDISP 16 /* maximum dispersion (sec) */
143#define MAXSTRAT 16 /* maximum stratum (infinity metric) */ 152#define MAXSTRAT 16 /* maximum stratum (infinity metric) */
@@ -283,6 +292,7 @@ enum {
283 OPT_p = (1 << 5), 292 OPT_p = (1 << 5),
284 OPT_S = (1 << 6), 293 OPT_S = (1 << 6),
285 OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER, 294 OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER,
295 OPT_I = (1 << 8) * ENABLE_FEATURE_NTPD_SERVER,
286 /* We hijack some bits for other purposes */ 296 /* We hijack some bits for other purposes */
287 OPT_qq = (1 << 31), 297 OPT_qq = (1 << 31),
288}; 298};
@@ -301,6 +311,7 @@ struct globals {
301 llist_t *ntp_peers; 311 llist_t *ntp_peers;
302#if ENABLE_FEATURE_NTPD_SERVER 312#if ENABLE_FEATURE_NTPD_SERVER
303 int listen_fd; 313 int listen_fd;
314 char *if_name;
304# define G_listen_fd (G.listen_fd) 315# define G_listen_fd (G.listen_fd)
305#else 316#else
306# define G_listen_fd (-1) 317# define G_listen_fd (-1)
@@ -969,6 +980,16 @@ step_time(double offset)
969 } 980 }
970} 981}
971 982
983static void clamp_pollexp_and_set_MAXSTRAT(void)
984{
985 if (G.poll_exp < MINPOLL)
986 G.poll_exp = MINPOLL;
987 if (G.poll_exp > BIGPOLL)
988 G.poll_exp = BIGPOLL;
989 G.polladj_count = 0;
990 G.stratum = MAXSTRAT;
991}
992
972 993
973/* 994/*
974 * Selection and clustering, and their helpers 995 * Selection and clustering, and their helpers
@@ -1450,9 +1471,7 @@ update_local_clock(peer_t *p)
1450 exit(0); 1471 exit(0);
1451 } 1472 }
1452 1473
1453 G.polladj_count = 0; 1474 clamp_pollexp_and_set_MAXSTRAT();
1454 G.poll_exp = MINPOLL;
1455 G.stratum = MAXSTRAT;
1456 1475
1457 run_script("step", offset); 1476 run_script("step", offset);
1458 1477
@@ -1469,11 +1488,10 @@ update_local_clock(peer_t *p)
1469 1488
1470 } else { /* abs_offset <= STEP_THRESHOLD */ 1489 } else { /* abs_offset <= STEP_THRESHOLD */
1471 1490
1472 if (G.poll_exp < MINPOLL && G.initial_poll_complete) { 1491 /* The ratio is calculated before jitter is updated to make
1473 VERB4 bb_error_msg("small offset:%+f, disabling burst mode", offset); 1492 * poll adjust code more sensitive to large offsets.
1474 G.polladj_count = 0; 1493 */
1475 G.poll_exp = MINPOLL; 1494 G.offset_to_jitter_ratio = abs_offset / G.discipline_jitter;
1476 }
1477 1495
1478 /* Compute the clock jitter as the RMS of exponentially 1496 /* Compute the clock jitter as the RMS of exponentially
1479 * weighted offset differences. Used by the poll adjust code. 1497 * weighted offset differences. Used by the poll adjust code.
@@ -1481,6 +1499,8 @@ update_local_clock(peer_t *p)
1481 etemp = SQUARE(G.discipline_jitter); 1499 etemp = SQUARE(G.discipline_jitter);
1482 dtemp = SQUARE(offset - G.last_update_offset); 1500 dtemp = SQUARE(offset - G.last_update_offset);
1483 G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); 1501 G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG);
1502 if (G.discipline_jitter < G_precision_sec)
1503 G.discipline_jitter = G_precision_sec;
1484 1504
1485 switch (G.discipline_state) { 1505 switch (G.discipline_state) {
1486 case STATE_NSET: 1506 case STATE_NSET:
@@ -1557,10 +1577,6 @@ update_local_clock(peer_t *p)
1557 } 1577 }
1558 } 1578 }
1559 1579
1560 if (G.discipline_jitter < G_precision_sec)
1561 G.discipline_jitter = G_precision_sec;
1562 G.offset_to_jitter_ratio = abs_offset / G.discipline_jitter;
1563
1564 G.reftime = G.cur_time; 1580 G.reftime = G.cur_time;
1565 G.ntp_status = p->lastpkt_status; 1581 G.ntp_status = p->lastpkt_status;
1566 G.refid = p->lastpkt_refid; 1582 G.refid = p->lastpkt_refid;
@@ -1657,30 +1673,53 @@ update_local_clock(peer_t *p)
1657 * (helpers first) 1673 * (helpers first)
1658 */ 1674 */
1659static unsigned 1675static unsigned
1660retry_interval(void) 1676poll_interval(int upper_bound)
1661{
1662 /* Local problem, want to retry soon */
1663 unsigned interval, r;
1664 interval = RETRY_INTERVAL;
1665 r = rand();
1666 interval += r % (unsigned)(RETRY_INTERVAL / 4);
1667 VERB4 bb_error_msg("chose retry interval:%u", interval);
1668 return interval;
1669}
1670static unsigned
1671poll_interval(int exponent)
1672{ 1677{
1673 unsigned interval, r, mask; 1678 unsigned interval, r, mask;
1674 exponent = G.poll_exp + exponent; 1679 interval = 1 << G.poll_exp;
1675 if (exponent < 0) 1680 if (interval > upper_bound)
1676 exponent = 0; 1681 interval = upper_bound;
1677 interval = 1 << exponent;
1678 mask = ((interval-1) >> 4) | 1; 1682 mask = ((interval-1) >> 4) | 1;
1679 r = rand(); 1683 r = rand();
1680 interval += r & mask; /* ~ random(0..1) * interval/16 */ 1684 interval += r & mask; /* ~ random(0..1) * interval/16 */
1681 VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); 1685 VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d)", interval, G.poll_exp);
1682 return interval; 1686 return interval;
1683} 1687}
1688static void
1689adjust_poll(int count)
1690{
1691 G.polladj_count += count;
1692 if (G.polladj_count > POLLADJ_LIMIT) {
1693 G.polladj_count = 0;
1694 if (G.poll_exp < MAXPOLL) {
1695 G.poll_exp++;
1696 VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d",
1697 G.discipline_jitter, G.poll_exp);
1698 }
1699 } else if (G.polladj_count < -POLLADJ_LIMIT || (count < 0 && G.poll_exp > BIGPOLL)) {
1700 G.polladj_count = 0;
1701 if (G.poll_exp > MINPOLL) {
1702 llist_t *item;
1703
1704 G.poll_exp--;
1705 /* Correct p->next_action_time in each peer
1706 * which waits for sending, so that they send earlier.
1707 * Old pp->next_action_time are on the order
1708 * of t + (1 << old_poll_exp) + small_random,
1709 * we simply need to subtract ~half of that.
1710 */
1711 for (item = G.ntp_peers; item != NULL; item = item->link) {
1712 peer_t *pp = (peer_t *) item->data;
1713 if (pp->p_fd < 0)
1714 pp->next_action_time -= (1 << G.poll_exp);
1715 }
1716 VERB4 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d",
1717 G.discipline_jitter, G.poll_exp);
1718 }
1719 } else {
1720 VERB4 bb_error_msg("polladj: count:%d", G.polladj_count);
1721 }
1722}
1684static NOINLINE void 1723static NOINLINE void
1685recv_and_process_peer_pkt(peer_t *p) 1724recv_and_process_peer_pkt(peer_t *p)
1686{ 1725{
@@ -1700,19 +1739,23 @@ recv_and_process_peer_pkt(peer_t *p)
1700 * ntp servers reply from their *other IP*. 1739 * ntp servers reply from their *other IP*.
1701 * TODO: maybe we should check at least what we can: from.port == 123? 1740 * TODO: maybe we should check at least what we can: from.port == 123?
1702 */ 1741 */
1742 recv_again:
1703 size = recv(p->p_fd, &msg, sizeof(msg), MSG_DONTWAIT); 1743 size = recv(p->p_fd, &msg, sizeof(msg), MSG_DONTWAIT);
1704 if (size == -1) { 1744 if (size < 0) {
1705 bb_perror_msg("recv(%s) error", p->p_dotted); 1745 if (errno == EINTR)
1706 if (errno == EHOSTUNREACH || errno == EHOSTDOWN 1746 /* Signal caught */
1707 || errno == ENETUNREACH || errno == ENETDOWN 1747 goto recv_again;
1708 || errno == ECONNREFUSED || errno == EADDRNOTAVAIL 1748 if (errno == EAGAIN)
1709 || errno == EAGAIN 1749 /* There was no packet after all
1710 ) { 1750 * (poll() returning POLLIN for a fd
1711//TODO: always do this? 1751 * is not a ironclad guarantee that data is there)
1712 interval = retry_interval(); 1752 */
1713 goto set_next_and_ret; 1753 return;
1714 } 1754 /*
1715 xfunc_die(); 1755 * If you need a different handling for a specific
1756 * errno, always explain it in comment.
1757 */
1758 bb_perror_msg_and_die("recv(%s) error", p->p_dotted);
1716 } 1759 }
1717 1760
1718 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { 1761 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
@@ -1738,10 +1781,15 @@ recv_and_process_peer_pkt(peer_t *p)
1738 || msg.m_stratum == 0 1781 || msg.m_stratum == 0
1739 || msg.m_stratum > NTP_MAXSTRATUM 1782 || msg.m_stratum > NTP_MAXSTRATUM
1740 ) { 1783 ) {
1741// TODO: stratum 0 responses may have commands in 32-bit m_refid field:
1742// "DENY", "RSTR" - peer does not like us at all
1743// "RATE" - peer is overloaded, reduce polling freq
1744 bb_error_msg("reply from %s: peer is unsynced", p->p_dotted); 1784 bb_error_msg("reply from %s: peer is unsynced", p->p_dotted);
1785 /*
1786 * Stratum 0 responses may have commands in 32-bit m_refid field:
1787 * "DENY", "RSTR" - peer does not like us at all,
1788 * "RATE" - peer is overloaded, reduce polling freq.
1789 * If poll interval is small, increase it.
1790 */
1791 if (G.poll_exp < BIGPOLL)
1792 goto increase_interval;
1745 goto pick_normal_interval; 1793 goto pick_normal_interval;
1746 } 1794 }
1747 1795
@@ -1830,21 +1878,36 @@ recv_and_process_peer_pkt(peer_t *p)
1830 /* Muck with statictics and update the clock */ 1878 /* Muck with statictics and update the clock */
1831 filter_datapoints(p); 1879 filter_datapoints(p);
1832 q = select_and_cluster(); 1880 q = select_and_cluster();
1833 rc = -1; 1881 rc = 0;
1834 if (q) { 1882 if (q) {
1835 rc = 0;
1836 if (!(option_mask32 & OPT_w)) { 1883 if (!(option_mask32 & OPT_w)) {
1837 rc = update_local_clock(q); 1884 rc = update_local_clock(q);
1885#if 0
1886//Disabled this because there is a case where largish offsets
1887//are unavoidable: if network round-trip delay is, say, ~0.6s,
1888//error in offset estimation would be ~delay/2 ~= 0.3s.
1889//Thus, offsets will be usually in -0.3...0.3s range.
1890//In this case, this code would keep poll interval small,
1891//but it won't be helping.
1892//BIGOFF check below deals with a case of seeing multi-second offsets.
1893
1838 /* If drift is dangerously large, immediately 1894 /* If drift is dangerously large, immediately
1839 * drop poll interval one step down. 1895 * drop poll interval one step down.
1840 */ 1896 */
1841 if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) { 1897 if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) {
1842 VERB4 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset); 1898 VERB4 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset);
1843 goto poll_down; 1899 adjust_poll(-POLLADJ_LIMIT * 3);
1900 rc = 0;
1844 } 1901 }
1902#endif
1845 } 1903 }
1904 } else {
1905 /* No peer selected.
1906 * If poll interval is small, increase it.
1907 */
1908 if (G.poll_exp < BIGPOLL)
1909 goto increase_interval;
1846 } 1910 }
1847 /* else: no peer selected, rc = -1: we want to poll more often */
1848 1911
1849 if (rc != 0) { 1912 if (rc != 0) {
1850 /* Adjust the poll interval by comparing the current offset 1913 /* Adjust the poll interval by comparing the current offset
@@ -1856,50 +1919,17 @@ recv_and_process_peer_pkt(peer_t *p)
1856 if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { 1919 if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) {
1857 /* was += G.poll_exp but it is a bit 1920 /* was += G.poll_exp but it is a bit
1858 * too optimistic for my taste at high poll_exp's */ 1921 * too optimistic for my taste at high poll_exp's */
1859 G.polladj_count += MINPOLL; 1922 increase_interval:
1860 if (G.polladj_count > POLLADJ_LIMIT) { 1923 adjust_poll(MINPOLL);
1861 G.polladj_count = 0;
1862 if (G.poll_exp < MAXPOLL) {
1863 G.poll_exp++;
1864 VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d",
1865 G.discipline_jitter, G.poll_exp);
1866 }
1867 } else {
1868 VERB4 bb_error_msg("polladj: incr:%d", G.polladj_count);
1869 }
1870 } else { 1924 } else {
1871 G.polladj_count -= G.poll_exp * 2; 1925 adjust_poll(-G.poll_exp * 2);
1872 if (G.polladj_count < -POLLADJ_LIMIT || G.poll_exp >= BIGPOLL) {
1873 poll_down:
1874 G.polladj_count = 0;
1875 if (G.poll_exp > MINPOLL) {
1876 llist_t *item;
1877
1878 G.poll_exp--;
1879 /* Correct p->next_action_time in each peer
1880 * which waits for sending, so that they send earlier.
1881 * Old pp->next_action_time are on the order
1882 * of t + (1 << old_poll_exp) + small_random,
1883 * we simply need to subtract ~half of that.
1884 */
1885 for (item = G.ntp_peers; item != NULL; item = item->link) {
1886 peer_t *pp = (peer_t *) item->data;
1887 if (pp->p_fd < 0)
1888 pp->next_action_time -= (1 << G.poll_exp);
1889 }
1890 VERB4 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d",
1891 G.discipline_jitter, G.poll_exp);
1892 }
1893 } else {
1894 VERB4 bb_error_msg("polladj: decr:%d", G.polladj_count);
1895 }
1896 } 1926 }
1897 } 1927 }
1898 1928
1899 /* Decide when to send new query for this peer */ 1929 /* Decide when to send new query for this peer */
1900 pick_normal_interval: 1930 pick_normal_interval:
1901 interval = poll_interval(0); 1931 interval = poll_interval(INT_MAX);
1902 if (fabs(offset) >= STEP_THRESHOLD * 8 && interval > BIGOFF_INTERVAL) { 1932 if (fabs(offset) >= BIGOFF && interval > BIGOFF_INTERVAL) {
1903 /* If we are synced, offsets are less than STEP_THRESHOLD, 1933 /* If we are synced, offsets are less than STEP_THRESHOLD,
1904 * or at the very least not much larger than it. 1934 * or at the very least not much larger than it.
1905 * Now we see a largish one. 1935 * Now we see a largish one.
@@ -1914,7 +1944,6 @@ recv_and_process_peer_pkt(peer_t *p)
1914 interval = BIGOFF_INTERVAL; 1944 interval = BIGOFF_INTERVAL;
1915 } 1945 }
1916 1946
1917 set_next_and_ret:
1918 set_next(p, interval); 1947 set_next(p, interval);
1919} 1948}
1920 1949
@@ -2085,6 +2114,7 @@ static NOINLINE void ntp_init(char **argv)
2085 bb_error_msg_and_die(bb_msg_you_must_be_root); 2114 bb_error_msg_and_die(bb_msg_you_must_be_root);
2086 2115
2087 /* Set some globals */ 2116 /* Set some globals */
2117 G.discipline_jitter = G_precision_sec;
2088 G.stratum = MAXSTRAT; 2118 G.stratum = MAXSTRAT;
2089 if (BURSTPOLL != 0) 2119 if (BURSTPOLL != 0)
2090 G.poll_exp = BURSTPOLL; /* speeds up initial sync */ 2120 G.poll_exp = BURSTPOLL; /* speeds up initial sync */
@@ -2092,13 +2122,19 @@ static NOINLINE void ntp_init(char **argv)
2092 2122
2093 /* Parse options */ 2123 /* Parse options */
2094 peers = NULL; 2124 peers = NULL;
2095 opt_complementary = "dd:p::wn"; /* d: counter; p: list; -w implies -n */ 2125 opt_complementary = "dd:p::wn" /* -d: counter; -p: list; -w implies -n */
2126 IF_FEATURE_NTPD_SERVER(":Il"); /* -I implies -l */
2096 opts = getopt32(argv, 2127 opts = getopt32(argv,
2097 "nqNx" /* compat */ 2128 "nqNx" /* compat */
2098 "wp:S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */ 2129 "wp:S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */
2130 IF_FEATURE_NTPD_SERVER("I:") /* compat */
2099 "d" /* compat */ 2131 "d" /* compat */
2100 "46aAbgL", /* compat, ignored */ 2132 "46aAbgL", /* compat, ignored */
2101 &peers, &G.script_name, &G.verbose); 2133 &peers,&G.script_name,
2134#if ENABLE_FEATURE_NTPD_SERVER
2135 &G.if_name,
2136#endif
2137 &G.verbose);
2102 2138
2103// if (opts & OPT_x) /* disable stepping, only slew is allowed */ 2139// if (opts & OPT_x) /* disable stepping, only slew is allowed */
2104// G.time_was_stepped = 1; 2140// G.time_was_stepped = 1;
@@ -2130,18 +2166,22 @@ static NOINLINE void ntp_init(char **argv)
2130 /* -l but no peers: "stratum 1 server" mode */ 2166 /* -l but no peers: "stratum 1 server" mode */
2131 G.stratum = 1; 2167 G.stratum = 1;
2132 } 2168 }
2133 if (!(opts & OPT_n)) {
2134 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
2135 logmode = LOGMODE_NONE;
2136 }
2137#if ENABLE_FEATURE_NTPD_SERVER 2169#if ENABLE_FEATURE_NTPD_SERVER
2138 G_listen_fd = -1; 2170 G_listen_fd = -1;
2139 if (opts & OPT_l) { 2171 if (opts & OPT_l) {
2140 G_listen_fd = create_and_bind_dgram_or_die(NULL, 123); 2172 G_listen_fd = create_and_bind_dgram_or_die(NULL, 123);
2173 if (opts & OPT_I) {
2174 if (setsockopt_bindtodevice(G_listen_fd, G.if_name))
2175 xfunc_die();
2176 }
2141 socket_want_pktinfo(G_listen_fd); 2177 socket_want_pktinfo(G_listen_fd);
2142 setsockopt(G_listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); 2178 setsockopt(G_listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY));
2143 } 2179 }
2144#endif 2180#endif
2181 if (!(opts & OPT_n)) {
2182 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
2183 logmode = LOGMODE_NONE;
2184 }
2145 /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */ 2185 /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */
2146 if (opts & OPT_N) 2186 if (opts & OPT_N)
2147 setpriority(PRIO_PROCESS, 0, -15); 2187 setpriority(PRIO_PROCESS, 0, -15);
@@ -2229,6 +2269,9 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2229 if (p->p_fd == -1) { 2269 if (p->p_fd == -1) {
2230 /* Time to send new req */ 2270 /* Time to send new req */
2231 if (--cnt == 0) { 2271 if (--cnt == 0) {
2272 VERB4 bb_error_msg("disabling burst mode");
2273 G.polladj_count = 0;
2274 G.poll_exp = MINPOLL;
2232 G.initial_poll_complete = 1; 2275 G.initial_poll_complete = 1;
2233 } 2276 }
2234 send_query_to_peer(p); 2277 send_query_to_peer(p);
@@ -2236,7 +2279,10 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2236 /* Timed out waiting for reply */ 2279 /* Timed out waiting for reply */
2237 close(p->p_fd); 2280 close(p->p_fd);
2238 p->p_fd = -1; 2281 p->p_fd = -1;
2239 timeout = poll_interval(-2); /* -2: try a bit sooner */ 2282 /* If poll interval is small, increase it */
2283 if (G.poll_exp < BIGPOLL)
2284 adjust_poll(MINPOLL);
2285 timeout = poll_interval(NOREPLY_INTERVAL);
2240 bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", 2286 bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us",
2241 p->p_dotted, p->reachable_bits, timeout); 2287 p->p_dotted, p->reachable_bits, timeout);
2242 set_next(p, timeout); 2288 set_next(p, timeout);
@@ -2327,9 +2373,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2327 goto have_reachable_peer; 2373 goto have_reachable_peer;
2328 } 2374 }
2329 /* No peer responded for last 8 packets, panic */ 2375 /* No peer responded for last 8 packets, panic */
2330 G.polladj_count = 0; 2376 clamp_pollexp_and_set_MAXSTRAT();
2331 G.poll_exp = MINPOLL;
2332 G.stratum = MAXSTRAT;
2333 run_script("unsync", 0.0); 2377 run_script("unsync", 0.0);
2334 have_reachable_peer: ; 2378 have_reachable_peer: ;
2335 } 2379 }
diff --git a/networking/ping.c b/networking/ping.c
index 5e4771f5a..c475395e7 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -100,8 +100,9 @@
100//usage: "\n (after all -c CNT packets are sent)" 100//usage: "\n (after all -c CNT packets are sent)"
101//usage: "\n -w SEC Seconds until ping exits (default:infinite)" 101//usage: "\n -w SEC Seconds until ping exits (default:infinite)"
102//usage: "\n (can exit earlier with -c CNT)" 102//usage: "\n (can exit earlier with -c CNT)"
103//usage: "\n -q Quiet, only displays output at start" 103//usage: "\n -q Quiet, only display output at start"
104//usage: "\n and when finished" 104//usage: "\n and when finished"
105//usage: "\n -p Pattern to use for payload"
105//usage: 106//usage:
106//usage:# define ping6_trivial_usage 107//usage:# define ping6_trivial_usage
107//usage: "[OPTIONS] HOST" 108//usage: "[OPTIONS] HOST"
@@ -110,8 +111,9 @@
110//usage: "\n -c CNT Send only CNT pings" 111//usage: "\n -c CNT Send only CNT pings"
111//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" 112//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)"
112//usage: "\n -I IFACE/IP Use interface or IP address as source" 113//usage: "\n -I IFACE/IP Use interface or IP address as source"
113//usage: "\n -q Quiet, only displays output at start" 114//usage: "\n -q Quiet, only display output at start"
114//usage: "\n and when finished" 115//usage: "\n and when finished"
116//usage: "\n -p Pattern to use for payload"
115//usage: 117//usage:
116//usage:#endif 118//usage:#endif
117//usage: 119//usage:
@@ -330,7 +332,7 @@ static int common_ping_main(sa_family_t af, char **argv)
330 332
331/* Full(er) version */ 333/* Full(er) version */
332 334
333#define OPT_STRING ("qvc:s:t:w:W:I:n4" IF_PING6("6")) 335#define OPT_STRING ("qvc:s:t:w:W:I:np:4" IF_PING6("6"))
334enum { 336enum {
335 OPT_QUIET = 1 << 0, 337 OPT_QUIET = 1 << 0,
336 OPT_VERBOSE = 1 << 1, 338 OPT_VERBOSE = 1 << 1,
@@ -341,8 +343,9 @@ enum {
341 OPT_W = 1 << 6, 343 OPT_W = 1 << 6,
342 OPT_I = 1 << 7, 344 OPT_I = 1 << 7,
343 /*OPT_n = 1 << 8, - ignored */ 345 /*OPT_n = 1 << 8, - ignored */
344 OPT_IPV4 = 1 << 9, 346 OPT_p = 1 << 9,
345 OPT_IPV6 = (1 << 10) * ENABLE_PING6, 347 OPT_IPV4 = 1 << 10,
348 OPT_IPV6 = (1 << 11) * ENABLE_PING6,
346}; 349};
347 350
348 351
@@ -355,6 +358,7 @@ struct globals {
355 unsigned opt_ttl; 358 unsigned opt_ttl;
356 unsigned long ntransmitted, nreceived, nrepeats; 359 unsigned long ntransmitted, nreceived, nrepeats;
357 uint16_t myid; 360 uint16_t myid;
361 uint8_t pattern;
358 unsigned tmin, tmax; /* in us */ 362 unsigned tmin, tmax; /* in us */
359 unsigned long long tsum; /* in us, sum of all times */ 363 unsigned long long tsum; /* in us, sum of all times */
360 unsigned deadline; 364 unsigned deadline;
@@ -485,7 +489,7 @@ static void sendping4(int junk UNUSED_PARAM)
485{ 489{
486 struct icmp *pkt = G.snd_packet; 490 struct icmp *pkt = G.snd_packet;
487 491
488 //memset(pkt, 0, datalen + ICMP_MINLEN + 4); - G.snd_packet was xzalloced 492 memset(pkt, G.pattern, datalen + ICMP_MINLEN + 4);
489 pkt->icmp_type = ICMP_ECHO; 493 pkt->icmp_type = ICMP_ECHO;
490 /*pkt->icmp_code = 0;*/ 494 /*pkt->icmp_code = 0;*/
491 pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ 495 pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */
@@ -508,7 +512,7 @@ static void sendping6(int junk UNUSED_PARAM)
508{ 512{
509 struct icmp6_hdr *pkt = G.snd_packet; 513 struct icmp6_hdr *pkt = G.snd_packet;
510 514
511 //memset(pkt, 0, datalen + sizeof(struct icmp6_hdr) + 4); 515 memset(pkt, G.pattern, datalen + sizeof(struct icmp6_hdr) + 4);
512 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 516 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
513 /*pkt->icmp6_code = 0;*/ 517 /*pkt->icmp6_code = 0;*/
514 /*pkt->icmp6_cksum = 0;*/ 518 /*pkt->icmp6_cksum = 0;*/
@@ -850,13 +854,13 @@ static void ping(len_and_sockaddr *lsa)
850static int common_ping_main(int opt, char **argv) 854static int common_ping_main(int opt, char **argv)
851{ 855{
852 len_and_sockaddr *lsa; 856 len_and_sockaddr *lsa;
853 char *str_s; 857 char *str_s, *str_p;
854 858
855 INIT_G(); 859 INIT_G();
856 860
857 /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */ 861 /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */
858 opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+"; 862 opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+";
859 opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I); 863 opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p);
860 if (opt & OPT_s) 864 if (opt & OPT_s)
861 datalen = xatou16(str_s); // -s 865 datalen = xatou16(str_s); // -s
862 if (opt & OPT_I) { // -I 866 if (opt & OPT_I) { // -I
@@ -867,6 +871,9 @@ static int common_ping_main(int opt, char **argv)
867 str_I = NULL; /* don't try to bind to device later */ 871 str_I = NULL; /* don't try to bind to device later */
868 } 872 }
869 } 873 }
874 if (opt & OPT_p)
875 G.pattern = xstrtou_range(str_p, 16, 0, 255);
876
870 myid = (uint16_t) getpid(); 877 myid = (uint16_t) getpid();
871 hostname = argv[optind]; 878 hostname = argv[optind];
872#if ENABLE_PING6 879#if ENABLE_PING6
diff --git a/networking/tftp.c b/networking/tftp.c
index 630fdaf9a..7c0ee58d7 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -117,8 +117,10 @@ struct globals {
117 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ 117 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
118 uint8_t error_pkt[4 + 32]; 118 uint8_t error_pkt[4 + 32];
119 struct passwd *pw; 119 struct passwd *pw;
120 /* used in tftpd_main(), a bit big for stack: */ 120 /* Used in tftpd_main() for initial packet */
121 char block_buf[TFTP_BLKSIZE_DEFAULT]; 121 /* Some HP PA-RISC firmware always sends fixed 516-byte requests */
122 char block_buf[516];
123 char block_buf_tail[1];
122#if ENABLE_FEATURE_TFTP_PROGRESS_BAR 124#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
123 off_t pos; 125 off_t pos;
124 off_t size; 126 off_t size;
@@ -793,14 +795,16 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
793 xchroot(argv[0]); 795 xchroot(argv[0]);
794 } 796 }
795 797
796 result = recv_from_to(STDIN_FILENO, G.block_buf, sizeof(G.block_buf), 798 result = recv_from_to(STDIN_FILENO,
799 G.block_buf, sizeof(G.block_buf) + 1,
800 /* ^^^ sizeof+1 to reliably detect oversized input */
797 0 /* flags */, 801 0 /* flags */,
798 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len); 802 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
799 803
800 error_msg = "malformed packet"; 804 error_msg = "malformed packet";
801 opcode = ntohs(*(uint16_t*)G.block_buf); 805 opcode = ntohs(*(uint16_t*)G.block_buf);
802 if (result < 4 || result >= sizeof(G.block_buf) 806 if (result < 4 || result > sizeof(G.block_buf)
803 || G.block_buf[result-1] != '\0' 807 /*|| G.block_buf[result-1] != '\0' - bug compatibility, see below */
804 || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */ 808 || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
805 IF_GETPUT(&&) 809 IF_GETPUT(&&)
806 IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */ 810 IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
@@ -808,6 +812,13 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
808 ) { 812 ) {
809 goto err; 813 goto err;
810 } 814 }
815 /* Some HP PA-RISC firmware always sends fixed 516-byte requests,
816 * with trailing garbage.
817 * Support that by not requiring NUL to be the last byte (see above).
818 * To make strXYZ() ops safe, force NUL termination:
819 */
820 G.block_buf_tail[0] = '\0';
821
811 local_file = G.block_buf + 2; 822 local_file = G.block_buf + 2;
812 if (local_file[0] == '.' || strstr(local_file, "/.")) { 823 if (local_file[0] == '.' || strstr(local_file, "/.")) {
813 error_msg = "dot in file name"; 824 error_msg = "dot in file name";
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index fe322db4f..bc41c8d4d 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -63,6 +63,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ 63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
64#endif 64#endif
65 { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */ 65 { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */
66 { OPTION_STRING , 0xd2 }, /* DHCP_PXE_PATH_PREFIX */
66 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ 67 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
67 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ 68 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
68 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 69 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
@@ -130,6 +131,7 @@ const char dhcp_option_strings[] ALIGN1 =
130 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ 131 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */
131#endif 132#endif
132 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */ 133 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
134 "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */
133 "ip6rd" "\0" /* DHCP_6RD */ 135 "ip6rd" "\0" /* DHCP_6RD */
134 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ 136 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
135 "wpad" "\0" /* DHCP_WPAD */ 137 "wpad" "\0" /* DHCP_WPAD */
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 5e70d609f..e5e0f2599 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -152,6 +152,7 @@ enum {
152//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */ 152//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */
153//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */ 153//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */
154//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */ 154//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */
155//#define DHCP_PXE_PATH_PREFIX 0xd2 /* RFC 5071 Configuration File */
155//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */ 156//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
156//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ 157//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
157#define DHCP_END 0xff 158#define DHCP_END 0xff
diff --git a/networking/zcip.c b/networking/zcip.c
index 7314ff8db..45d1f7c1c 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -366,11 +366,11 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
366 nprobes++; 366 nprobes++;
367 VDBG("probe/%u %s@%s\n", 367 VDBG("probe/%u %s@%s\n",
368 nprobes, argv_intf, inet_ntoa(ip)); 368 nprobes, argv_intf, inet_ntoa(ip));
369 timeout_ms = PROBE_MIN * 1000;
370 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
369 arp(/* ARPOP_REQUEST, */ 371 arp(/* ARPOP_REQUEST, */
370 /* &eth_addr, */ null_ip, 372 /* &eth_addr, */ null_ip,
371 &null_addr, ip); 373 &null_addr, ip);
372 timeout_ms = PROBE_MIN * 1000;
373 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
374 } 374 }
375 else { 375 else {
376 // Switch to announce state. 376 // Switch to announce state.
@@ -378,10 +378,10 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
378 nclaims = 0; 378 nclaims = 0;
379 VDBG("announce/%u %s@%s\n", 379 VDBG("announce/%u %s@%s\n",
380 nclaims, argv_intf, inet_ntoa(ip)); 380 nclaims, argv_intf, inet_ntoa(ip));
381 timeout_ms = ANNOUNCE_INTERVAL * 1000;
381 arp(/* ARPOP_REQUEST, */ 382 arp(/* ARPOP_REQUEST, */
382 /* &eth_addr, */ ip, 383 /* &eth_addr, */ ip,
383 &eth_addr, ip); 384 &eth_addr, ip);
384 timeout_ms = ANNOUNCE_INTERVAL * 1000;
385 } 385 }
386 break; 386 break;
387 case RATE_LIMIT_PROBE: 387 case RATE_LIMIT_PROBE:
@@ -391,10 +391,10 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
391 nclaims = 0; 391 nclaims = 0;
392 VDBG("announce/%u %s@%s\n", 392 VDBG("announce/%u %s@%s\n",
393 nclaims, argv_intf, inet_ntoa(ip)); 393 nclaims, argv_intf, inet_ntoa(ip));
394 timeout_ms = ANNOUNCE_INTERVAL * 1000;
394 arp(/* ARPOP_REQUEST, */ 395 arp(/* ARPOP_REQUEST, */
395 /* &eth_addr, */ ip, 396 /* &eth_addr, */ ip,
396 &eth_addr, ip); 397 &eth_addr, ip);
397 timeout_ms = ANNOUNCE_INTERVAL * 1000;
398 break; 398 break;
399 case ANNOUNCE: 399 case ANNOUNCE:
400 // timeouts in the ANNOUNCE state mean no conflicting ARP packets 400 // timeouts in the ANNOUNCE state mean no conflicting ARP packets
@@ -403,10 +403,10 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
403 nclaims++; 403 nclaims++;
404 VDBG("announce/%u %s@%s\n", 404 VDBG("announce/%u %s@%s\n",
405 nclaims, argv_intf, inet_ntoa(ip)); 405 nclaims, argv_intf, inet_ntoa(ip));
406 timeout_ms = ANNOUNCE_INTERVAL * 1000;
406 arp(/* ARPOP_REQUEST, */ 407 arp(/* ARPOP_REQUEST, */
407 /* &eth_addr, */ ip, 408 /* &eth_addr, */ ip,
408 &eth_addr, ip); 409 &eth_addr, ip);
409 timeout_ms = ANNOUNCE_INTERVAL * 1000;
410 } 410 }
411 else { 411 else {
412 // Switch to monitor state. 412 // Switch to monitor state.
@@ -495,22 +495,28 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
495 } 495 }
496#endif 496#endif
497 if (p.arp.arp_op != htons(ARPOP_REQUEST) 497 if (p.arp.arp_op != htons(ARPOP_REQUEST)
498 && p.arp.arp_op != htons(ARPOP_REPLY)) 498 && p.arp.arp_op != htons(ARPOP_REPLY)
499 ) {
499 continue; 500 continue;
501 }
500 502
501 source_ip_conflict = 0; 503 source_ip_conflict = 0;
502 target_ip_conflict = 0; 504 target_ip_conflict = 0;
503 505
504 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 506 if (memcmp(&p.arp.arp_sha, &eth_addr, ETH_ALEN) != 0) {
505 && memcmp(&p.arp.arp_sha, &eth_addr, ETH_ALEN) != 0 507 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr))) {
506 ) { 508 /* A probe or reply with source_ip == chosen ip */
507 source_ip_conflict = 1; 509 source_ip_conflict = 1;
508 } 510 }
509 if (p.arp.arp_op == htons(ARPOP_REQUEST) 511 if (p.arp.arp_op == htons(ARPOP_REQUEST)
510 && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 512 && memcmp(p.arp.arp_spa, &null_ip, sizeof(struct in_addr)) == 0
511 && memcmp(&p.arp.arp_tha, &eth_addr, ETH_ALEN) != 0 513 && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0
512 ) { 514 ) {
513 target_ip_conflict = 1; 515 /* A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
516 * another host trying to claim this ip!
517 */
518 target_ip_conflict = 1;
519 }
514 } 520 }
515 521
516 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", 522 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
diff --git a/procps/top.c b/procps/top.c
index 530f45fa1..3d67c3cfd 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -499,85 +499,93 @@ static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)
499# define display_cpus(scr_width, scrbuf, lines_rem) ((void)0) 499# define display_cpus(scr_width, scrbuf, lines_rem) ((void)0)
500#endif 500#endif
501 501
502static unsigned long display_header(int scr_width, int *lines_rem_p) 502enum {
503{ 503 MI_MEMTOTAL,
504 FILE *fp; 504 MI_MEMFREE,
505 char buf[80]; 505 MI_MEMSHARED,
506 char scrbuf[80]; 506 MI_SHMEM,
507 unsigned long total, used, mfree, shared, buffers, cached; 507 MI_BUFFERS,
508 508 MI_CACHED,
509 /* read memory info */ 509 MI_SWAPTOTAL,
510 fp = xfopen_for_read("meminfo"); 510 MI_SWAPFREE,
511 MI_DIRTY,
512 MI_WRITEBACK,
513 MI_ANONPAGES,
514 MI_MAPPED,
515 MI_SLAB,
516 MI_MAX
517};
511 518
512 /* 519static void parse_meminfo(unsigned long meminfo[MI_MAX])
513 * Old kernels (such as 2.4.x) had a nice summary of memory info that 520{
514 * we could parse, however this is gone entirely in 2.6. Try parsing 521 static const char fields[] =
515 * the old way first, and if that fails, parse each field manually. 522 "MemTotal\0"
516 * 523 "MemFree\0"
517 * First, we read in the first line. Old kernels will have bogus 524 "MemShared\0"
518 * strings we don't care about, whereas new kernels will start right 525 "Shmem\0"
519 * out with MemTotal: 526 "Buffers\0"
520 * -- PFM. 527 "Cached\0"
521 */ 528 "SwapTotal\0"
522 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) { 529 "SwapFree\0"
523 fgets(buf, sizeof(buf), fp); /* skip first line */ 530 "Dirty\0"
524 531 "Writeback\0"
525 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu", 532 "AnonPages\0"
526 &total, &used, &mfree, &shared, &buffers, &cached); 533 "Mapped\0"
527 /* convert to kilobytes */ 534 "Slab\0";
528 used /= 1024; 535 char buf[60]; /* actual lines we expect are ~30 chars or less */
529 mfree /= 1024; 536 FILE *f;
530 shared /= 1024; 537 int i;
531 buffers /= 1024;
532 cached /= 1024;
533 total /= 1024;
534 } else {
535 /*
536 * Revert to manual parsing, which incidentally already has the
537 * sizes in kilobytes. This should be safe for both 2.4 and
538 * 2.6.
539 */
540 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
541 538
542 /* 539 memset(meminfo, 0, sizeof(meminfo[0]) * MI_MAX);
543 * MemShared: is no longer present in 2.6. Report this as 0, 540 f = xfopen_for_read("meminfo");
544 * to maintain consistent behavior with normal procps. 541 while (fgets(buf, sizeof(buf), f) != NULL) {
545 */ 542 char *c = strchr(buf, ':');
546 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2) 543 if (!c)
547 shared = 0; 544 continue;
545 *c = '\0';
546 i = index_in_strings(fields, buf);
547 if (i >= 0)
548 meminfo[i] = strtoul(c+1, NULL, 10);
549 }
550 fclose(f);
551}
548 552
549 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf); 553static unsigned long display_header(int scr_width, int *lines_rem_p)
550 fscanf(fp, "Cached: %lu %s\n", &cached, buf); 554{
555 char scrbuf[100]; /* [80] was a bit too low on 8Gb ram box */
556 char *buf;
557 unsigned long meminfo[MI_MAX];
551 558
552 used = total - mfree; 559 parse_meminfo(meminfo);
553 }
554 fclose(fp);
555 560
556 /* output memory info */ 561 /* Output memory info */
557 if (scr_width > (int)sizeof(scrbuf)) 562 if (scr_width > (int)sizeof(scrbuf))
558 scr_width = sizeof(scrbuf); 563 scr_width = sizeof(scrbuf);
559 snprintf(scrbuf, scr_width, 564 snprintf(scrbuf, scr_width,
560 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", 565 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
561 used, mfree, shared, buffers, cached); 566 meminfo[MI_MEMTOTAL] - meminfo[MI_MEMFREE],
562 /* go to top & clear to the end of screen */ 567 meminfo[MI_MEMFREE],
568 meminfo[MI_MEMSHARED] + meminfo[MI_SHMEM],
569 meminfo[MI_BUFFERS],
570 meminfo[MI_CACHED]);
571 /* Go to top & clear to the end of screen */
563 printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf); 572 printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf);
564 (*lines_rem_p)--; 573 (*lines_rem_p)--;
565 574
566 /* Display CPU time split as percentage of total time 575 /* Display CPU time split as percentage of total time.
567 * This displays either a cumulative line or one line per CPU 576 * This displays either a cumulative line or one line per CPU.
568 */ 577 */
569 display_cpus(scr_width, scrbuf, lines_rem_p); 578 display_cpus(scr_width, scrbuf, lines_rem_p);
570 579
571 /* read load average as a string */ 580 /* Read load average as a string */
572 buf[0] = '\0'; 581 buf = stpcpy(scrbuf, "Load average: ");
573 open_read_close("loadavg", buf, sizeof(buf) - 1); 582 open_read_close("loadavg", buf, sizeof(scrbuf) - sizeof("Load average: "));
574 buf[sizeof(buf) - 1] = '\n'; 583 scrbuf[scr_width - 1] = '\0';
575 *strchr(buf, '\n') = '\0'; 584 strchrnul(buf, '\n')[0] = '\0';
576 snprintf(scrbuf, scr_width, "Load average: %s", buf);
577 puts(scrbuf); 585 puts(scrbuf);
578 (*lines_rem_p)--; 586 (*lines_rem_p)--;
579 587
580 return total; 588 return meminfo[MI_MEMTOTAL];
581} 589}
582 590
583static NOINLINE void display_process_list(int lines_rem, int scr_width) 591static NOINLINE void display_process_list(int lines_rem, int scr_width)
@@ -781,64 +789,31 @@ static int topmem_sort(char *a, char *b)
781/* display header info (meminfo / loadavg) */ 789/* display header info (meminfo / loadavg) */
782static void display_topmem_header(int scr_width, int *lines_rem_p) 790static void display_topmem_header(int scr_width, int *lines_rem_p)
783{ 791{
784 enum { 792 unsigned long meminfo[MI_MAX];
785 TOTAL = 0, MFREE, BUF, CACHE, 793
786 SWAPTOTAL, SWAPFREE, DIRTY, 794 parse_meminfo(meminfo);
787 MWRITE, ANON, MAP, SLAB,
788 NUM_FIELDS
789 };
790 static const char match[NUM_FIELDS][12] = {
791 "\x09" "MemTotal:", // TOTAL
792 "\x08" "MemFree:", // MFREE
793 "\x08" "Buffers:", // BUF
794 "\x07" "Cached:", // CACHE
795 "\x0a" "SwapTotal:", // SWAPTOTAL
796 "\x09" "SwapFree:", // SWAPFREE
797 "\x06" "Dirty:", // DIRTY
798 "\x0a" "Writeback:", // MWRITE
799 "\x0a" "AnonPages:", // ANON
800 "\x07" "Mapped:", // MAP
801 "\x05" "Slab:", // SLAB
802 };
803 char meminfo_buf[4 * 1024];
804 const char *Z[NUM_FIELDS];
805 unsigned i;
806 int sz;
807
808 for (i = 0; i < NUM_FIELDS; i++)
809 Z[i] = "?";
810
811 /* read memory info */
812 sz = open_read_close("meminfo", meminfo_buf, sizeof(meminfo_buf) - 1);
813 if (sz >= 0) {
814 char *p = meminfo_buf;
815 meminfo_buf[sz] = '\0';
816 /* Note that fields always appear in the match[] order */
817 for (i = 0; i < NUM_FIELDS; i++) {
818 char *found = strstr(p, match[i] + 1);
819 if (found) {
820 /* Cut "NNNN" out of " NNNN kb" */
821 char *s = skip_whitespace(found + match[i][0]);
822 p = skip_non_whitespace(s);
823 *p++ = '\0';
824 Z[i] = s;
825 }
826 }
827 }
828 795
829 snprintf(line_buf, LINE_BUF_SIZE, 796 snprintf(line_buf, LINE_BUF_SIZE,
830 "Mem total:%s anon:%s map:%s free:%s", 797 "Mem total:%lu anon:%lu map:%lu free:%lu",
831 Z[TOTAL], Z[ANON], Z[MAP], Z[MFREE]); 798 meminfo[MI_MEMTOTAL],
799 meminfo[MI_ANONPAGES],
800 meminfo[MI_MAPPED],
801 meminfo[MI_MEMFREE]);
832 printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, line_buf); 802 printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, line_buf);
833 803
834 snprintf(line_buf, LINE_BUF_SIZE, 804 snprintf(line_buf, LINE_BUF_SIZE,
835 " slab:%s buf:%s cache:%s dirty:%s write:%s", 805 " slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu",
836 Z[SLAB], Z[BUF], Z[CACHE], Z[DIRTY], Z[MWRITE]); 806 meminfo[MI_SLAB],
807 meminfo[MI_BUFFERS],
808 meminfo[MI_CACHED],
809 meminfo[MI_DIRTY],
810 meminfo[MI_WRITEBACK]);
837 printf("%.*s\n", scr_width, line_buf); 811 printf("%.*s\n", scr_width, line_buf);
838 812
839 snprintf(line_buf, LINE_BUF_SIZE, 813 snprintf(line_buf, LINE_BUF_SIZE,
840 "Swap total:%s free:%s", // TODO: % used? 814 "Swap total:%lu free:%lu", // TODO: % used?
841 Z[SWAPTOTAL], Z[SWAPFREE]); 815 meminfo[MI_SWAPTOTAL],
816 meminfo[MI_SWAPFREE]);
842 printf("%.*s\n", scr_width, line_buf); 817 printf("%.*s\n", scr_width, line_buf);
843 818
844 (*lines_rem_p) -= 3; 819 (*lines_rem_p) -= 3;
diff --git a/shell/ash.c b/shell/ash.c
index 550a98db6..3f3e2f4bc 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -161,6 +161,13 @@
161//config: help 161//config: help
162//config: Enable support for test builtin in ash. 162//config: Enable support for test builtin in ash.
163//config: 163//config:
164//config:config ASH_HELP
165//config: bool "help builtin"
166//config: default y
167//config: depends on ASH
168//config: help
169//config: Enable help builtin in ash.
170//config:
164//config:config ASH_CMDCMD 171//config:config ASH_CMDCMD
165//config: bool "'command' command to override shell builtins" 172//config: bool "'command' command to override shell builtins"
166//config: default y 173//config: default y
@@ -2189,6 +2196,22 @@ lookupvar(const char *name)
2189 return NULL; 2196 return NULL;
2190} 2197}
2191 2198
2199static void reinit_unicode_for_ash(void)
2200{
2201 /* Unicode support should be activated even if LANG is set
2202 * _during_ shell execution, not only if it was set when
2203 * shell was started. Therefore, re-check LANG every time:
2204 */
2205 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2206 || ENABLE_UNICODE_USING_LOCALE
2207 ) {
2208 const char *s = lookupvar("LC_ALL");
2209 if (!s) s = lookupvar("LC_CTYPE");
2210 if (!s) s = lookupvar("LANG");
2211 reinit_unicode(s);
2212 }
2213}
2214
2192/* 2215/*
2193 * Search the environment of a builtin command. 2216 * Search the environment of a builtin command.
2194 */ 2217 */
@@ -3818,7 +3841,7 @@ getjob(const char *name, int getctl)
3818 3841
3819 if (is_number(p)) { 3842 if (is_number(p)) {
3820 num = atoi(p); 3843 num = atoi(p);
3821 if (num < njobs) { 3844 if (num <= njobs) {
3822 jp = jobtab + num - 1; 3845 jp = jobtab + num - 1;
3823 if (jp->used) 3846 if (jp->used)
3824 goto gotit; 3847 goto gotit;
@@ -7127,7 +7150,15 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
7127 varunset(p, var, 0, 0); 7150 varunset(p, var, 0, 0);
7128 7151
7129 if (subtype == VSLENGTH) { 7152 if (subtype == VSLENGTH) {
7130 cvtnum(varlen > 0 ? varlen : 0); 7153 ssize_t n = varlen;
7154 if (n > 0) {
7155 reinit_unicode_for_ash();
7156 if (unicode_status == UNICODE_ON) {
7157 const char *val = lookupvar(var);
7158 n = unicode_strlen(val);
7159 }
7160 }
7161 cvtnum(n > 0 ? n : 0);
7131 goto record; 7162 goto record;
7132 } 7163 }
7133 7164
@@ -9180,8 +9211,8 @@ setinteractive(int on)
9180 if (!did_banner) { 9211 if (!did_banner) {
9181 /* note: ash and hush share this string */ 9212 /* note: ash and hush share this string */
9182 out1fmt("\n\n%s %s\n" 9213 out1fmt("\n\n%s %s\n"
9183 "Enter 'help' for a list of built-in commands." 9214 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9184 "\n\n", 9215 "\n",
9185 bb_banner, 9216 bb_banner,
9186 "built-in shell (ash)" 9217 "built-in shell (ash)"
9187 ); 9218 );
@@ -9434,7 +9465,7 @@ static int exportcmd(int, char **) FAST_FUNC;
9434#if ENABLE_ASH_GETOPTS 9465#if ENABLE_ASH_GETOPTS
9435static int getoptscmd(int, char **) FAST_FUNC; 9466static int getoptscmd(int, char **) FAST_FUNC;
9436#endif 9467#endif
9437#if !ENABLE_FEATURE_SH_EXTRA_QUIET 9468#if ENABLE_ASH_HELP
9438static int helpcmd(int, char **) FAST_FUNC; 9469static int helpcmd(int, char **) FAST_FUNC;
9439#endif 9470#endif
9440#if MAX_HISTORY 9471#if MAX_HISTORY
@@ -9510,7 +9541,7 @@ static const struct builtincmd builtintab[] = {
9510 { BUILTIN_REGULAR "getopts" , getoptscmd }, 9541 { BUILTIN_REGULAR "getopts" , getoptscmd },
9511#endif 9542#endif
9512 { BUILTIN_NOSPEC "hash" , hashcmd }, 9543 { BUILTIN_NOSPEC "hash" , hashcmd },
9513#if !ENABLE_FEATURE_SH_EXTRA_QUIET 9544#if ENABLE_ASH_HELP
9514 { BUILTIN_NOSPEC "help" , helpcmd }, 9545 { BUILTIN_NOSPEC "help" , helpcmd },
9515#endif 9546#endif
9516#if MAX_HISTORY 9547#if MAX_HISTORY
@@ -10080,16 +10111,7 @@ preadfd(void)
10080# if ENABLE_FEATURE_TAB_COMPLETION 10111# if ENABLE_FEATURE_TAB_COMPLETION
10081 line_input_state->path_lookup = pathval(); 10112 line_input_state->path_lookup = pathval();
10082# endif 10113# endif
10083 /* Unicode support should be activated even if LANG is set 10114 reinit_unicode_for_ash();
10084 * _during_ shell execution, not only if it was set when
10085 * shell was started. Therefore, re-check LANG every time:
10086 */
10087 {
10088 const char *s = lookupvar("LC_ALL");
10089 if (!s) s = lookupvar("LC_CTYPE");
10090 if (!s) s = lookupvar("LANG");
10091 reinit_unicode(s);
10092 }
10093 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); 10115 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
10094 if (nr == 0) { 10116 if (nr == 0) {
10095 /* Ctrl+C pressed */ 10117 /* Ctrl+C pressed */
@@ -13059,10 +13081,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13059 13081
13060/* ============ Builtins */ 13082/* ============ Builtins */
13061 13083
13062#if !ENABLE_FEATURE_SH_EXTRA_QUIET 13084#if ENABLE_ASH_HELP
13063/*
13064 * Lists available builtins
13065 */
13066static int FAST_FUNC 13085static int FAST_FUNC
13067helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 13086helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13068{ 13087{
@@ -13080,7 +13099,7 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13080 col = 0; 13099 col = 0;
13081 } 13100 }
13082 } 13101 }
13083#if ENABLE_FEATURE_SH_STANDALONE 13102# if ENABLE_FEATURE_SH_STANDALONE
13084 { 13103 {
13085 const char *a = applet_names; 13104 const char *a = applet_names;
13086 while (*a) { 13105 while (*a) {
@@ -13092,11 +13111,11 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13092 a += strlen(a) + 1; 13111 a += strlen(a) + 1;
13093 } 13112 }
13094 } 13113 }
13095#endif 13114# endif
13096 out1fmt("\n\n"); 13115 out1fmt("\n\n");
13097 return EXIT_SUCCESS; 13116 return EXIT_SUCCESS;
13098} 13117}
13099#endif /* FEATURE_SH_EXTRA_QUIET */ 13118#endif
13100 13119
13101#if MAX_HISTORY 13120#if MAX_HISTORY
13102static int FAST_FUNC 13121static int FAST_FUNC
diff --git a/shell/hush.c b/shell/hush.c
index e1d0ece29..92d790180 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1977,6 +1977,26 @@ static struct variable *set_vars_and_save_old(char **strings)
1977 1977
1978 1978
1979/* 1979/*
1980 * Unicode helper
1981 */
1982static void reinit_unicode_for_hush(void)
1983{
1984 /* Unicode support should be activated even if LANG is set
1985 * _during_ shell execution, not only if it was set when
1986 * shell was started. Therefore, re-check LANG every time:
1987 */
1988 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
1989 || ENABLE_UNICODE_USING_LOCALE
1990 ) {
1991 const char *s = get_local_var_value("LC_ALL");
1992 if (!s) s = get_local_var_value("LC_CTYPE");
1993 if (!s) s = get_local_var_value("LANG");
1994 reinit_unicode(s);
1995 }
1996}
1997
1998
1999/*
1980 * in_str support 2000 * in_str support
1981 */ 2001 */
1982static int FAST_FUNC static_get(struct in_str *i) 2002static int FAST_FUNC static_get(struct in_str *i)
@@ -2042,15 +2062,7 @@ static void get_user_input(struct in_str *i)
2042 /* Enable command line editing only while a command line 2062 /* Enable command line editing only while a command line
2043 * is actually being read */ 2063 * is actually being read */
2044 do { 2064 do {
2045 /* Unicode support should be activated even if LANG is set 2065 reinit_unicode_for_hush();
2046 * _during_ shell execution, not only if it was set when
2047 * shell was started. Therefore, re-check LANG every time:
2048 */
2049 const char *s = get_local_var_value("LC_ALL");
2050 if (!s) s = get_local_var_value("LC_CTYPE");
2051 if (!s) s = get_local_var_value("LANG");
2052 reinit_unicode(s);
2053
2054 G.flag_SIGINT = 0; 2066 G.flag_SIGINT = 0;
2055 /* buglet: SIGINT will not make new prompt to appear _at once_, 2067 /* buglet: SIGINT will not make new prompt to appear _at once_,
2056 * only after <Enter>. (^C will work) */ 2068 * only after <Enter>. (^C will work) */
@@ -5028,8 +5040,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5028 5040
5029 /* Handle any expansions */ 5041 /* Handle any expansions */
5030 if (exp_op == 'L') { 5042 if (exp_op == 'L') {
5043 reinit_unicode_for_hush();
5031 debug_printf_expand("expand: length(%s)=", val); 5044 debug_printf_expand("expand: length(%s)=", val);
5032 val = utoa(val ? strlen(val) : 0); 5045 val = utoa(val ? unicode_strlen(val) : 0);
5033 debug_printf_expand("%s\n", val); 5046 debug_printf_expand("%s\n", val);
5034 } else if (exp_op) { 5047 } else if (exp_op) {
5035 if (exp_op == '%' || exp_op == '#') { 5048 if (exp_op == '%' || exp_op == '#') {
diff --git a/shell/hush_test/hush-misc/unicode1.right b/shell/hush_test/hush-misc/unicode1.right
new file mode 100644
index 000000000..d3bbbf697
--- /dev/null
+++ b/shell/hush_test/hush-misc/unicode1.right
@@ -0,0 +1,3 @@
11
21
3Ok
diff --git a/shell/hush_test/hush-misc/unicode1.tests b/shell/hush_test/hush-misc/unicode1.tests
new file mode 100755
index 000000000..8788ba910
--- /dev/null
+++ b/shell/hush_test/hush-misc/unicode1.tests
@@ -0,0 +1,13 @@
1LANG=en_US.UTF-8
2
3# A combining character U+300
4a=`printf "\xcc\x80"`
5# Should print 1
6echo ${#a}
7
8# A Japanese katakana charachter U+30a3
9a=`printf "\xe3\x82\xa3"`
10# Should print 1
11echo ${#a}
12
13echo Ok
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index f75851085..266657f3b 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -21,31 +21,31 @@
21//usage: "(this version of syslogd ignores /etc/syslog.conf)\n" 21//usage: "(this version of syslogd ignores /etc/syslog.conf)\n"
22//usage: ) 22//usage: )
23//usage: "\n -n Run in foreground" 23//usage: "\n -n Run in foreground"
24//usage: "\n -O FILE Log to FILE (default:/var/log/messages)"
25//usage: "\n -l N Log only messages more urgent than prio N (1-8)"
26//usage: "\n -S Smaller output"
27//usage: IF_FEATURE_ROTATE_LOGFILE(
28//usage: "\n -s SIZE Max size (KB) before rotation (default:200KB, 0=off)"
29//usage: "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)"
30//usage: )
31//usage: IF_FEATURE_REMOTE_LOG( 24//usage: IF_FEATURE_REMOTE_LOG(
32//usage: "\n -R HOST[:PORT] Log to HOST:PORT (default PORT:514)" 25//usage: "\n -R HOST[:PORT] Log to HOST:PORT (default PORT:514)"
33//usage: "\n -L Log locally and via network (default is network only if -R)" 26//usage: "\n -L Log locally and via network (default is network only if -R)"
34//usage: ) 27//usage: )
35//usage: IF_FEATURE_SYSLOGD_DUP(
36//usage: "\n -D Drop duplicates"
37//usage: )
38//usage: IF_FEATURE_IPC_SYSLOG( 28//usage: IF_FEATURE_IPC_SYSLOG(
39/* NB: -Csize shouldn't have space (because size is optional) */ 29/* NB: -Csize shouldn't have space (because size is optional) */
40//usage: "\n -C[size_kb] Log to shared mem buffer (use logread to read it)" 30//usage: "\n -C[size_kb] Log to shared mem buffer (use logread to read it)"
41//usage: ) 31//usage: )
32//usage: IF_FEATURE_KMSG_SYSLOG(
33//usage: "\n -K Log to kernel printk buffer (use dmesg to read it)"
34//usage: )
35//usage: "\n -O FILE Log to FILE (default:/var/log/messages, stdout if -)"
36//usage: IF_FEATURE_ROTATE_LOGFILE(
37//usage: "\n -s SIZE Max size (KB) before rotation (default:200KB, 0=off)"
38//usage: "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)"
39//usage: )
40//usage: "\n -l N Log only messages more urgent than prio N (1-8)"
41//usage: "\n -S Smaller output"
42//usage: IF_FEATURE_SYSLOGD_DUP(
43//usage: "\n -D Drop duplicates"
44//usage: )
42//usage: IF_FEATURE_SYSLOGD_CFG( 45//usage: IF_FEATURE_SYSLOGD_CFG(
43//usage: "\n -f FILE Use FILE as config (default:/etc/syslog.conf)" 46//usage: "\n -f FILE Use FILE as config (default:/etc/syslog.conf)"
44//usage: ) 47//usage: )
45/* //usage: "\n -m MIN Minutes between MARK lines (default:20, 0=off)" */ 48/* //usage: "\n -m MIN Minutes between MARK lines (default:20, 0=off)" */
46//usage: IF_FEATURE_KMSG_SYSLOG(
47//usage: "\n -K Log to kernel printk buffer (use dmesg to read it)"
48//usage: )
49//usage: 49//usage:
50//usage:#define syslogd_example_usage 50//usage:#define syslogd_example_usage
51//usage: "$ syslogd -R masterlog:514\n" 51//usage: "$ syslogd -R masterlog:514\n"
@@ -110,6 +110,7 @@ typedef struct {
110typedef struct logFile_t { 110typedef struct logFile_t {
111 const char *path; 111 const char *path;
112 int fd; 112 int fd;
113 time_t last_log_time;
113#if ENABLE_FEATURE_ROTATE_LOGFILE 114#if ENABLE_FEATURE_ROTATE_LOGFILE
114 unsigned size; 115 unsigned size;
115 uint8_t isRegular; 116 uint8_t isRegular;
@@ -165,7 +166,6 @@ struct globals {
165#if ENABLE_FEATURE_IPC_SYSLOG 166#if ENABLE_FEATURE_IPC_SYSLOG
166 struct shbuf_ds *shbuf; 167 struct shbuf_ds *shbuf;
167#endif 168#endif
168 time_t last_log_time;
169 /* localhost's name. We print only first 64 chars */ 169 /* localhost's name. We print only first 64 chars */
170 char *hostname; 170 char *hostname;
171 171
@@ -569,7 +569,7 @@ static void log_to_kmsg(int pri, const char *msg)
569 */ 569 */
570 pri &= G.primask; 570 pri &= G.primask;
571 571
572 write(G.kmsgfd, G.printbuf, sprintf(G.printbuf, "<%d>%s\n", pri, msg)); 572 full_write(G.kmsgfd, G.printbuf, sprintf(G.printbuf, "<%d>%s\n", pri, msg));
573} 573}
574#else 574#else
575static void kmsg_init(void) {} 575static void kmsg_init(void) {}
@@ -585,42 +585,54 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
585#endif 585#endif
586 int len = strlen(msg); 586 int len = strlen(msg);
587 587
588 if (log_file->fd >= 0) { 588 /* fd can't be 0 (we connect fd 0 to /dev/log socket) */
589 /* Reopen log file every second. This allows admin 589 /* fd is 1 if "-O -" is in use */
590 * to delete the file and not worry about restarting us. 590 if (log_file->fd > 1) {
591 /* Reopen log files every second. This allows admin
592 * to delete the files and not worry about restarting us.
591 * This costs almost nothing since it happens 593 * This costs almost nothing since it happens
592 * _at most_ once a second. 594 * _at most_ once a second for each file, and happens
595 * only when each file is actually written.
593 */ 596 */
594 if (!now) 597 if (!now)
595 now = time(NULL); 598 now = time(NULL);
596 if (G.last_log_time != now) { 599 if (log_file->last_log_time != now) {
597 G.last_log_time = now; 600 log_file->last_log_time = now;
598 close(log_file->fd); 601 close(log_file->fd);
599 goto reopen; 602 goto reopen;
600 } 603 }
601 } else { 604 }
605 else if (log_file->fd == 1) {
606 /* We are logging to stdout: do nothing */
607 }
608 else {
609 if (LONE_DASH(log_file->path)) {
610 log_file->fd = 1;
611 /* log_file->isRegular = 0; - already is */
612 } else {
602 reopen: 613 reopen:
603 log_file->fd = open(log_file->path, O_WRONLY | O_CREAT 614 log_file->fd = open(log_file->path, O_WRONLY | O_CREAT
604 | O_NOCTTY | O_APPEND | O_NONBLOCK, 615 | O_NOCTTY | O_APPEND | O_NONBLOCK,
605 0666); 616 0666);
606 if (log_file->fd < 0) { 617 if (log_file->fd < 0) {
607 /* cannot open logfile? - print to /dev/console then */ 618 /* cannot open logfile? - print to /dev/console then */
608 int fd = device_open(DEV_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK); 619 int fd = device_open(DEV_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK);
609 if (fd < 0) 620 if (fd < 0)
610 fd = 2; /* then stderr, dammit */ 621 fd = 2; /* then stderr, dammit */
611 full_write(fd, msg, len); 622 full_write(fd, msg, len);
612 if (fd != 2) 623 if (fd != 2)
613 close(fd); 624 close(fd);
614 return; 625 return;
615 } 626 }
616#if ENABLE_FEATURE_ROTATE_LOGFILE 627#if ENABLE_FEATURE_ROTATE_LOGFILE
617 { 628 {
618 struct stat statf; 629 struct stat statf;
619 log_file->isRegular = (fstat(log_file->fd, &statf) == 0 && S_ISREG(statf.st_mode)); 630 log_file->isRegular = (fstat(log_file->fd, &statf) == 0 && S_ISREG(statf.st_mode));
620 /* bug (mostly harmless): can wrap around if file > 4gb */ 631 /* bug (mostly harmless): can wrap around if file > 4gb */
621 log_file->size = statf.st_size; 632 log_file->size = statf.st_size;
622 } 633 }
623#endif 634#endif
635 }
624 } 636 }
625 637
626#ifdef SYSLOGD_WRLOCK 638#ifdef SYSLOGD_WRLOCK
@@ -667,9 +679,14 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
667 close(log_file->fd); 679 close(log_file->fd);
668 goto reopen; 680 goto reopen;
669 } 681 }
670 log_file->size += 682/* TODO: what to do on write errors ("disk full")? */
683 len = full_write(log_file->fd, msg, len);
684 if (len > 0)
685 log_file->size += len;
686#else
687 full_write(log_file->fd, msg, len);
671#endif 688#endif
672 full_write(log_file->fd, msg, len); 689
673#ifdef SYSLOGD_WRLOCK 690#ifdef SYSLOGD_WRLOCK
674 fl.l_type = F_UNLCK; 691 fl.l_type = F_UNLCK;
675 fcntl(log_file->fd, F_SETLKW, &fl); 692 fcntl(log_file->fd, F_SETLKW, &fl);
@@ -865,7 +882,6 @@ static int try_to_resolve_remote(remoteHost_t *rh)
865static void do_syslogd(void) NORETURN; 882static void do_syslogd(void) NORETURN;
866static void do_syslogd(void) 883static void do_syslogd(void)
867{ 884{
868 int sock_fd;
869#if ENABLE_FEATURE_REMOTE_LOG 885#if ENABLE_FEATURE_REMOTE_LOG
870 llist_t *item; 886 llist_t *item;
871#endif 887#endif
@@ -886,7 +902,7 @@ static void do_syslogd(void)
886 signal(SIGALRM, do_mark); 902 signal(SIGALRM, do_mark);
887 alarm(G.markInterval); 903 alarm(G.markInterval);
888#endif 904#endif
889 sock_fd = create_socket(); 905 xmove_fd(create_socket(), STDIN_FILENO);
890 906
891 if (option_mask32 & OPT_circularlog) 907 if (option_mask32 & OPT_circularlog)
892 ipcsyslog_init(); 908 ipcsyslog_init();
@@ -907,7 +923,7 @@ static void do_syslogd(void)
907 recvbuf = G.recvbuf; 923 recvbuf = G.recvbuf;
908#endif 924#endif
909 read_again: 925 read_again:
910 sz = read(sock_fd, recvbuf, MAX_READ - 1); 926 sz = read(STDIN_FILENO, recvbuf, MAX_READ - 1);
911 if (sz < 0) { 927 if (sz < 0) {
912 if (!bb_got_signal) 928 if (!bb_got_signal)
913 bb_perror_msg("read from %s", _PATH_LOG); 929 bb_perror_msg("read from %s", _PATH_LOG);
@@ -978,7 +994,6 @@ static void do_syslogd(void)
978 } /* while (!bb_got_signal) */ 994 } /* while (!bb_got_signal) */
979 995
980 timestamp_and_log_internal("syslogd exiting"); 996 timestamp_and_log_internal("syslogd exiting");
981 puts("syslogd exiting");
982 remove_pidfile(CONFIG_PID_FILE_PATH "/syslogd.pid"); 997 remove_pidfile(CONFIG_PID_FILE_PATH "/syslogd.pid");
983 ipcsyslog_cleanup(); 998 ipcsyslog_cleanup();
984 if (option_mask32 & OPT_kmsg) 999 if (option_mask32 & OPT_kmsg)
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index 323b3849d..f6d9f2105 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -171,6 +171,26 @@ testing "grep -w word match second word" \
171 "bword,word\n""wordb,word\n""bwordb,word\n" \ 171 "bword,word\n""wordb,word\n""bwordb,word\n" \
172 "" 172 ""
173 173
174# -r on symlink to dir should recurse into dir
175mkdir -p grep.testdir/foo
176echo bar > grep.testdir/foo/file
177ln -s foo grep.testdir/symfoo
178testing "grep -r on symlink to dir" \
179 "grep -r . grep.testdir/symfoo" \
180 "grep.testdir/symfoo/file:bar\n" \
181 "" ""
182rm -Rf grep.testdir
183
184# But -r on dir/symlink_to_dir should not recurse into symlink_to_dir
185mkdir -p grep.testdir/foo
186echo bar > grep.testdir/foo/file
187ln -s foo grep.testdir/symfoo
188testing "grep -r on dir/symlink to dir" \
189 "grep -r . grep.testdir" \
190 "grep.testdir/foo/file:bar\n" \
191 "" ""
192rm -Rf grep.testdir
193
174# testing "test name" "commands" "expected result" "file input" "stdin" 194# testing "test name" "commands" "expected result" "file input" "stdin"
175# file input will be file called "input" 195# file input will be file called "input"
176# test can create a file "actual" instead of writing to stdout 196# test can create a file "actual" instead of writing to stdout
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 9494ac2de..19f2915ce 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -329,6 +329,10 @@ line with \\
329continuation 329continuation
330" 330"
331 331
332testing "sed s///NUM test" \
333 "sed -e 's/a/b/2; s/a/c/g'" \
334 "cb\n" "" "aa\n"
335
332# testing "description" "commands" "result" "infile" "stdin" 336# testing "description" "commands" "result" "infile" "stdin"
333 337
334exit $FAILCOUNT 338exit $FAILCOUNT
diff --git a/testsuite/test.tests b/testsuite/test.tests
index 2c92e34ba..1c2edaf62 100755
--- a/testsuite/test.tests
+++ b/testsuite/test.tests
@@ -76,4 +76,24 @@ testing "test ! a = b -a ! c = d: should be true (0)" \
76 "0\n" \ 76 "0\n" \
77 "" "" 77 "" ""
78 78
79testing "test '!' = '!': should be true (0)" \
80 "busybox test '!' = '!'; echo \$?" \
81 "0\n" \
82 "" ""
83
84testing "test '(' = '(': should be true (0)" \
85 "busybox test '(' = '('; echo \$?" \
86 "0\n" \
87 "" ""
88
89testing "test '!' '!' = '!': should be false (1)" \
90 "busybox test '!' '!' = '!'; echo \$?" \
91 "1\n" \
92 "" ""
93
94testing "test '!' '(' = '(': should be false (1)" \
95 "busybox test '!' '(' = '('; echo \$?" \
96 "1\n" \
97 "" ""
98
79exit $FAILCOUNT 99exit $FAILCOUNT
diff --git a/util-linux/fatattr.c b/util-linux/fatattr.c
index 0f8d63268..5d933874a 100644
--- a/util-linux/fatattr.c
+++ b/util-linux/fatattr.c
@@ -34,8 +34,8 @@
34#include "libbb.h" 34#include "libbb.h"
35/* linux/msdos_fs.h says: */ 35/* linux/msdos_fs.h says: */
36#ifndef FAT_IOCTL_GET_ATTRIBUTES 36#ifndef FAT_IOCTL_GET_ATTRIBUTES
37# define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32) 37# define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, uint32_t)
38# define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32) 38# define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, uint32_t)
39#endif 39#endif
40 40
41/* Currently supports only the FAT flags, not the NTFS ones. 41/* Currently supports only the FAT flags, not the NTFS ones.
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index e80b58f2e..b2d56575f 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -972,7 +972,7 @@ wait_for_seqfile(const char *seq)
972 break; 972 break;
973 } 973 }
974 seqbuf[seqlen] = '\0'; 974 seqbuf[seqlen] = '\0';
975 if (seqbuf[0] == '\n') { 975 if (seqbuf[0] == '\n' || seqbuf[0] == '\0') {
976 /* seed file: write out seq ASAP */ 976 /* seed file: write out seq ASAP */
977 xwrite_str(seq_fd, seq); 977 xwrite_str(seq_fd, seq);
978 xlseek(seq_fd, 0, SEEK_SET); 978 xlseek(seq_fd, 0, SEEK_SET);