diff options
author | Ron Yorston <rmy@pobox.com> | 2014-10-06 12:50:22 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2014-10-06 12:50:22 +0100 |
commit | b04d11dcbadda2620743a1dd923938f2f3043a38 (patch) | |
tree | 971afe425a81304b79e44122e220c7a69efe2616 | |
parent | 124bbf02948b7ac0babb4ead04acd1559db182d3 (diff) | |
parent | 760d035699c4a878f9109544c1d35ea0d5f6b76c (diff) | |
download | busybox-w32-b04d11dcbadda2620743a1dd923938f2f3043a38.tar.gz busybox-w32-b04d11dcbadda2620743a1dd923938f2f3043a38.tar.bz2 busybox-w32-b04d11dcbadda2620743a1dd923938f2f3043a38.zip |
Merge branch 'busybox' into merge
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 | ||
53 | static 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 | |||
52 | int main(int argc, char **argv) | 63 | int 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 | |||
566 | static char* format_line(char* /*, int*/); | 566 | static char* format_line(char* /*, int*/); |
567 | static void refresh(int); // update the terminal from screen[] | 567 | static void refresh(int); // update the terminal from screen[] |
568 | 568 | ||
569 | static void Indicate_Error(void); // use flash or beep to indicate error | 569 | static void indicate_error(void); // use flash or beep to indicate error |
570 | #define indicate_error(c) Indicate_Error() | ||
571 | static void Hit_Return(void); | 570 | static 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 | ||
2220 | static char *find_pair(char *p, const char c) | 2213 | static 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 | ||
3109 | static void Indicate_Error(void) | 3102 | static 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 |
559 | ACTF(perm) | 559 | ACTF(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)) | |||
342 | IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP)) | 342 | IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP)) |
343 | IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) | 343 | IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) |
344 | IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) | 344 | IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) |
345 | IF_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)) */ |
347 | IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd)) | 346 | IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd)) |
348 | IF_TEE(APPLET(tee, BB_DIR_USR_BIN, BB_SUID_DROP)) | 347 | IF_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; | |||
403 | char *last_char_is(const char *s, int c) FAST_FUNC; | 403 | char *last_char_is(const char *s, int c) FAST_FUNC; |
404 | const char* endofname(const char *name) FAST_FUNC; | 404 | const char* endofname(const char *name) FAST_FUNC; |
405 | 405 | ||
406 | void ndelay_on(int fd) FAST_FUNC; | 406 | int ndelay_on(int fd) FAST_FUNC; |
407 | void ndelay_off(int fd) FAST_FUNC; | 407 | int ndelay_off(int fd) FAST_FUNC; |
408 | void close_on_exec_on(int fd) FAST_FUNC; | 408 | void close_on_exec_on(int fd) FAST_FUNC; |
409 | void xdup2(int, int) FAST_FUNC; | 409 | void xdup2(int, int) FAST_FUNC; |
410 | void xmove_fd(int, int) FAST_FUNC; | 410 | void 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) |
1333 | void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; | 1333 | void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; |
1334 | void nuke_str(char *str) FAST_FUNC; | 1334 | void nuke_str(char *str) FAST_FUNC; |
1335 | int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC; | ||
1335 | int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; | 1336 | int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; |
1336 | int ask_and_check_password(const struct passwd *pw) FAST_FUNC; | 1337 | int 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 | |||
152 | lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o | 152 | lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o |
153 | lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o | 153 | lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o |
154 | lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o | 154 | lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o |
155 | lib-$(CONFIG_FEATURE_FTP_AUTHENTICATION) += pw_encrypt.o | ||
155 | 156 | ||
156 | lib-$(CONFIG_DF) += find_mount_point.o | 157 | lib-$(CONFIG_DF) += find_mount_point.o |
157 | lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o | 158 | lib-$(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 | ||
42 | static 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 | */ | ||
71 | int 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 @@ | |||
41 | int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw, | 98 | int 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 | |||
929 | enum { | 948 | enum { |
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 | */ | ||
957 | static 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 */ | ||
979 | static 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 | ||
1077 | void FAST_FUNC sha3_begin(sha3_ctx_t *ctx) | 1356 | void 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 */ |
28 | void FAST_FUNC ndelay_on(int fd) | 28 | int 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 | ||
36 | void FAST_FUNC ndelay_off(int fd) | 37 | int 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 | ||
44 | void FAST_FUNC close_on_exec_on(int fd) | 46 | void 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 | ||
502 | config 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 | |||
509 | config 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 | |||
518 | config TIME | 502 | config 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 | |||
39 | lib-$(CONFIG_RX) += rx.o | 39 | lib-$(CONFIG_RX) += rx.o |
40 | lib-$(CONFIG_SETSID) += setsid.o | 40 | lib-$(CONFIG_SETSID) += setsid.o |
41 | lib-$(CONFIG_STRINGS) += strings.o | 41 | lib-$(CONFIG_STRINGS) += strings.o |
42 | lib-$(CONFIG_TASKSET) += taskset.o | ||
43 | lib-$(CONFIG_TIME) += time.o | 42 | lib-$(CONFIG_TIME) += time.o |
44 | lib-$(CONFIG_TIMEOUT) += timeout.o | 43 | lib-$(CONFIG_TIMEOUT) += timeout.o |
45 | lib-$(CONFIG_TTYSIZE) += ttysize.o | 44 | lib-$(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 | ||
37 | static int display(const char *data, const char *pattern, int flag) | 37 | static 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 | ||
47 | static void modinfo(const char *path, const char *version, | 47 | static 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 | ||
137 | config 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 | |||
137 | config FTPGET | 144 | config 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 | ||
1111 | int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1112 | int 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 | ||
983 | static 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 | */ |
1659 | static unsigned | 1675 | static unsigned |
1660 | retry_interval(void) | 1676 | poll_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 | } | ||
1670 | static unsigned | ||
1671 | poll_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 | } |
1688 | static void | ||
1689 | adjust_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 | } | ||
1684 | static NOINLINE void | 1723 | static NOINLINE void |
1685 | recv_and_process_peer_pkt(peer_t *p) | 1724 | recv_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")) |
334 | enum { | 336 | enum { |
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) | |||
850 | static int common_ping_main(int opt, char **argv) | 854 | static 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 | /* ð_addr, */ null_ip, | 372 | /* ð_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 | /* ð_addr, */ ip, | 383 | /* ð_addr, */ ip, |
383 | ð_addr, ip); | 384 | ð_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 | /* ð_addr, */ ip, | 396 | /* ð_addr, */ ip, |
396 | ð_addr, ip); | 397 | ð_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 | /* ð_addr, */ ip, | 408 | /* ð_addr, */ ip, |
408 | ð_addr, ip); | 409 | ð_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, ð_addr, ETH_ALEN) != 0) { |
505 | && memcmp(&p.arp.arp_sha, ð_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, ð_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 | ||
502 | static unsigned long display_header(int scr_width, int *lines_rem_p) | 502 | enum { |
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 | /* | 519 | static 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); | 553 | static 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 | ||
583 | static NOINLINE void display_process_list(int lines_rem, int scr_width) | 591 | static 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) */ |
782 | static void display_topmem_header(int scr_width, int *lines_rem_p) | 790 | static 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 | ||
2199 | static 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 |
9435 | static int getoptscmd(int, char **) FAST_FUNC; | 9466 | static int getoptscmd(int, char **) FAST_FUNC; |
9436 | #endif | 9467 | #endif |
9437 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | 9468 | #if ENABLE_ASH_HELP |
9438 | static int helpcmd(int, char **) FAST_FUNC; | 9469 | static 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 | */ | ||
13066 | static int FAST_FUNC | 13085 | static int FAST_FUNC |
13067 | helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 13086 | helpcmd(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 |
13102 | static int FAST_FUNC | 13121 | static 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 | */ | ||
1982 | static 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 | */ |
1982 | static int FAST_FUNC static_get(struct in_str *i) | 2002 | static 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 @@ | |||
1 | 1 | ||
2 | 1 | ||
3 | Ok | ||
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 @@ | |||
1 | LANG=en_US.UTF-8 | ||
2 | |||
3 | # A combining character U+300 | ||
4 | a=`printf "\xcc\x80"` | ||
5 | # Should print 1 | ||
6 | echo ${#a} | ||
7 | |||
8 | # A Japanese katakana charachter U+30a3 | ||
9 | a=`printf "\xe3\x82\xa3"` | ||
10 | # Should print 1 | ||
11 | echo ${#a} | ||
12 | |||
13 | echo 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 { | |||
110 | typedef struct logFile_t { | 110 | typedef 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 |
575 | static void kmsg_init(void) {} | 575 | static 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) | |||
865 | static void do_syslogd(void) NORETURN; | 882 | static void do_syslogd(void) NORETURN; |
866 | static void do_syslogd(void) | 883 | static 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 | ||
175 | mkdir -p grep.testdir/foo | ||
176 | echo bar > grep.testdir/foo/file | ||
177 | ln -s foo grep.testdir/symfoo | ||
178 | testing "grep -r on symlink to dir" \ | ||
179 | "grep -r . grep.testdir/symfoo" \ | ||
180 | "grep.testdir/symfoo/file:bar\n" \ | ||
181 | "" "" | ||
182 | rm -Rf grep.testdir | ||
183 | |||
184 | # But -r on dir/symlink_to_dir should not recurse into symlink_to_dir | ||
185 | mkdir -p grep.testdir/foo | ||
186 | echo bar > grep.testdir/foo/file | ||
187 | ln -s foo grep.testdir/symfoo | ||
188 | testing "grep -r on dir/symlink to dir" \ | ||
189 | "grep -r . grep.testdir" \ | ||
190 | "grep.testdir/foo/file:bar\n" \ | ||
191 | "" "" | ||
192 | rm -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 \\ | |||
329 | continuation | 329 | continuation |
330 | " | 330 | " |
331 | 331 | ||
332 | testing "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 | ||
334 | exit $FAILCOUNT | 338 | exit $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 | ||
79 | testing "test '!' = '!': should be true (0)" \ | ||
80 | "busybox test '!' = '!'; echo \$?" \ | ||
81 | "0\n" \ | ||
82 | "" "" | ||
83 | |||
84 | testing "test '(' = '(': should be true (0)" \ | ||
85 | "busybox test '(' = '('; echo \$?" \ | ||
86 | "0\n" \ | ||
87 | "" "" | ||
88 | |||
89 | testing "test '!' '!' = '!': should be false (1)" \ | ||
90 | "busybox test '!' '!' = '!'; echo \$?" \ | ||
91 | "1\n" \ | ||
92 | "" "" | ||
93 | |||
94 | testing "test '!' '(' = '(': should be false (1)" \ | ||
95 | "busybox test '!' '(' = '('; echo \$?" \ | ||
96 | "1\n" \ | ||
97 | "" "" | ||
98 | |||
79 | exit $FAILCOUNT | 99 | exit $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); |