diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 13:08:20 +1000 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 13:08:20 +1000 |
commit | 6a6efd31038d7afe977e3059508ae863e65cbdf5 (patch) | |
tree | 5cd69a751e893b83176751c80fcea7a7afeed1ae | |
parent | a6a2325ecf402054132daae169f71edb0fb849e3 (diff) | |
parent | 29082231d0cb1a5b327de5d515b16f332d4dbdaf (diff) | |
download | busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.tar.gz busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.tar.bz2 busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.zip |
Merge branch 'origin/master' (early part)
142 files changed, 3445 insertions, 2141 deletions
diff --git a/.gitignore b/.gitignore index 53bd540a2..7d2cca67c 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -7,6 +7,7 @@ | |||
7 | *.a | 7 | *.a |
8 | *.s | 8 | *.s |
9 | Kbuild | 9 | Kbuild |
10 | Config.in | ||
10 | 11 | ||
11 | # | 12 | # |
12 | # Never ignore these | 13 | # Never ignore these |
@@ -152,6 +152,7 @@ config UNICODE_USING_LOCALE | |||
152 | help | 152 | help |
153 | With this option on, Unicode support is implemented using libc | 153 | With this option on, Unicode support is implemented using libc |
154 | routines. Otherwise, internal implementation is used. | 154 | routines. Otherwise, internal implementation is used. |
155 | Internal implementation is smaller. | ||
155 | 156 | ||
156 | config FEATURE_CHECK_UNICODE_IN_ENV | 157 | config FEATURE_CHECK_UNICODE_IN_ENV |
157 | bool "Check $LANG environment variable" | 158 | bool "Check $LANG environment variable" |
@@ -1,5 +1,5 @@ | |||
1 | VERSION = 1 | 1 | VERSION = 1 |
2 | PATCHLEVEL = 17 | 2 | PATCHLEVEL = 18 |
3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 0 |
4 | EXTRAVERSION = .git | 4 | EXTRAVERSION = .git |
5 | NAME = Unnamed | 5 | NAME = Unnamed |
@@ -361,7 +361,7 @@ scripts/basic/%: scripts_basic ; | |||
361 | 361 | ||
362 | # This target generates Kbuild's and Config.in's from *.c files | 362 | # This target generates Kbuild's and Config.in's from *.c files |
363 | PHONY += gen_build_files | 363 | PHONY += gen_build_files |
364 | gen_build_files: | 364 | gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) |
365 | $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) | 365 | $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) |
366 | 366 | ||
367 | # bbox: we have helpers in applets/ | 367 | # bbox: we have helpers in applets/ |
@@ -511,9 +511,11 @@ include $(srctree)/Makefile.flags | |||
511 | # with it and forgot to run make oldconfig. | 511 | # with it and forgot to run make oldconfig. |
512 | # If kconfig.d is missing then we are probarly in a cleaned tree so | 512 | # If kconfig.d is missing then we are probarly in a cleaned tree so |
513 | # we execute the config step to be sure to catch updated Kconfig files | 513 | # we execute the config step to be sure to catch updated Kconfig files |
514 | include/autoconf.h: .kconfig.d .config | 514 | include/autoconf.h: .kconfig.d .config $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) | gen_build_files |
515 | $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig | 515 | $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig |
516 | 516 | ||
517 | include/usage.h: gen_build_files | ||
518 | |||
517 | else | 519 | else |
518 | # Dummy target needed, because used as prerequisite | 520 | # Dummy target needed, because used as prerequisite |
519 | include/autoconf.h: ; | 521 | include/autoconf.h: ; |
@@ -1,5 +1,8 @@ | |||
1 | Busybox TODO | 1 | Busybox TODO |
2 | 2 | ||
3 | Harvest patches from | ||
4 | http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/ | ||
5 | |||
3 | Stuff that needs to be done. This is organized by who plans to get around to | 6 | Stuff that needs to be done. This is organized by who plans to get around to |
4 | doing it eventually, but that doesn't mean they "own" the item. If you want to | 7 | doing it eventually, but that doesn't mean they "own" the item. If you want to |
5 | do one of these bounce an email off the person it's listed under to see if they | 8 | do one of these bounce an email off the person it's listed under to see if they |
@@ -9,9 +12,6 @@ between your work and theirs. But otherwise, all of these are fair game. | |||
9 | Rob Landley suggested this: | 12 | Rob Landley suggested this: |
10 | Implement bb_realpath() that can handle NULL on non-glibc. | 13 | Implement bb_realpath() that can handle NULL on non-glibc. |
11 | 14 | ||
12 | Remove obsolete _() wrapper crud for internationalization we don't do. | ||
13 | Figure out where we need utf8 support, and add it. | ||
14 | |||
15 | sh | 15 | sh |
16 | The command shell situation is a mess. We have two different | 16 | The command shell situation is a mess. We have two different |
17 | shells that don't really share any code, and the "standalone shell" doesn't | 17 | shells that don't really share any code, and the "standalone shell" doesn't |
@@ -31,7 +31,7 @@ Rob Landley suggested this: | |||
31 | How much internationalization should we do? | 31 | How much internationalization should we do? |
32 | 32 | ||
33 | The low hanging fruit is UTF-8 character set support. We should do this. | 33 | The low hanging fruit is UTF-8 character set support. We should do this. |
34 | (Vodz pointed out the shell's cmdedit as needing work here. What else?) | 34 | See TODO_unicode file. |
35 | 35 | ||
36 | We also have lots of hardwired english text messages. Consolidating this | 36 | We also have lots of hardwired english text messages. Consolidating this |
37 | into some kind of message table not only makes translation easier, but | 37 | into some kind of message table not only makes translation easier, but |
@@ -59,6 +59,7 @@ Rob Landley suggested this: | |||
59 | Turning libbb into a real dll is another possibility, especially if libbb | 59 | Turning libbb into a real dll is another possibility, especially if libbb |
60 | could export some of the other library interfaces we've already more or less | 60 | could export some of the other library interfaces we've already more or less |
61 | got the code for (like zlib). | 61 | got the code for (like zlib). |
62 | |||
62 | buildroot - Make a "dogfood" option | 63 | buildroot - Make a "dogfood" option |
63 | Busybox 1.1 will be capable of replacing most gnu packages for real world | 64 | Busybox 1.1 will be capable of replacing most gnu packages for real world |
64 | use, such as developing software or in a live CD. It needs wider testing. | 65 | use, such as developing software or in a live CD. It needs wider testing. |
@@ -78,22 +79,25 @@ Rob Landley suggested this: | |||
78 | 79 | ||
79 | One example of an existing system that does this already is Firmware Linux: | 80 | One example of an existing system that does this already is Firmware Linux: |
80 | http://www.landley.net/code/firmware | 81 | http://www.landley.net/code/firmware |
82 | |||
81 | initramfs | 83 | initramfs |
82 | Busybox should have a sample initramfs build script. This depends on | 84 | Busybox should have a sample initramfs build script. This depends on |
83 | bbsh, mdev, and switch_root. | 85 | bbsh, mdev, and switch_root. |
86 | |||
84 | mkdep | 87 | mkdep |
85 | Write a mkdep that doesn't segfault if there's a directory it doesn't | 88 | Write a mkdep that doesn't segfault if there's a directory it doesn't |
86 | have permission to read, isn't based on manually editing the output of | 89 | have permission to read, isn't based on manually editing the output of |
87 | lexx and yacc, doesn't make such a mess under include/config, etc. | 90 | lexx and yacc, doesn't make such a mess under include/config, etc. |
91 | |||
88 | Group globals into unions of structures. | 92 | Group globals into unions of structures. |
89 | Go through and turn all the global and static variables into structures, | 93 | Go through and turn all the global and static variables into structures, |
90 | and have all those structures be in a big union shared between processes, | 94 | and have all those structures be in a big union shared between processes, |
91 | so busybox uses less bss. (This is a big win on nommu machines.) See | 95 | so busybox uses less bss. (This is a big win on nommu machines.) See |
92 | sed.c and mdev.c for examples. | 96 | sed.c and mdev.c for examples. |
97 | |||
93 | Go through bugs.busybox.net and close out all of that somehow. | 98 | Go through bugs.busybox.net and close out all of that somehow. |
94 | This one's open to everybody, but I'll wind up doing it... | 99 | This one's open to everybody, but I'll wind up doing it... |
95 | 100 | ||
96 | |||
97 | Bernhard Reutner-Fischer <busybox@busybox.net> suggests to look at these: | 101 | Bernhard Reutner-Fischer <busybox@busybox.net> suggests to look at these: |
98 | New debug options: | 102 | New debug options: |
99 | -Wlarger-than-127 | 103 | -Wlarger-than-127 |
@@ -177,40 +181,6 @@ Memory Allocation | |||
177 | call free might also be optimized out by the compiler if written right, so | 181 | call free might also be optimized out by the compiler if written right, so |
178 | we can yank those #ifdefs too, and generally clean up the code. | 182 | we can yank those #ifdefs too, and generally clean up the code. |
179 | --- | 183 | --- |
180 | Switch CONFIG_SYMBOLS to ENABLE_SYMBOLS | ||
181 | |||
182 | In busybox 1.0 and earlier, configuration was done by CONFIG_SYMBOLS | ||
183 | that were either defined or undefined to indicate whether the symbol was | ||
184 | selected in the .config file. They were used with #ifdefs, ala: | ||
185 | |||
186 | #ifdef CONFIG_SYMBOL | ||
187 | if (other_test) { | ||
188 | do_code(); | ||
189 | } | ||
190 | #endif | ||
191 | |||
192 | In 1.1, we have new ENABLE_SYMBOLS which are always defined (as 0 or 1), | ||
193 | meaning you can still use them for preprocessor tests by replacing | ||
194 | "#ifdef CONFIG_SYMBOL" with "#if ENABLE_SYMBOL". But more importantly, we | ||
195 | can use them as a true or false test in normal C code: | ||
196 | |||
197 | if (ENABLE_SYMBOL && other_test) { | ||
198 | do_code(); | ||
199 | } | ||
200 | |||
201 | (Optimizing away if() statements that resolve to a constant value | ||
202 | is known as "dead code elimination", an optimization so old and simple that | ||
203 | Turbo Pascal for DOS did it twenty years ago. Even modern mini-compilers | ||
204 | like the Tiny C Compiler (tcc) and the Small Device C Compiler (SDCC) | ||
205 | perform dead code elimination.) | ||
206 | |||
207 | Right now, busybox.h is #including both "config.h" (defining the | ||
208 | CONFIG_SYMBOLS) and "bb_config.h" (defining the ENABLE_SYMBOLS). At some | ||
209 | point in the future, it would be nice to wean ourselves off of the | ||
210 | CONFIG versions. (Among other things, some defective build environments | ||
211 | leak the Linux kernel's CONFIG_SYMBOLS into the system's standard #include | ||
212 | files. We've experienced collisions before.) | ||
213 | --- | ||
214 | FEATURE_CLEAN_UP | 184 | FEATURE_CLEAN_UP |
215 | This is more an unresolved issue than a to-do item. More thought is needed. | 185 | This is more an unresolved issue than a to-do item. More thought is needed. |
216 | 186 | ||
@@ -266,12 +236,7 @@ Minor stuff: | |||
266 | --- | 236 | --- |
267 | unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. | 237 | unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. |
268 | --- | 238 | --- |
269 | support start-stop-daemon -d <chdir-path> | 239 | support start-stop-daemon -d <chdir-path> |
270 | |||
271 | Code cleanup: | ||
272 | |||
273 | Replace deprecated functions. | ||
274 | |||
275 | --- | 240 | --- |
276 | vdprintf() -> similar sized functionality | 241 | vdprintf() -> similar sized functionality |
277 | --- | 242 | --- |
@@ -296,8 +261,6 @@ vdprintf() -> similar sized functionality | |||
296 | The first step would to generate a file/matrix what is already archived | 261 | The first step would to generate a file/matrix what is already archived |
297 | (also IPV6) | 262 | (also IPV6) |
298 | 263 | ||
299 | * ntpdate/ntpd (see ntpclient and openntp for examples) | ||
300 | |||
301 | * implement 'at' | 264 | * implement 'at' |
302 | 265 | ||
303 | * rpcbind (former portmap) or equivalent | 266 | * rpcbind (former portmap) or equivalent |
@@ -311,64 +274,3 @@ vdprintf() -> similar sized functionality | |||
311 | most likely there is more | 274 | most likely there is more |
312 | 275 | ||
313 | * even more support for statistics: mpstat, iostat, powertop.... | 276 | * even more support for statistics: mpstat, iostat, powertop.... |
314 | |||
315 | |||
316 | Unicode work needed: | ||
317 | |||
318 | Unicode support uses libc multibyte functions if LOCALE_SUPPORT is on | ||
319 | (in this case, the code will also support many more encodings), | ||
320 | or uses a limited subset of re-implemented multibyte functions | ||
321 | which only understand "one byte == one char" and unicode. | ||
322 | This is useful if you build against uclibc with locale support disabled. | ||
323 | |||
324 | Unicode-dependent applets must call check_unicode_in_env() when they | ||
325 | begin executing. | ||
326 | |||
327 | Applet code may conditionalize on UNICODE_SUPPORT in order to use | ||
328 | more efficient code if unicode support is not requested. | ||
329 | |||
330 | Available functions (if you need more, implement them in libbb/unicode.c | ||
331 | so that they work without LOCALE_SUPPORT too): | ||
332 | |||
333 | int bb_mbstrlen(str) - multibyte-aware strlen | ||
334 | size_t mbstowcs(wdest, src, n) | ||
335 | size_t wcstombs(dest, wsrc, n) | ||
336 | size_t wcrtomb(str, wc, wstate) | ||
337 | int iswspace(wc) | ||
338 | int iswalnum(wc) | ||
339 | int iswpunct(wc) | ||
340 | |||
341 | Applets which only need to align columns on screen correctly: | ||
342 | |||
343 | ls - already done, use source as an example | ||
344 | df | ||
345 | dumpleases | ||
346 | lsmod | ||
347 | |||
348 | Applets which need to account for Unicode chars | ||
349 | while processing the output: | ||
350 | |||
351 | [un]expand | ||
352 | fold | ||
353 | man | ||
354 | watch | ||
355 | cut (-b and -c are currently the same, needs fixing) | ||
356 | |||
357 | These applets need to ensure that unicode input | ||
358 | is handled correctly (say, <unicode><backspace> sequence): | ||
359 | |||
360 | getty, login | ||
361 | rm -i | ||
362 | unzip (overwrite prompt) | ||
363 | |||
364 | Viewers/editors are more difficult (many cases to get right). | ||
365 | libbb/lineedit.c is an example how to do it: | ||
366 | |||
367 | less, most, ed, vi | ||
368 | awk | ||
369 | [ef]grep | ||
370 | sed | ||
371 | |||
372 | Probably needs some specialized work: | ||
373 | |||
374 | loadkeys | ||
diff --git a/applets/Kbuild.src b/applets/Kbuild.src index e3bac9681..31fee8d1e 100644 --- a/applets/Kbuild.src +++ b/applets/Kbuild.src | |||
@@ -38,7 +38,7 @@ include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compress | |||
38 | $(call cmd,gen_usage_compressed) | 38 | $(call cmd,gen_usage_compressed) |
39 | 39 | ||
40 | quiet_cmd_gen_applet_tables = GEN include/applet_tables.h | 40 | quiet_cmd_gen_applet_tables = GEN include/applet_tables.h |
41 | cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h | 41 | cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h |
42 | 42 | ||
43 | include/applet_tables.h: applets/applet_tables | 43 | include/applet_tables.h: applets/applet_tables |
44 | $(call cmd,gen_applet_tables) | 44 | $(call cmd,gen_applet_tables) |
diff --git a/applets/applet_tables.c b/applets/applet_tables.c index e48be4682..338dc20f9 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c | |||
@@ -79,7 +79,7 @@ int main(int argc, char **argv) | |||
79 | } | 79 | } |
80 | printf("\n"); | 80 | printf("\n"); |
81 | 81 | ||
82 | printf("#ifndef SKIP_definitions\n"); | 82 | //printf("#ifndef SKIP_definitions\n"); |
83 | printf("const char applet_names[] ALIGN1 = \"\"\n"); | 83 | printf("const char applet_names[] ALIGN1 = \"\"\n"); |
84 | for (i = 0; i < NUM_APPLETS; i++) { | 84 | for (i = 0; i < NUM_APPLETS; i++) { |
85 | printf("\"%s\" \"\\0\"\n", applets[i].name); | 85 | printf("\"%s\" \"\\0\"\n", applets[i].name); |
@@ -123,9 +123,29 @@ int main(int argc, char **argv) | |||
123 | } | 123 | } |
124 | printf("};\n"); | 124 | printf("};\n"); |
125 | #endif | 125 | #endif |
126 | printf("#endif /* SKIP_definitions */\n"); | 126 | //printf("#endif /* SKIP_definitions */\n"); |
127 | printf("\n"); | 127 | printf("\n"); |
128 | printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); | 128 | printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); |
129 | 129 | ||
130 | if (argv[2]) { | ||
131 | char line_old[80]; | ||
132 | char line_new[80]; | ||
133 | FILE *fp; | ||
134 | |||
135 | line_old[0] = 0; | ||
136 | fp = fopen(argv[2], "r"); | ||
137 | if (fp) { | ||
138 | fgets(line_old, sizeof(line_old), fp); | ||
139 | fclose(fp); | ||
140 | } | ||
141 | sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS); | ||
142 | if (strcmp(line_old, line_new) != 0) { | ||
143 | fp = fopen(argv[2], "w"); | ||
144 | if (!fp) | ||
145 | return 1; | ||
146 | fputs(line_new, fp); | ||
147 | } | ||
148 | } | ||
149 | |||
130 | return 0; | 150 | return 0; |
131 | } | 151 | } |
diff --git a/applets/applets.c b/applets/applets.c index 133a21575..6a3996272 100644 --- a/applets/applets.c +++ b/applets/applets.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2, see file License in this tarball for details. | 7 | * Licensed under GPLv2, see file License in this tarball for details. |
8 | */ | 8 | */ |
9 | |||
10 | #include <assert.h> | ||
11 | #include "busybox.h" | 9 | #include "busybox.h" |
12 | 10 | ||
13 | #if ENABLE_BUILD_LIBBUSYBOX | 11 | #if ENABLE_BUILD_LIBBUSYBOX |
diff --git a/applets/usage_compressed b/applets/usage_compressed index bfd5aa873..e1fd0d94d 100755 --- a/applets/usage_compressed +++ b/applets/usage_compressed | |||
@@ -9,7 +9,7 @@ test -x "$loc/usage" || exit 1 | |||
9 | test "$SED" || SED=sed | 9 | test "$SED" || SED=sed |
10 | test "$DD" || DD=dd | 10 | test "$DD" || DD=dd |
11 | 11 | ||
12 | exec >"$target" | 12 | exec >"$target.$$" |
13 | 13 | ||
14 | echo '#define UNPACKED_USAGE "" \' | 14 | echo '#define UNPACKED_USAGE "" \' |
15 | "$loc/usage" | od -v -t x1 \ | 15 | "$loc/usage" | od -v -t x1 \ |
@@ -39,3 +39,5 @@ echo '#define PACKED_USAGE \' | |||
39 | -e 's/\(..\)/0x\1,/g' \ | 39 | -e 's/\(..\)/0x\1,/g' \ |
40 | -e 's/$/ \\/' | 40 | -e 's/$/ \\/' |
41 | echo '' | 41 | echo '' |
42 | |||
43 | mv -- "$target.$$" "$target" | ||
diff --git a/archival/Config.src b/archival/Config.src index 3dbd3aea1..f64b3347b 100644 --- a/archival/Config.src +++ b/archival/Config.src | |||
@@ -280,6 +280,15 @@ config FEATURE_TAR_LONG_OPTIONS | |||
280 | help | 280 | help |
281 | Enable use of long options, increases size by about 400 Bytes | 281 | Enable use of long options, increases size by about 400 Bytes |
282 | 282 | ||
283 | config FEATURE_TAR_TO_COMMAND | ||
284 | bool "Support for writing to an external program" | ||
285 | default y | ||
286 | depends on TAR && FEATURE_TAR_LONG_OPTIONS | ||
287 | help | ||
288 | If you enable this option you'll be able to instruct tar to send | ||
289 | the contents of each extracted file to the standard input of an | ||
290 | external program. | ||
291 | |||
283 | config FEATURE_TAR_UNAME_GNAME | 292 | config FEATURE_TAR_UNAME_GNAME |
284 | bool "Enable use of user and group names" | 293 | bool "Enable use of user and group names" |
285 | default y | 294 | default y |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index b243afb2e..c1259ac46 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -373,12 +373,21 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) | |||
373 | static | 373 | static |
374 | IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) | 374 | IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) |
375 | { | 375 | { |
376 | struct { | ||
377 | uint32_t v1; | ||
378 | uint16_t v2; | ||
379 | } magic; | ||
380 | xread(STDIN_FILENO, &magic, 6); | ||
381 | if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) { | ||
382 | bb_error_msg("invalid magic"); | ||
383 | return -1; | ||
384 | } | ||
376 | return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); | 385 | return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); |
377 | } | 386 | } |
378 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 387 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
379 | int unxz_main(int argc UNUSED_PARAM, char **argv) | 388 | int unxz_main(int argc UNUSED_PARAM, char **argv) |
380 | { | 389 | { |
381 | int opts = getopt32(argv, "cfvdt"); | 390 | IF_XZ(int opts =) getopt32(argv, "cfvdt"); |
382 | # if ENABLE_XZ | 391 | # if ENABLE_XZ |
383 | /* xz without -d or -t? */ | 392 | /* xz without -d or -t? */ |
384 | if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) | 393 | if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) |
diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src index 81854558b..a8549570e 100644 --- a/archival/libunarchive/Kbuild.src +++ b/archival/libunarchive/Kbuild.src | |||
@@ -38,6 +38,7 @@ INSERT | |||
38 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o | 38 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o |
39 | lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o | 39 | lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o |
40 | lib-$(CONFIG_UNLZMA) += decompress_unlzma.o | 40 | lib-$(CONFIG_UNLZMA) += decompress_unlzma.o |
41 | lib-$(CONFIG_UNXZ) += decompress_unxz.o | ||
41 | lib-$(CONFIG_CPIO) += get_header_cpio.o | 42 | lib-$(CONFIG_CPIO) += get_header_cpio.o |
42 | lib-$(CONFIG_DPKG) += $(DPKG_FILES) | 43 | lib-$(CONFIG_DPKG) += $(DPKG_FILES) |
43 | lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) | 44 | lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) |
@@ -53,6 +54,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2 | |||
53 | lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o | 54 | lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o |
54 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o | 55 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o |
55 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o | 56 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o |
57 | lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o | ||
56 | 58 | ||
57 | ifneq ($(lib-y),) | 59 | ifneq ($(lib-y),) |
58 | lib-y += $(COMMON_FILES) | 60 | lib-y += $(COMMON_FILES) |
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c index c4ffe7ef8..00e67d405 100644 --- a/archival/libunarchive/data_extract_all.c +++ b/archival/libunarchive/data_extract_all.c | |||
@@ -127,6 +127,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
127 | break; | 127 | break; |
128 | case S_IFLNK: | 128 | case S_IFLNK: |
129 | /* Symlink */ | 129 | /* Symlink */ |
130 | //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) | ||
130 | res = symlink(file_header->link_target, file_header->name); | 131 | res = symlink(file_header->link_target, file_header->name); |
131 | if ((res == -1) | 132 | if ((res == -1) |
132 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | 133 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c new file mode 100644 index 000000000..95f5bc864 --- /dev/null +++ b/archival/libunarchive/data_extract_to_command.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
4 | */ | ||
5 | |||
6 | #include "libbb.h" | ||
7 | #include "unarchive.h" | ||
8 | |||
9 | enum { | ||
10 | //TAR_FILETYPE, | ||
11 | TAR_MODE, | ||
12 | TAR_FILENAME, | ||
13 | TAR_REALNAME, | ||
14 | #if ENABLE_FEATURE_TAR_UNAME_GNAME | ||
15 | TAR_UNAME, | ||
16 | TAR_GNAME, | ||
17 | #endif | ||
18 | TAR_SIZE, | ||
19 | TAR_UID, | ||
20 | TAR_GID, | ||
21 | TAR_MAX, | ||
22 | }; | ||
23 | |||
24 | static const char *const tar_var[] = { | ||
25 | // "FILETYPE", | ||
26 | "MODE", | ||
27 | "FILENAME", | ||
28 | "REALNAME", | ||
29 | #if ENABLE_FEATURE_TAR_UNAME_GNAME | ||
30 | "UNAME", | ||
31 | "GNAME", | ||
32 | #endif | ||
33 | "SIZE", | ||
34 | "UID", | ||
35 | "GID", | ||
36 | }; | ||
37 | |||
38 | static void xputenv(char *str) | ||
39 | { | ||
40 | if (putenv(str)) | ||
41 | bb_error_msg_and_die(bb_msg_memory_exhausted); | ||
42 | } | ||
43 | |||
44 | static void str2env(char *env[], int idx, const char *str) | ||
45 | { | ||
46 | env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str); | ||
47 | xputenv(env[idx]); | ||
48 | } | ||
49 | |||
50 | static void dec2env(char *env[], int idx, unsigned long long val) | ||
51 | { | ||
52 | env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val); | ||
53 | xputenv(env[idx]); | ||
54 | } | ||
55 | |||
56 | static void oct2env(char *env[], int idx, unsigned long val) | ||
57 | { | ||
58 | env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val); | ||
59 | xputenv(env[idx]); | ||
60 | } | ||
61 | |||
62 | void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) | ||
63 | { | ||
64 | file_header_t *file_header = archive_handle->file_header; | ||
65 | |||
66 | #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ | ||
67 | char *sctx = archive_handle->tar__next_file_sctx; | ||
68 | if (!sctx) | ||
69 | sctx = archive_handle->tar__global_sctx; | ||
70 | if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ | ||
71 | setfscreatecon(sctx); | ||
72 | free(archive_handle->tar__next_file_sctx); | ||
73 | archive_handle->tar__next_file_sctx = NULL; | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | if ((file_header->mode & S_IFMT) == S_IFREG) { | ||
78 | pid_t pid; | ||
79 | int p[2], status; | ||
80 | char *tar_env[TAR_MAX]; | ||
81 | |||
82 | memset(tar_env, 0, sizeof(tar_env)); | ||
83 | |||
84 | xpipe(p); | ||
85 | pid = BB_MMU ? xfork() : xvfork(); | ||
86 | if (pid == 0) { | ||
87 | /* Child */ | ||
88 | /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ | ||
89 | oct2env(tar_env, TAR_MODE, file_header->mode); | ||
90 | str2env(tar_env, TAR_FILENAME, file_header->name); | ||
91 | str2env(tar_env, TAR_REALNAME, file_header->name); | ||
92 | #if ENABLE_FEATURE_TAR_UNAME_GNAME | ||
93 | str2env(tar_env, TAR_UNAME, file_header->tar__uname); | ||
94 | str2env(tar_env, TAR_GNAME, file_header->tar__gname); | ||
95 | #endif | ||
96 | dec2env(tar_env, TAR_SIZE, file_header->size); | ||
97 | dec2env(tar_env, TAR_UID, file_header->uid); | ||
98 | dec2env(tar_env, TAR_GID, file_header->gid); | ||
99 | close(p[1]); | ||
100 | xdup2(p[0], STDIN_FILENO); | ||
101 | signal(SIGPIPE, SIG_DFL); | ||
102 | execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", archive_handle->tar__to_command, NULL); | ||
103 | bb_perror_msg_and_die("can't execute '%s'", DEFAULT_SHELL); | ||
104 | } | ||
105 | close(p[0]); | ||
106 | /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) | ||
107 | * so that we don't die if child don't read all the input: */ | ||
108 | bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size); | ||
109 | close(p[1]); | ||
110 | |||
111 | if (safe_waitpid(pid, &status, 0) == -1) | ||
112 | bb_perror_msg_and_die("waitpid"); | ||
113 | if (WIFEXITED(status) && WEXITSTATUS(status)) | ||
114 | bb_error_msg_and_die("'%s' returned status %d", | ||
115 | archive_handle->tar__to_command, WEXITSTATUS(status)); | ||
116 | if (WIFSIGNALED(status)) | ||
117 | bb_error_msg_and_die("'%s' terminated on signal %d", | ||
118 | archive_handle->tar__to_command, WTERMSIG(status)); | ||
119 | |||
120 | if (!BB_MMU) { | ||
121 | int i; | ||
122 | for (i = 0; i < TAR_MAX; i++) { | ||
123 | if (tar_env[i]) | ||
124 | bb_unsetenv_and_free(tar_env[i]); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | #if 0 /* ENABLE_FEATURE_TAR_SELINUX */ | ||
130 | if (sctx) | ||
131 | /* reset the context after creating an entry */ | ||
132 | setfscreatecon(NULL); | ||
133 | #endif | ||
134 | } | ||
diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index cd8df086e..bdbd39ac2 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c | |||
@@ -692,9 +692,9 @@ unpack_bz2_stream(int src_fd, int dst_fd) | |||
692 | IF_DESKTOP(long long) int FAST_FUNC | 692 | IF_DESKTOP(long long) int FAST_FUNC |
693 | unpack_bz2_stream_prime(int src_fd, int dst_fd) | 693 | unpack_bz2_stream_prime(int src_fd, int dst_fd) |
694 | { | 694 | { |
695 | unsigned char magic[2]; | 695 | uint16_t magic2; |
696 | xread(src_fd, magic, 2); | 696 | xread(src_fd, &magic2, 2); |
697 | if (magic[0] != 'B' || magic[1] != 'Z') { | 697 | if (magic2 != BZIP2_MAGIC) { |
698 | bb_error_msg_and_die("invalid magic"); | 698 | bb_error_msg_and_die("invalid magic"); |
699 | } | 699 | } |
700 | return unpack_bz2_stream(src_fd, dst_fd); | 700 | return unpack_bz2_stream(src_fd, dst_fd); |
diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 1302e29fb..721acd907 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c | |||
@@ -12,10 +12,11 @@ | |||
12 | #include "libbb.h" | 12 | #include "libbb.h" |
13 | #include "unarchive.h" | 13 | #include "unarchive.h" |
14 | 14 | ||
15 | #define XZ_REALLOC_DICT_BUF(ptr, size) xrealloc(ptr, size) | ||
16 | #define XZ_FUNC FAST_FUNC | 15 | #define XZ_FUNC FAST_FUNC |
17 | #define XZ_EXTERN static | 16 | #define XZ_EXTERN static |
18 | 17 | ||
18 | #define XZ_DEC_DYNALLOC | ||
19 | |||
19 | /* Skip check (rather than fail) of unsupported hash functions */ | 20 | /* Skip check (rather than fail) of unsupported hash functions */ |
20 | #define XZ_DEC_ANY_CHECK 1 | 21 | #define XZ_DEC_ANY_CHECK 1 |
21 | 22 | ||
@@ -40,15 +41,9 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | |||
40 | #define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) | 41 | #define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) |
41 | #define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) | 42 | #define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) |
42 | 43 | ||
43 | #include "unxz/xz.h" | ||
44 | #include "unxz/xz_config.h" | ||
45 | |||
46 | #include "unxz/xz_dec_bcj.c" | 44 | #include "unxz/xz_dec_bcj.c" |
47 | #include "unxz/xz_dec_lzma2.c" | 45 | #include "unxz/xz_dec_lzma2.c" |
48 | #include "unxz/xz_dec_stream.c" | 46 | #include "unxz/xz_dec_stream.c" |
49 | #include "unxz/xz_lzma2.h" | ||
50 | #include "unxz/xz_private.h" | ||
51 | #include "unxz/xz_stream.h" | ||
52 | 47 | ||
53 | IF_DESKTOP(long long) int FAST_FUNC | 48 | IF_DESKTOP(long long) int FAST_FUNC |
54 | unpack_xz_stream(int src_fd, int dst_fd) | 49 | unpack_xz_stream(int src_fd, int dst_fd) |
@@ -57,55 +52,45 @@ unpack_xz_stream(int src_fd, int dst_fd) | |||
57 | struct xz_dec *state; | 52 | struct xz_dec *state; |
58 | unsigned char *membuf; | 53 | unsigned char *membuf; |
59 | IF_DESKTOP(long long) int total = 0; | 54 | IF_DESKTOP(long long) int total = 0; |
60 | enum { | ||
61 | IN_SIZE = 4 * 1024, | ||
62 | OUT_SIZE = 60 * 1024, | ||
63 | }; | ||
64 | 55 | ||
65 | if (!crc32_table) | 56 | if (!crc32_table) |
66 | crc32_table = crc32_filltable(NULL, /*endian:*/ 0); | 57 | crc32_table = crc32_filltable(NULL, /*endian:*/ 0); |
67 | 58 | ||
68 | membuf = xmalloc(IN_SIZE + OUT_SIZE); | ||
69 | memset(&iobuf, 0, sizeof(iobuf)); | 59 | memset(&iobuf, 0, sizeof(iobuf)); |
60 | /* Preload XZ file signature */ | ||
61 | membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); | ||
70 | iobuf.in = membuf; | 62 | iobuf.in = membuf; |
71 | iobuf.out = membuf + IN_SIZE; | 63 | iobuf.in_size = HEADER_MAGIC_SIZE; |
72 | iobuf.out_size = OUT_SIZE; | 64 | iobuf.out = membuf + BUFSIZ; |
65 | iobuf.out_size = BUFSIZ; | ||
73 | 66 | ||
74 | state = xz_dec_init(64*1024); /* initial dict of 64k */ | 67 | /* Limit memory usage to about 64 MiB. */ |
68 | state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); | ||
75 | 69 | ||
76 | while (1) { | 70 | while (1) { |
77 | enum xz_ret r; | 71 | enum xz_ret r; |
78 | int insz, rd, outpos; | ||
79 | 72 | ||
80 | iobuf.in_size -= iobuf.in_pos; | 73 | if (iobuf.in_pos == iobuf.in_size) { |
81 | insz = iobuf.in_size; | 74 | int rd = safe_read(src_fd, membuf, BUFSIZ); |
82 | if (insz) | ||
83 | memmove(membuf, membuf + iobuf.in_pos, insz); | ||
84 | iobuf.in_pos = 0; | ||
85 | rd = IN_SIZE - insz; | ||
86 | if (rd) { | ||
87 | rd = safe_read(src_fd, membuf + insz, rd); | ||
88 | if (rd < 0) { | 75 | if (rd < 0) { |
89 | bb_error_msg(bb_msg_read_error); | 76 | bb_error_msg(bb_msg_read_error); |
90 | total = -1; | 77 | total = -1; |
91 | break; | 78 | break; |
92 | } | 79 | } |
93 | iobuf.in_size = insz + rd; | 80 | iobuf.in_size = rd; |
81 | iobuf.in_pos = 0; | ||
94 | } | 82 | } |
95 | // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", | 83 | // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", |
96 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); | 84 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); |
97 | r = xz_dec_run(state, &iobuf); | 85 | r = xz_dec_run(state, &iobuf); |
98 | // bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", | 86 | // bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", |
99 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r); | 87 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r); |
100 | outpos = iobuf.out_pos; | 88 | if (iobuf.out_pos) { |
101 | if (outpos) { | 89 | xwrite(dst_fd, iobuf.out, iobuf.out_pos); |
102 | xwrite(dst_fd, iobuf.out, outpos); | 90 | IF_DESKTOP(total += iobuf.out_pos;) |
103 | IF_DESKTOP(total += outpos;) | 91 | iobuf.out_pos = 0; |
104 | } | 92 | } |
105 | if (r == XZ_STREAM_END | 93 | if (r == XZ_STREAM_END) { |
106 | /* this happens even with well-formed files: */ | ||
107 | || (r == XZ_BUF_ERROR && insz == 0 && outpos == 0) | ||
108 | ) { | ||
109 | break; | 94 | break; |
110 | } | 95 | } |
111 | if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { | 96 | if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { |
@@ -113,7 +98,6 @@ unpack_xz_stream(int src_fd, int dst_fd) | |||
113 | total = -1; | 98 | total = -1; |
114 | break; | 99 | break; |
115 | } | 100 | } |
116 | iobuf.out_pos = 0; | ||
117 | } | 101 | } |
118 | xz_dec_end(state); | 102 | xz_dec_end(state); |
119 | free(membuf); | 103 | free(membuf); |
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index fcddcb834..d5c92359c 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c | |||
@@ -118,34 +118,10 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns | |||
118 | } | 118 | } |
119 | #endif | 119 | #endif |
120 | 120 | ||
121 | void BUG_tar_header_size(void); | ||
122 | char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | 121 | char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) |
123 | { | 122 | { |
124 | file_header_t *file_header = archive_handle->file_header; | 123 | file_header_t *file_header = archive_handle->file_header; |
125 | struct { | 124 | struct tar_header_t tar; |
126 | /* ustar header, Posix 1003.1 */ | ||
127 | char name[100]; /* 0-99 */ | ||
128 | char mode[8]; /* 100-107 */ | ||
129 | char uid[8]; /* 108-115 */ | ||
130 | char gid[8]; /* 116-123 */ | ||
131 | char size[12]; /* 124-135 */ | ||
132 | char mtime[12]; /* 136-147 */ | ||
133 | char chksum[8]; /* 148-155 */ | ||
134 | char typeflag; /* 156-156 */ | ||
135 | char linkname[100]; /* 157-256 */ | ||
136 | /* POSIX: "ustar" NUL "00" */ | ||
137 | /* GNU tar: "ustar " NUL */ | ||
138 | /* Normally it's defined as magic[6] followed by | ||
139 | * version[2], but we put them together to simplify code | ||
140 | */ | ||
141 | char magic[8]; /* 257-264 */ | ||
142 | char uname[32]; /* 265-296 */ | ||
143 | char gname[32]; /* 297-328 */ | ||
144 | char devmajor[8]; /* 329-336 */ | ||
145 | char devminor[8]; /* 337-344 */ | ||
146 | char prefix[155]; /* 345-499 */ | ||
147 | char padding[12]; /* 500-512 */ | ||
148 | } tar; | ||
149 | char *cp; | 125 | char *cp; |
150 | int i, sum_u, sum; | 126 | int i, sum_u, sum; |
151 | #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY | 127 | #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY |
@@ -162,9 +138,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
162 | # define p_linkname 0 | 138 | # define p_linkname 0 |
163 | #endif | 139 | #endif |
164 | 140 | ||
165 | if (sizeof(tar) != 512) | ||
166 | BUG_tar_header_size(); | ||
167 | |||
168 | #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX | 141 | #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX |
169 | again: | 142 | again: |
170 | #endif | 143 | #endif |
@@ -223,25 +196,31 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
223 | ) { | 196 | ) { |
224 | #if ENABLE_FEATURE_TAR_AUTODETECT | 197 | #if ENABLE_FEATURE_TAR_AUTODETECT |
225 | char FAST_FUNC (*get_header_ptr)(archive_handle_t *); | 198 | char FAST_FUNC (*get_header_ptr)(archive_handle_t *); |
199 | uint16_t magic2; | ||
226 | 200 | ||
227 | autodetect: | 201 | autodetect: |
202 | magic2 = *(uint16_t*)tar.name; | ||
228 | /* tar gz/bz autodetect: check for gz/bz2 magic. | 203 | /* tar gz/bz autodetect: check for gz/bz2 magic. |
229 | * If we see the magic, and it is the very first block, | 204 | * If we see the magic, and it is the very first block, |
230 | * we can switch to get_header_tar_gz/bz2/lzma(). | 205 | * we can switch to get_header_tar_gz/bz2/lzma(). |
231 | * Needs seekable fd. I wish recv(MSG_PEEK) works | 206 | * Needs seekable fd. I wish recv(MSG_PEEK) works |
232 | * on any fd... */ | 207 | * on any fd... */ |
233 | #if ENABLE_FEATURE_SEAMLESS_GZ | 208 | # if ENABLE_FEATURE_SEAMLESS_GZ |
234 | if (tar.name[0] == 0x1f && tar.name[1] == (char)0x8b) { /* gzip */ | 209 | if (magic2 == GZIP_MAGIC) { |
235 | get_header_ptr = get_header_tar_gz; | 210 | get_header_ptr = get_header_tar_gz; |
236 | } else | 211 | } else |
237 | #endif | 212 | # endif |
238 | #if ENABLE_FEATURE_SEAMLESS_BZ2 | 213 | # if ENABLE_FEATURE_SEAMLESS_BZ2 |
239 | if (tar.name[0] == 'B' && tar.name[1] == 'Z' | 214 | if (magic2 == BZIP2_MAGIC |
240 | && tar.name[2] == 'h' && isdigit(tar.name[3]) | 215 | && tar.name[2] == 'h' && isdigit(tar.name[3]) |
241 | ) { /* bzip2 */ | 216 | ) { /* bzip2 */ |
242 | get_header_ptr = get_header_tar_bz2; | 217 | get_header_ptr = get_header_tar_bz2; |
243 | } else | 218 | } else |
244 | #endif | 219 | # endif |
220 | # if ENABLE_FEATURE_SEAMLESS_XZ | ||
221 | //TODO: if (magic2 == XZ_MAGIC1)... | ||
222 | //else | ||
223 | # endif | ||
245 | goto err; | 224 | goto err; |
246 | /* Two different causes for lseek() != 0: | 225 | /* Two different causes for lseek() != 0: |
247 | * unseekable fd (would like to support that too, but...), | 226 | * unseekable fd (would like to support that too, but...), |
@@ -460,9 +439,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
460 | /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ | 439 | /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ |
461 | if (cp) | 440 | if (cp) |
462 | *cp = '\0'; | 441 | *cp = '\0'; |
463 | //archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET; // why?? | ||
464 | archive_handle->action_data(archive_handle); | 442 | archive_handle->action_data(archive_handle); |
465 | llist_add_to(&(archive_handle->passed), file_header->name); | 443 | if (archive_handle->accept || archive_handle->reject) |
444 | llist_add_to(&archive_handle->passed, file_header->name); | ||
445 | else /* Caller isn't interested in list of unpacked files */ | ||
446 | free(file_header->name); | ||
466 | } else { | 447 | } else { |
467 | data_skip(archive_handle); | 448 | data_skip(archive_handle); |
468 | free(file_header->name); | 449 | free(file_header->name); |
@@ -470,7 +451,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
470 | archive_handle->offset += file_header->size; | 451 | archive_handle->offset += file_header->size; |
471 | 452 | ||
472 | free(file_header->link_target); | 453 | free(file_header->link_target); |
473 | /* Do not free(file_header->name)! (why?) */ | 454 | /* Do not free(file_header->name)! |
455 | * It might be inserted in archive_handle->passed - see above */ | ||
474 | #if ENABLE_FEATURE_TAR_UNAME_GNAME | 456 | #if ENABLE_FEATURE_TAR_UNAME_GNAME |
475 | free(file_header->tar__uname); | 457 | free(file_header->tar__uname); |
476 | free(file_header->tar__gname); | 458 | free(file_header->tar__gname); |
diff --git a/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c index 47c13e6f4..cba049f1f 100644 --- a/archival/libunarchive/open_transformer.c +++ b/archival/libunarchive/open_transformer.c | |||
@@ -19,19 +19,9 @@ void FAST_FUNC open_transformer(int fd, | |||
19 | int pid; | 19 | int pid; |
20 | 20 | ||
21 | xpiped_pair(fd_pipe); | 21 | xpiped_pair(fd_pipe); |
22 | 22 | pid = BB_MMU ? xfork() : xvfork(); | |
23 | #if BB_MMU | ||
24 | pid = fork(); | ||
25 | if (pid == -1) | ||
26 | bb_perror_msg_and_die("vfork" + 1); | ||
27 | #else | ||
28 | pid = vfork(); | ||
29 | if (pid == -1) | ||
30 | bb_perror_msg_and_die("vfork"); | ||
31 | #endif | ||
32 | |||
33 | if (pid == 0) { | 23 | if (pid == 0) { |
34 | /* child process */ | 24 | /* Child */ |
35 | close(fd_pipe.rd); /* we don't want to read from the parent */ | 25 | close(fd_pipe.rd); /* we don't want to read from the parent */ |
36 | // FIXME: error check? | 26 | // FIXME: error check? |
37 | #if BB_MMU | 27 | #if BB_MMU |
diff --git a/archival/libunarchive/unxz/xz.h b/archival/libunarchive/unxz/xz.h index eb82706b9..c6c071c4a 100644 --- a/archival/libunarchive/unxz/xz.h +++ b/archival/libunarchive/unxz/xz.h | |||
@@ -30,9 +30,42 @@ | |||
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * enum xz_mode - Operation mode | ||
34 | * | ||
35 | * @XZ_SINGLE: Single-call mode. This uses less RAM than | ||
36 | * than multi-call modes, because the LZMA2 | ||
37 | * dictionary doesn't need to be allocated as | ||
38 | * part of the decoder state. All required data | ||
39 | * structures are allocated at initialization, | ||
40 | * so xz_dec_run() cannot return XZ_MEM_ERROR. | ||
41 | * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 | ||
42 | * dictionary buffer. All data structures are | ||
43 | * allocated at initialization, so xz_dec_run() | ||
44 | * cannot return XZ_MEM_ERROR. | ||
45 | * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is | ||
46 | * allocated once the required size has been | ||
47 | * parsed from the stream headers. If the | ||
48 | * allocation fails, xz_dec_run() will return | ||
49 | * XZ_MEM_ERROR. | ||
50 | * | ||
51 | * It is possible to enable support only for a subset of the above | ||
52 | * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, | ||
53 | * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled | ||
54 | * with support for all operation modes, but the preboot code may | ||
55 | * be built with fewer features to minimize code size. | ||
56 | */ | ||
57 | enum xz_mode { | ||
58 | XZ_SINGLE, | ||
59 | XZ_PREALLOC, | ||
60 | XZ_DYNALLOC | ||
61 | }; | ||
62 | |||
63 | /** | ||
33 | * enum xz_ret - Return codes | 64 | * enum xz_ret - Return codes |
34 | * @XZ_OK: Everything is OK so far. More input or more | 65 | * @XZ_OK: Everything is OK so far. More input or more |
35 | * output space is required to continue. | 66 | * output space is required to continue. This |
67 | * return code is possible only in multi-call mode | ||
68 | * (XZ_PREALLOC or XZ_DYNALLOC). | ||
36 | * @XZ_STREAM_END: Operation finished successfully. | 69 | * @XZ_STREAM_END: Operation finished successfully. |
37 | * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding | 70 | * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding |
38 | * is still possible in multi-call mode by simply | 71 | * is still possible in multi-call mode by simply |
@@ -42,8 +75,17 @@ | |||
42 | * which is not used in the kernel. Unsupported | 75 | * which is not used in the kernel. Unsupported |
43 | * check types return XZ_OPTIONS_ERROR if | 76 | * check types return XZ_OPTIONS_ERROR if |
44 | * XZ_DEC_ANY_CHECK was not defined at build time. | 77 | * XZ_DEC_ANY_CHECK was not defined at build time. |
45 | * @XZ_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder | 78 | * @XZ_MEM_ERROR: Allocating memory failed. This return code is |
46 | * initialization time. | 79 | * possible only if the decoder was initialized |
80 | * with XZ_DYNALLOC. The amount of memory that was | ||
81 | * tried to be allocated was no more than the | ||
82 | * dict_max argument given to xz_dec_init(). | ||
83 | * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than | ||
84 | * allowed by the dict_max argument given to | ||
85 | * xz_dec_init(). This return value is possible | ||
86 | * only in multi-call mode (XZ_PREALLOC or | ||
87 | * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) | ||
88 | * ignores the dict_max argument. | ||
47 | * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic | 89 | * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic |
48 | * bytes). | 90 | * bytes). |
49 | * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested | 91 | * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested |
@@ -72,6 +114,7 @@ enum xz_ret { | |||
72 | XZ_OK, | 114 | XZ_OK, |
73 | XZ_STREAM_END, | 115 | XZ_STREAM_END, |
74 | XZ_UNSUPPORTED_CHECK, | 116 | XZ_UNSUPPORTED_CHECK, |
117 | XZ_MEM_ERROR, | ||
75 | XZ_MEMLIMIT_ERROR, | 118 | XZ_MEMLIMIT_ERROR, |
76 | XZ_FORMAT_ERROR, | 119 | XZ_FORMAT_ERROR, |
77 | XZ_OPTIONS_ERROR, | 120 | XZ_OPTIONS_ERROR, |
@@ -112,61 +155,67 @@ struct xz_dec; | |||
112 | 155 | ||
113 | /** | 156 | /** |
114 | * xz_dec_init() - Allocate and initialize a XZ decoder state | 157 | * xz_dec_init() - Allocate and initialize a XZ decoder state |
158 | * @mode: Operation mode | ||
115 | * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for | 159 | * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for |
116 | * multi-call decoding, or special value of zero to indicate | 160 | * multi-call decoding. This is ignored in single-call mode |
117 | * single-call decoding mode. | 161 | * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes |
118 | * | 162 | * or 2^n + 2^(n-1) bytes (the latter sizes are less common |
119 | * If dict_max > 0, the decoder is initialized to work in multi-call mode. | 163 | * in practice), so other values for dict_max don't make sense. |
120 | * dict_max number of bytes of memory is preallocated for the LZMA2 | 164 | * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, |
121 | * dictionary. This way there is no risk that xz_dec_run() could run out | 165 | * 512 KiB, and 1 MiB are probably the only reasonable values, |
122 | * of memory, since xz_dec_run() will never allocate any memory. Instead, | 166 | * except for kernel and initramfs images where a bigger |
123 | * if the preallocated dictionary is too small for decoding the given input | 167 | * dictionary can be fine and useful. |
124 | * stream, xz_dec_run() will return XZ_MEMLIMIT_ERROR. Thus, it is important | 168 | * |
125 | * to know what kind of data will be decoded to avoid allocating excessive | 169 | * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at |
126 | * amount of memory for the dictionary. | 170 | * once. The caller must provide enough output space or the decoding will |
127 | * | 171 | * fail. The output space is used as the dictionary buffer, which is why |
128 | * LZMA2 dictionary is always 2^n bytes or 2^n + 2^(n-1) bytes (the latter | 172 | * there is no need to allocate the dictionary as part of the decoder's |
129 | * sizes are less common in practice). In the kernel, dictionary sizes of | 173 | * internal state. |
130 | * 64 KiB, 128 KiB, 256 KiB, 512 KiB, and 1 MiB are probably the only | ||
131 | * reasonable values. | ||
132 | * | ||
133 | * If dict_max == 0, the decoder is initialized to work in single-call mode. | ||
134 | * In single-call mode, xz_dec_run() decodes the whole stream at once. The | ||
135 | * caller must provide enough output space or the decoding will fail. The | ||
136 | * output space is used as the dictionary buffer, which is why there is | ||
137 | * no need to allocate the dictionary as part of the decoder's internal | ||
138 | * state. | ||
139 | * | 174 | * |
140 | * Because the output buffer is used as the workspace, streams encoded using | 175 | * Because the output buffer is used as the workspace, streams encoded using |
141 | * a big dictionary are not a problem in single-call. It is enough that the | 176 | * a big dictionary are not a problem in single-call mode. It is enough that |
142 | * output buffer is big enough to hold the actual uncompressed data; it | 177 | * the output buffer is big enough to hold the actual uncompressed data; it |
143 | * can be smaller than the dictionary size stored in the stream headers. | 178 | * can be smaller than the dictionary size stored in the stream headers. |
144 | * | 179 | * |
180 | * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes | ||
181 | * of memory is preallocated for the LZMA2 dictionary. This way there is no | ||
182 | * risk that xz_dec_run() could run out of memory, since xz_dec_run() will | ||
183 | * never allocate any memory. Instead, if the preallocated dictionary is too | ||
184 | * small for decoding the given input stream, xz_dec_run() will return | ||
185 | * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be | ||
186 | * decoded to avoid allocating excessive amount of memory for the dictionary. | ||
187 | * | ||
188 | * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): | ||
189 | * dict_max specifies the maximum allowed dictionary size that xz_dec_run() | ||
190 | * may allocate once it has parsed the dictionary size from the stream | ||
191 | * headers. This way excessive allocations can be avoided while still | ||
192 | * limiting the maximum memory usage to a sane value to prevent running the | ||
193 | * system out of memory when decompressing streams from untrusted sources. | ||
194 | * | ||
145 | * On success, xz_dec_init() returns a pointer to struct xz_dec, which is | 195 | * On success, xz_dec_init() returns a pointer to struct xz_dec, which is |
146 | * ready to be used with xz_dec_run(). On error, xz_dec_init() returns NULL. | 196 | * ready to be used with xz_dec_run(). If memory allocation fails, |
197 | * xz_dec_init() returns NULL. | ||
147 | */ | 198 | */ |
148 | XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max); | 199 | XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( |
200 | enum xz_mode mode, uint32_t dict_max); | ||
149 | 201 | ||
150 | /** | 202 | /** |
151 | * xz_dec_run() - Run the XZ decoder | 203 | * xz_dec_run() - Run the XZ decoder |
152 | * @s: Decoder state allocated using xz_dec_init() | 204 | * @s: Decoder state allocated using xz_dec_init() |
153 | * @b: Input and output buffers | 205 | * @b: Input and output buffers |
154 | * | 206 | * |
155 | * In multi-call mode, this function may return any of the values listed in | 207 | * The possible return values depend on build options and operation mode. |
156 | * enum xz_ret. | 208 | * See enum xz_ret for details. |
157 | * | 209 | * |
158 | * In single-call mode, this function never returns XZ_OK. If an error occurs | 210 | * NOTE: If an error occurs in single-call mode (return value is not |
159 | * in single-call mode (return value is not XZ_STREAM_END), b->in_pos and | 211 | * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the |
160 | * b->out_pos are not modified, and the contents of the output buffer from | 212 | * contents of the output buffer from b->out[b->out_pos] onward are |
161 | * b->out[b->out_pos] onward are undefined. | 213 | * undefined. This is true even after XZ_BUF_ERROR, because with some filter |
162 | * | 214 | * chains, there may be a second pass over the output buffer, and this pass |
163 | * NOTE: In single-call mode, the contents of the output buffer are undefined | 215 | * cannot be properly done if the output buffer is truncated. Thus, you |
164 | * also after XZ_BUF_ERROR. This is because with some filter chains, there | 216 | * cannot give the single-call decoder a too small buffer and then expect to |
165 | * may be a second pass over the output buffer, and this pass cannot be | 217 | * get that amount valid data from the beginning of the stream. You must use |
166 | * properly done if the output buffer is truncated. Thus, you cannot give | 218 | * the multi-call decoder if you don't want to uncompress the whole stream. |
167 | * the single-call decoder a too small buffer and then expect to get that | ||
168 | * amount valid data from the beginning of the stream. You must use the | ||
169 | * multi-call decoder if you don't want to uncompress the whole stream. | ||
170 | */ | 219 | */ |
171 | XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); | 220 | XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); |
172 | 221 | ||
diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libunarchive/unxz/xz_config.h index ff90eff26..187e1cbed 100644 --- a/archival/libunarchive/unxz/xz_config.h +++ b/archival/libunarchive/unxz/xz_config.h | |||
@@ -32,6 +32,8 @@ | |||
32 | #define memeq(a, b, size) (memcmp(a, b, size) == 0) | 32 | #define memeq(a, b, size) (memcmp(a, b, size) == 0) |
33 | #define memzero(buf, size) memset(buf, 0, size) | 33 | #define memzero(buf, size) memset(buf, 0, size) |
34 | 34 | ||
35 | #undef min | ||
36 | #undef min_t | ||
35 | #define min(x, y) ((x) < (y) ? (x) : (y)) | 37 | #define min(x, y) ((x) < (y) ? (x) : (y)) |
36 | #define min_t(type, x, y) min(x, y) | 38 | #define min_t(type, x, y) min(x, y) |
37 | 39 | ||
diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libunarchive/unxz/xz_dec_lzma2.c index 37de6fc32..da71cb4d4 100644 --- a/archival/libunarchive/unxz/xz_dec_lzma2.c +++ b/archival/libunarchive/unxz/xz_dec_lzma2.c | |||
@@ -34,7 +34,8 @@ | |||
34 | * | 34 | * |
35 | * In multi-call mode, also these are true: | 35 | * In multi-call mode, also these are true: |
36 | * end == size | 36 | * end == size |
37 | * size <= allocated | 37 | * size <= size_max |
38 | * allocated <= size | ||
38 | * | 39 | * |
39 | * Most of these variables are size_t to support single-call mode, | 40 | * Most of these variables are size_t to support single-call mode, |
40 | * in which the dictionary variables address the actual output | 41 | * in which the dictionary variables address the actual output |
@@ -74,11 +75,20 @@ struct dictionary { | |||
74 | uint32_t size; | 75 | uint32_t size; |
75 | 76 | ||
76 | /* | 77 | /* |
77 | * Amount of memory allocated for the dictionary. A special | 78 | * Maximum allowed dictionary size in multi-call mode. |
78 | * value of zero indicates that we are in single-call mode, | 79 | * This is ignored in single-call mode. |
79 | * where the output buffer works as the dictionary. | 80 | */ |
81 | uint32_t size_max; | ||
82 | |||
83 | /* | ||
84 | * Amount of memory currently allocated for the dictionary. | ||
85 | * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, | ||
86 | * size_max is always the same as the allocated size.) | ||
80 | */ | 87 | */ |
81 | uint32_t allocated; | 88 | uint32_t allocated; |
89 | |||
90 | /* Operation mode */ | ||
91 | enum xz_mode mode; | ||
82 | }; | 92 | }; |
83 | 93 | ||
84 | /* Range decoder */ | 94 | /* Range decoder */ |
@@ -120,31 +130,31 @@ struct lzma_len_dec { | |||
120 | }; | 130 | }; |
121 | 131 | ||
122 | struct lzma_dec { | 132 | struct lzma_dec { |
123 | /* | ||
124 | * LZMA properties or related bit masks (number of literal | ||
125 | * context bits, a mask dervied from the number of literal | ||
126 | * position bits, and a mask dervied from the number | ||
127 | * position bits) | ||
128 | */ | ||
129 | uint32_t lc; | ||
130 | uint32_t literal_pos_mask; /* (1 << lp) - 1 */ | ||
131 | uint32_t pos_mask; /* (1 << pb) - 1 */ | ||
132 | |||
133 | /* Types of the most recently seen LZMA symbols */ | ||
134 | enum lzma_state state; | ||
135 | |||
136 | /* Distances of latest four matches */ | 133 | /* Distances of latest four matches */ |
137 | uint32_t rep0; | 134 | uint32_t rep0; |
138 | uint32_t rep1; | 135 | uint32_t rep1; |
139 | uint32_t rep2; | 136 | uint32_t rep2; |
140 | uint32_t rep3; | 137 | uint32_t rep3; |
141 | 138 | ||
139 | /* Types of the most recently seen LZMA symbols */ | ||
140 | enum lzma_state state; | ||
141 | |||
142 | /* | 142 | /* |
143 | * Length of a match. This is updated so that dict_repeat can | 143 | * Length of a match. This is updated so that dict_repeat can |
144 | * be called again to finish repeating the whole match. | 144 | * be called again to finish repeating the whole match. |
145 | */ | 145 | */ |
146 | uint32_t len; | 146 | uint32_t len; |
147 | 147 | ||
148 | /* | ||
149 | * LZMA properties or related bit masks (number of literal | ||
150 | * context bits, a mask dervied from the number of literal | ||
151 | * position bits, and a mask dervied from the number | ||
152 | * position bits) | ||
153 | */ | ||
154 | uint32_t lc; | ||
155 | uint32_t literal_pos_mask; /* (1 << lp) - 1 */ | ||
156 | uint32_t pos_mask; /* (1 << pb) - 1 */ | ||
157 | |||
148 | /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ | 158 | /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ |
149 | uint16_t is_match[STATES][POS_STATES_MAX]; | 159 | uint16_t is_match[STATES][POS_STATES_MAX]; |
150 | 160 | ||
@@ -201,49 +211,59 @@ struct lzma_dec { | |||
201 | uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; | 211 | uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; |
202 | }; | 212 | }; |
203 | 213 | ||
214 | struct lzma2_dec { | ||
215 | /* Position in xz_dec_lzma2_run(). */ | ||
216 | enum lzma2_seq { | ||
217 | SEQ_CONTROL, | ||
218 | SEQ_UNCOMPRESSED_1, | ||
219 | SEQ_UNCOMPRESSED_2, | ||
220 | SEQ_COMPRESSED_0, | ||
221 | SEQ_COMPRESSED_1, | ||
222 | SEQ_PROPERTIES, | ||
223 | SEQ_LZMA_PREPARE, | ||
224 | SEQ_LZMA_RUN, | ||
225 | SEQ_COPY | ||
226 | } sequence; | ||
227 | |||
228 | /* Next position after decoding the compressed size of the chunk. */ | ||
229 | enum lzma2_seq next_sequence; | ||
230 | |||
231 | /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ | ||
232 | uint32_t uncompressed; | ||
233 | |||
234 | /* | ||
235 | * Compressed size of LZMA chunk or compressed/uncompressed | ||
236 | * size of uncompressed chunk (64 KiB at maximum) | ||
237 | */ | ||
238 | uint32_t compressed; | ||
239 | |||
240 | /* | ||
241 | * True if dictionary reset is needed. This is false before | ||
242 | * the first chunk (LZMA or uncompressed). | ||
243 | */ | ||
244 | bool need_dict_reset; | ||
245 | |||
246 | /* | ||
247 | * True if new LZMA properties are needed. This is false | ||
248 | * before the first LZMA chunk. | ||
249 | */ | ||
250 | bool need_props; | ||
251 | }; | ||
252 | |||
204 | struct xz_dec_lzma2 { | 253 | struct xz_dec_lzma2 { |
205 | /* LZMA2 */ | 254 | /* |
206 | struct { | 255 | * The order below is important on x86 to reduce code size and |
207 | /* Position in xz_dec_lzma2_run(). */ | 256 | * it shouldn't hurt on other platforms. Everything up to and |
208 | enum lzma2_seq { | 257 | * including lzma.pos_mask are in the first 128 bytes on x86-32, |
209 | SEQ_CONTROL, | 258 | * which allows using smaller instructions to access those |
210 | SEQ_UNCOMPRESSED_1, | 259 | * variables. On x86-64, fewer variables fit into the first 128 |
211 | SEQ_UNCOMPRESSED_2, | 260 | * bytes, but this is still the best order without sacrificing |
212 | SEQ_COMPRESSED_0, | 261 | * the readability by splitting the structures. |
213 | SEQ_COMPRESSED_1, | 262 | */ |
214 | SEQ_PROPERTIES, | 263 | struct rc_dec rc; |
215 | SEQ_LZMA_PREPARE, | 264 | struct dictionary dict; |
216 | SEQ_LZMA_RUN, | 265 | struct lzma2_dec lzma2; |
217 | SEQ_COPY | 266 | struct lzma_dec lzma; |
218 | } sequence; | ||
219 | |||
220 | /* | ||
221 | * Next position after decoding the compressed size of | ||
222 | * the chunk. | ||
223 | */ | ||
224 | enum lzma2_seq next_sequence; | ||
225 | |||
226 | /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ | ||
227 | uint32_t uncompressed; | ||
228 | |||
229 | /* | ||
230 | * Compressed size of LZMA chunk or compressed/uncompressed | ||
231 | * size of uncompressed chunk (64 KiB at maximum) | ||
232 | */ | ||
233 | uint32_t compressed; | ||
234 | |||
235 | /* | ||
236 | * True if dictionary reset is needed. This is false before | ||
237 | * the first chunk (LZMA or uncompressed). | ||
238 | */ | ||
239 | bool need_dict_reset; | ||
240 | |||
241 | /* | ||
242 | * True if new LZMA properties are needed. This is false | ||
243 | * before the first LZMA chunk. | ||
244 | */ | ||
245 | bool need_props; | ||
246 | } lzma2; | ||
247 | 267 | ||
248 | /* | 268 | /* |
249 | * Temporary buffer which holds small number of input bytes between | 269 | * Temporary buffer which holds small number of input bytes between |
@@ -253,10 +273,6 @@ struct xz_dec_lzma2 { | |||
253 | uint32_t size; | 273 | uint32_t size; |
254 | uint8_t buf[3 * LZMA_IN_REQUIRED]; | 274 | uint8_t buf[3 * LZMA_IN_REQUIRED]; |
255 | } temp; | 275 | } temp; |
256 | |||
257 | struct dictionary dict; | ||
258 | struct rc_dec rc; | ||
259 | struct lzma_dec lzma; | ||
260 | }; | 276 | }; |
261 | 277 | ||
262 | /************** | 278 | /************** |
@@ -269,7 +285,7 @@ struct xz_dec_lzma2 { | |||
269 | */ | 285 | */ |
270 | static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) | 286 | static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) |
271 | { | 287 | { |
272 | if (dict->allocated == 0) { | 288 | if (DEC_IS_SINGLE(dict->mode)) { |
273 | dict->buf = b->out + b->out_pos; | 289 | dict->buf = b->out + b->out_pos; |
274 | dict->end = b->out_size - b->out_pos; | 290 | dict->end = b->out_size - b->out_pos; |
275 | } | 291 | } |
@@ -379,7 +395,7 @@ static void XZ_FUNC dict_uncompressed( | |||
379 | if (dict->full < dict->pos) | 395 | if (dict->full < dict->pos) |
380 | dict->full = dict->pos; | 396 | dict->full = dict->pos; |
381 | 397 | ||
382 | if (dict->allocated != 0) { | 398 | if (DEC_IS_MULTI(dict->mode)) { |
383 | if (dict->pos == dict->end) | 399 | if (dict->pos == dict->end) |
384 | dict->pos = 0; | 400 | dict->pos = 0; |
385 | 401 | ||
@@ -404,7 +420,7 @@ static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) | |||
404 | { | 420 | { |
405 | size_t copy_size = dict->pos - dict->start; | 421 | size_t copy_size = dict->pos - dict->start; |
406 | 422 | ||
407 | if (dict->allocated != 0) { | 423 | if (DEC_IS_MULTI(dict->mode)) { |
408 | if (dict->pos == dict->end) | 424 | if (dict->pos == dict->end) |
409 | dict->pos = 0; | 425 | dict->pos = 0; |
410 | 426 | ||
@@ -422,7 +438,7 @@ static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) | |||
422 | *****************/ | 438 | *****************/ |
423 | 439 | ||
424 | /* Reset the range decoder. */ | 440 | /* Reset the range decoder. */ |
425 | static __always_inline void XZ_FUNC rc_reset(struct rc_dec *rc) | 441 | static void XZ_FUNC rc_reset(struct rc_dec *rc) |
426 | { | 442 | { |
427 | rc->range = (uint32_t)-1; | 443 | rc->range = (uint32_t)-1; |
428 | rc->code = 0; | 444 | rc->code = 0; |
@@ -1088,28 +1104,27 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( | |||
1088 | return XZ_OK; | 1104 | return XZ_OK; |
1089 | } | 1105 | } |
1090 | 1106 | ||
1091 | XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(uint32_t dict_max) | 1107 | XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( |
1108 | enum xz_mode mode, uint32_t dict_max) | ||
1092 | { | 1109 | { |
1093 | struct xz_dec_lzma2 *s; | 1110 | struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); |
1094 | |||
1095 | /* Maximum supported dictionary by this implementation is 3 GiB. */ | ||
1096 | if (dict_max > ((uint32_t)3 << 30)) | ||
1097 | return NULL; | ||
1098 | |||
1099 | s = kmalloc(sizeof(*s), GFP_KERNEL); | ||
1100 | if (s == NULL) | 1111 | if (s == NULL) |
1101 | return NULL; | 1112 | return NULL; |
1102 | 1113 | ||
1103 | if (dict_max > 0) { | 1114 | s->dict.mode = mode; |
1115 | s->dict.size_max = dict_max; | ||
1116 | |||
1117 | if (DEC_IS_PREALLOC(mode)) { | ||
1104 | s->dict.buf = vmalloc(dict_max); | 1118 | s->dict.buf = vmalloc(dict_max); |
1105 | if (s->dict.buf == NULL) { | 1119 | if (s->dict.buf == NULL) { |
1106 | kfree(s); | 1120 | kfree(s); |
1107 | return NULL; | 1121 | return NULL; |
1108 | } | 1122 | } |
1123 | } else if (DEC_IS_DYNALLOC(mode)) { | ||
1124 | s->dict.buf = NULL; | ||
1125 | s->dict.allocated = 0; | ||
1109 | } | 1126 | } |
1110 | 1127 | ||
1111 | s->dict.allocated = dict_max; | ||
1112 | |||
1113 | return s; | 1128 | return s; |
1114 | } | 1129 | } |
1115 | 1130 | ||
@@ -1123,18 +1138,23 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( | |||
1123 | s->dict.size = 2 + (props & 1); | 1138 | s->dict.size = 2 + (props & 1); |
1124 | s->dict.size <<= (props >> 1) + 11; | 1139 | s->dict.size <<= (props >> 1) + 11; |
1125 | 1140 | ||
1126 | if (s->dict.allocated > 0 && s->dict.allocated < s->dict.size) { | 1141 | if (DEC_IS_MULTI(s->dict.mode)) { |
1127 | #ifdef XZ_REALLOC_DICT_BUF | 1142 | if (s->dict.size > s->dict.size_max) |
1128 | s->dict.buf = XZ_REALLOC_DICT_BUF(s->dict.buf, s->dict.size); | 1143 | return XZ_MEMLIMIT_ERROR; |
1129 | if (!s->dict.buf) | ||
1130 | return XZ_MEMLIMIT_ERROR; | ||
1131 | s->dict.allocated = s->dict.size; | ||
1132 | #else | ||
1133 | return XZ_MEMLIMIT_ERROR; | ||
1134 | #endif | ||
1135 | } | ||
1136 | 1144 | ||
1137 | s->dict.end = s->dict.size; | 1145 | s->dict.end = s->dict.size; |
1146 | |||
1147 | if (DEC_IS_DYNALLOC(s->dict.mode)) { | ||
1148 | if (s->dict.allocated < s->dict.size) { | ||
1149 | vfree(s->dict.buf); | ||
1150 | s->dict.buf = vmalloc(s->dict.size); | ||
1151 | if (s->dict.buf == NULL) { | ||
1152 | s->dict.allocated = 0; | ||
1153 | return XZ_MEM_ERROR; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | } | ||
1138 | 1158 | ||
1139 | s->lzma.len = 0; | 1159 | s->lzma.len = 0; |
1140 | 1160 | ||
@@ -1148,7 +1168,7 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( | |||
1148 | 1168 | ||
1149 | XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) | 1169 | XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) |
1150 | { | 1170 | { |
1151 | if (s->dict.allocated > 0) | 1171 | if (DEC_IS_MULTI(s->dict.mode)) |
1152 | vfree(s->dict.buf); | 1172 | vfree(s->dict.buf); |
1153 | 1173 | ||
1154 | kfree(s); | 1174 | kfree(s); |
diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c index 21db283fb..bdcbf1ba3 100644 --- a/archival/libunarchive/unxz/xz_dec_stream.c +++ b/archival/libunarchive/unxz/xz_dec_stream.c | |||
@@ -48,8 +48,8 @@ struct xz_dec { | |||
48 | /* Type of the integrity check calculated from uncompressed data */ | 48 | /* Type of the integrity check calculated from uncompressed data */ |
49 | enum xz_check check_type; | 49 | enum xz_check check_type; |
50 | 50 | ||
51 | /* True if we are operating in single-call mode. */ | 51 | /* Operation mode */ |
52 | bool single_call; | 52 | enum xz_mode mode; |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * True if the next call to xz_dec_run() is allowed to return | 55 | * True if the next call to xz_dec_run() is allowed to return |
@@ -737,14 +737,14 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) | |||
737 | size_t out_start; | 737 | size_t out_start; |
738 | enum xz_ret ret; | 738 | enum xz_ret ret; |
739 | 739 | ||
740 | if (s->single_call) | 740 | if (DEC_IS_SINGLE(s->mode)) |
741 | xz_dec_reset(s); | 741 | xz_dec_reset(s); |
742 | 742 | ||
743 | in_start = b->in_pos; | 743 | in_start = b->in_pos; |
744 | out_start = b->out_pos; | 744 | out_start = b->out_pos; |
745 | ret = dec_main(s, b); | 745 | ret = dec_main(s, b); |
746 | 746 | ||
747 | if (s->single_call) { | 747 | if (DEC_IS_SINGLE(s->mode)) { |
748 | if (ret == XZ_OK) | 748 | if (ret == XZ_OK) |
749 | ret = b->in_pos == b->in_size | 749 | ret = b->in_pos == b->in_size |
750 | ? XZ_DATA_ERROR : XZ_BUF_ERROR; | 750 | ? XZ_DATA_ERROR : XZ_BUF_ERROR; |
@@ -767,21 +767,22 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) | |||
767 | return ret; | 767 | return ret; |
768 | } | 768 | } |
769 | 769 | ||
770 | XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max) | 770 | XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( |
771 | enum xz_mode mode, uint32_t dict_max) | ||
771 | { | 772 | { |
772 | struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); | 773 | struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); |
773 | if (s == NULL) | 774 | if (s == NULL) |
774 | return NULL; | 775 | return NULL; |
775 | 776 | ||
776 | s->single_call = dict_max == 0; | 777 | s->mode = mode; |
777 | 778 | ||
778 | #ifdef XZ_DEC_BCJ | 779 | #ifdef XZ_DEC_BCJ |
779 | s->bcj = xz_dec_bcj_create(s->single_call); | 780 | s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); |
780 | if (s->bcj == NULL) | 781 | if (s->bcj == NULL) |
781 | goto error_bcj; | 782 | goto error_bcj; |
782 | #endif | 783 | #endif |
783 | 784 | ||
784 | s->lzma2 = xz_dec_lzma2_create(dict_max); | 785 | s->lzma2 = xz_dec_lzma2_create(mode, dict_max); |
785 | if (s->lzma2 == NULL) | 786 | if (s->lzma2 == NULL) |
786 | goto error_lzma2; | 787 | goto error_lzma2; |
787 | 788 | ||
diff --git a/archival/libunarchive/unxz/xz_private.h b/archival/libunarchive/unxz/xz_private.h index f4e0b4010..145649a83 100644 --- a/archival/libunarchive/unxz/xz_private.h +++ b/archival/libunarchive/unxz/xz_private.h | |||
@@ -53,6 +53,45 @@ | |||
53 | # include "xz_config.h" | 53 | # include "xz_config.h" |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | /* If no specific decoding mode is requested, enable support for all modes. */ | ||
57 | #if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ | ||
58 | && !defined(XZ_DEC_DYNALLOC) | ||
59 | # define XZ_DEC_SINGLE | ||
60 | # define XZ_DEC_PREALLOC | ||
61 | # define XZ_DEC_DYNALLOC | ||
62 | #endif | ||
63 | |||
64 | /* | ||
65 | * The DEC_IS_foo(mode) macros are used in "if" statements. If only some | ||
66 | * of the supported modes are enabled, these macros will evaluate to true or | ||
67 | * false at compile time and thus allow the compiler to omit unneeded code. | ||
68 | */ | ||
69 | #ifdef XZ_DEC_SINGLE | ||
70 | # define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) | ||
71 | #else | ||
72 | # define DEC_IS_SINGLE(mode) (false) | ||
73 | #endif | ||
74 | |||
75 | #ifdef XZ_DEC_PREALLOC | ||
76 | # define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) | ||
77 | #else | ||
78 | # define DEC_IS_PREALLOC(mode) (false) | ||
79 | #endif | ||
80 | |||
81 | #ifdef XZ_DEC_DYNALLOC | ||
82 | # define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) | ||
83 | #else | ||
84 | # define DEC_IS_DYNALLOC(mode) (false) | ||
85 | #endif | ||
86 | |||
87 | #if !defined(XZ_DEC_SINGLE) | ||
88 | # define DEC_IS_MULTI(mode) (true) | ||
89 | #elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) | ||
90 | # define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) | ||
91 | #else | ||
92 | # define DEC_IS_MULTI(mode) (false) | ||
93 | #endif | ||
94 | |||
56 | /* | 95 | /* |
57 | * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. | 96 | * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. |
58 | * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. | 97 | * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. |
@@ -71,7 +110,7 @@ | |||
71 | * before calling xz_dec_lzma2_run(). | 110 | * before calling xz_dec_lzma2_run(). |
72 | */ | 111 | */ |
73 | XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( | 112 | XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( |
74 | uint32_t dict_max); | 113 | enum xz_mode mode, uint32_t dict_max); |
75 | 114 | ||
76 | /* | 115 | /* |
77 | * Decode the LZMA2 properties (one byte) and reset the decoder. Return | 116 | * Decode the LZMA2 properties (one byte) and reset the decoder. Return |
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 1c67dcc6e..5bc50b88f 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c | |||
@@ -75,7 +75,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
75 | } magic; | 75 | } magic; |
76 | IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); | 76 | IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); |
77 | 77 | ||
78 | xread(rpm_fd, magic.b16, sizeof(magic.b16)); | 78 | xread(rpm_fd, magic.b16, sizeof(magic.b16[0])); |
79 | if (magic.b16[0] == GZIP_MAGIC) { | 79 | if (magic.b16[0] == GZIP_MAGIC) { |
80 | unpack = unpack_gz_stream; | 80 | unpack = unpack_gz_stream; |
81 | } else | 81 | } else |
@@ -87,13 +87,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
87 | if (ENABLE_FEATURE_SEAMLESS_XZ | 87 | if (ENABLE_FEATURE_SEAMLESS_XZ |
88 | && magic.b16[0] == XZ_MAGIC1 | 88 | && magic.b16[0] == XZ_MAGIC1 |
89 | ) { | 89 | ) { |
90 | /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ | 90 | xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); |
91 | /* More info at: http://tukaani.org/xz/xz-file-format.txt */ | ||
92 | xread(rpm_fd, magic.b32, sizeof(magic.b32)); | ||
93 | if (magic.b32[0] != XZ_MAGIC2) | 91 | if (magic.b32[0] != XZ_MAGIC2) |
94 | goto no_magic; | 92 | goto no_magic; |
95 | /* unpack_xz_stream wants fd at position 0 */ | 93 | /* unpack_xz_stream wants fd at position 6, no need to seek */ |
96 | xlseek(rpm_fd, -6, SEEK_CUR); | 94 | //xlseek(rpm_fd, -6, SEEK_CUR); |
97 | unpack = unpack_xz_stream; | 95 | unpack = unpack_xz_stream; |
98 | } else { | 96 | } else { |
99 | no_magic: | 97 | no_magic: |
diff --git a/archival/tar.c b/archival/tar.c index 3a940128b..5ddff7fa5 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -48,37 +48,6 @@ | |||
48 | 48 | ||
49 | #if ENABLE_FEATURE_TAR_CREATE | 49 | #if ENABLE_FEATURE_TAR_CREATE |
50 | 50 | ||
51 | /* Tar file constants */ | ||
52 | |||
53 | #define TAR_BLOCK_SIZE 512 | ||
54 | |||
55 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ | ||
56 | #define NAME_SIZE 100 | ||
57 | #define NAME_SIZE_STR "100" | ||
58 | typedef struct TarHeader { /* byte offset */ | ||
59 | char name[NAME_SIZE]; /* 0-99 */ | ||
60 | char mode[8]; /* 100-107 */ | ||
61 | char uid[8]; /* 108-115 */ | ||
62 | char gid[8]; /* 116-123 */ | ||
63 | char size[12]; /* 124-135 */ | ||
64 | char mtime[12]; /* 136-147 */ | ||
65 | char chksum[8]; /* 148-155 */ | ||
66 | char typeflag; /* 156-156 */ | ||
67 | char linkname[NAME_SIZE]; /* 157-256 */ | ||
68 | /* POSIX: "ustar" NUL "00" */ | ||
69 | /* GNU tar: "ustar " NUL */ | ||
70 | /* Normally it's defined as magic[6] followed by | ||
71 | * version[2], but we put them together to save code. | ||
72 | */ | ||
73 | char magic[8]; /* 257-264 */ | ||
74 | char uname[32]; /* 265-296 */ | ||
75 | char gname[32]; /* 297-328 */ | ||
76 | char devmajor[8]; /* 329-336 */ | ||
77 | char devminor[8]; /* 337-344 */ | ||
78 | char prefix[155]; /* 345-499 */ | ||
79 | char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ | ||
80 | } TarHeader; | ||
81 | |||
82 | /* | 51 | /* |
83 | ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are | 52 | ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are |
84 | ** the only functions that deal with the HardLinkInfo structure. | 53 | ** the only functions that deal with the HardLinkInfo structure. |
@@ -193,7 +162,7 @@ static void putOctal(char *cp, int len, off_t value) | |||
193 | } | 162 | } |
194 | #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b)) | 163 | #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b)) |
195 | 164 | ||
196 | static void chksum_and_xwrite(int fd, struct TarHeader* hp) | 165 | static void chksum_and_xwrite(int fd, struct tar_header_t* hp) |
197 | { | 166 | { |
198 | /* POSIX says that checksum is done on unsigned bytes | 167 | /* POSIX says that checksum is done on unsigned bytes |
199 | * (Sun and HP-UX gets it wrong... more details in | 168 | * (Sun and HP-UX gets it wrong... more details in |
@@ -235,7 +204,7 @@ static void writeLongname(int fd, int type, const char *name, int dir) | |||
235 | "00000000000", | 204 | "00000000000", |
236 | "00000000000", | 205 | "00000000000", |
237 | }; | 206 | }; |
238 | struct TarHeader header; | 207 | struct tar_header_t header; |
239 | int size; | 208 | int size; |
240 | 209 | ||
241 | dir = !!dir; /* normalize: 0/1 */ | 210 | dir = !!dir; /* normalize: 0/1 */ |
@@ -262,16 +231,12 @@ static void writeLongname(int fd, int type, const char *name, int dir) | |||
262 | #endif | 231 | #endif |
263 | 232 | ||
264 | /* Write out a tar header for the specified file/directory/whatever */ | 233 | /* Write out a tar header for the specified file/directory/whatever */ |
265 | void BUG_tar_header_size(void); | ||
266 | static int writeTarHeader(struct TarBallInfo *tbInfo, | 234 | static int writeTarHeader(struct TarBallInfo *tbInfo, |
267 | const char *header_name, const char *fileName, struct stat *statbuf) | 235 | const char *header_name, const char *fileName, struct stat *statbuf) |
268 | { | 236 | { |
269 | struct TarHeader header; | 237 | struct tar_header_t header; |
270 | 238 | ||
271 | if (sizeof(header) != 512) | 239 | memset(&header, 0, sizeof(header)); |
272 | BUG_tar_header_size(); | ||
273 | |||
274 | memset(&header, 0, sizeof(struct TarHeader)); | ||
275 | 240 | ||
276 | strncpy(header.name, header_name, sizeof(header.name)); | 241 | strncpy(header.name, header_name, sizeof(header.name)); |
277 | 242 | ||
@@ -549,9 +514,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) | |||
549 | (void) &zip_exec; | 514 | (void) &zip_exec; |
550 | # endif | 515 | # endif |
551 | 516 | ||
552 | gzipPid = vfork(); | 517 | gzipPid = xvfork(); |
553 | if (gzipPid < 0) | ||
554 | bb_perror_msg_and_die("vfork"); | ||
555 | 518 | ||
556 | if (gzipPid == 0) { | 519 | if (gzipPid == 0) { |
557 | /* child */ | 520 | /* child */ |
@@ -738,6 +701,68 @@ static void handle_SIGCHLD(int status) | |||
738 | } | 701 | } |
739 | #endif | 702 | #endif |
740 | 703 | ||
704 | //usage:#define tar_trivial_usage | ||
705 | //usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") | ||
706 | //usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") | ||
707 | //usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " | ||
708 | //usage: IF_FEATURE_TAR_FROM("[-X FILE] ") | ||
709 | //usage: "[-f TARFILE] [-C DIR] [FILE]..." | ||
710 | //usage:#define tar_full_usage "\n\n" | ||
711 | //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") | ||
712 | //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") | ||
713 | //usage: "or list files from a tar file\n" | ||
714 | //usage: "\nOperation:" | ||
715 | //usage: IF_FEATURE_TAR_CREATE( | ||
716 | //usage: "\n c Create" | ||
717 | //usage: ) | ||
718 | //usage: "\n x Extract" | ||
719 | //usage: "\n t List" | ||
720 | //usage: "\nOptions:" | ||
721 | //usage: "\n f Name of TARFILE ('-' for stdin/out)" | ||
722 | //usage: "\n C Change to DIR before operation" | ||
723 | //usage: "\n v Verbose" | ||
724 | //usage: IF_FEATURE_SEAMLESS_GZ( | ||
725 | //usage: "\n z (De)compress using gzip" | ||
726 | //usage: ) | ||
727 | //usage: IF_FEATURE_SEAMLESS_BZ2( | ||
728 | //usage: "\n j (De)compress using bzip2" | ||
729 | //usage: ) | ||
730 | //usage: IF_FEATURE_SEAMLESS_LZMA( | ||
731 | //usage: "\n a (De)compress using lzma" | ||
732 | //usage: ) | ||
733 | //usage: IF_FEATURE_SEAMLESS_Z( | ||
734 | //usage: "\n Z (De)compress using compress" | ||
735 | //usage: ) | ||
736 | //usage: "\n O Extract to stdout" | ||
737 | //usage: IF_FEATURE_TAR_CREATE( | ||
738 | //usage: "\n h Follow symlinks" | ||
739 | //usage: ) | ||
740 | //usage: IF_FEATURE_TAR_NOPRESERVE_TIME( | ||
741 | //usage: "\n m Don't restore mtime" | ||
742 | //usage: ) | ||
743 | //usage: IF_FEATURE_TAR_FROM( | ||
744 | //usage: IF_FEATURE_TAR_LONG_OPTIONS( | ||
745 | //usage: "\n exclude File to exclude" | ||
746 | //usage: ) | ||
747 | //usage: "\n X File with names to exclude" | ||
748 | //usage: "\n T File with names to include" | ||
749 | //usage: ) | ||
750 | //usage: | ||
751 | //usage:#define tar_example_usage | ||
752 | //usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" | ||
753 | //usage: "$ tar -cf /tmp/tarball.tar /usr/local\n" | ||
754 | |||
755 | // Supported but aren't in --help: | ||
756 | // o no-same-owner | ||
757 | // p same-permissions | ||
758 | // k keep-old | ||
759 | // numeric-owner | ||
760 | // no-same-permissions | ||
761 | // overwrite | ||
762 | //IF_FEATURE_TAR_TO_COMMAND( | ||
763 | // to-command | ||
764 | //) | ||
765 | |||
741 | enum { | 766 | enum { |
742 | OPTBIT_KEEP_OLD = 8, | 767 | OPTBIT_KEEP_OLD = 8, |
743 | IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) | 768 | IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) |
@@ -750,6 +775,7 @@ enum { | |||
750 | IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit | 775 | IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit |
751 | IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) | 776 | IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) |
752 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | 777 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS |
778 | IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) | ||
753 | OPTBIT_NUMERIC_OWNER, | 779 | OPTBIT_NUMERIC_OWNER, |
754 | OPTBIT_NOPRESERVE_PERM, | 780 | OPTBIT_NOPRESERVE_PERM, |
755 | OPTBIT_OVERWRITE, | 781 | OPTBIT_OVERWRITE, |
@@ -772,6 +798,7 @@ enum { | |||
772 | OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z | 798 | OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z |
773 | OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z | 799 | OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z |
774 | OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m | 800 | OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m |
801 | OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command | ||
775 | OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner | 802 | OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner |
776 | OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions | 803 | OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions |
777 | OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite | 804 | OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite |
@@ -813,6 +840,9 @@ static const char tar_longopts[] ALIGN1 = | |||
813 | # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME | 840 | # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME |
814 | "touch\0" No_argument "m" | 841 | "touch\0" No_argument "m" |
815 | # endif | 842 | # endif |
843 | # if ENABLE_FEATURE_TAR_TO_COMMAND | ||
844 | "to-command\0" Required_argument "\xfb" | ||
845 | # endif | ||
816 | /* use numeric uid/gid from tar header, not textual */ | 846 | /* use numeric uid/gid from tar header, not textual */ |
817 | "numeric-owner\0" No_argument "\xfc" | 847 | "numeric-owner\0" No_argument "\xfc" |
818 | /* do not restore mode */ | 848 | /* do not restore mode */ |
@@ -904,6 +934,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
904 | , &tar_filename // -f filename | 934 | , &tar_filename // -f filename |
905 | IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T | 935 | IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T |
906 | IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X | 936 | IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X |
937 | IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command | ||
907 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM | 938 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM |
908 | , &excludes // --exclude | 939 | , &excludes // --exclude |
909 | #endif | 940 | #endif |
@@ -922,6 +953,12 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
922 | if (opt & OPT_2STDOUT) | 953 | if (opt & OPT_2STDOUT) |
923 | tar_handle->action_data = data_extract_to_stdout; | 954 | tar_handle->action_data = data_extract_to_stdout; |
924 | 955 | ||
956 | if (opt & OPT_2COMMAND) { | ||
957 | putenv((char*)"TAR_FILETYPE=f"); | ||
958 | signal(SIGPIPE, SIG_IGN); | ||
959 | tar_handle->action_data = data_extract_to_command; | ||
960 | } | ||
961 | |||
925 | if (opt & OPT_KEEP_OLD) | 962 | if (opt & OPT_KEEP_OLD) |
926 | tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; | 963 | tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; |
927 | 964 | ||
diff --git a/archival/unzip_doc.txt.bz2 b/archival/unzip_doc.txt.bz2 deleted file mode 100644 index ab77d10da..000000000 --- a/archival/unzip_doc.txt.bz2 +++ /dev/null | |||
Binary files differ | |||
diff --git a/console-tools/openvt.c b/console-tools/openvt.c index 7bd6072a4..e3ea71bc5 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c | |||
@@ -97,8 +97,7 @@ static NOINLINE void vfork_child(char **argv) | |||
97 | //bb_error_msg("our pgrp %d", getpgrp()); | 97 | //bb_error_msg("our pgrp %d", getpgrp()); |
98 | //bb_error_msg("VT's sid %d", tcgetsid(0)); | 98 | //bb_error_msg("VT's sid %d", tcgetsid(0)); |
99 | //bb_error_msg("VT's pgrp %d", tcgetpgrp(0)); | 99 | //bb_error_msg("VT's pgrp %d", tcgetpgrp(0)); |
100 | BB_EXECVP(argv[0], argv); | 100 | BB_EXECVP_or_die(argv); |
101 | bb_perror_msg_and_die("exec %s", argv[0]); | ||
102 | } | 101 | } |
103 | } | 102 | } |
104 | 103 | ||
diff --git a/coreutils/chroot.c b/coreutils/chroot.c index f7228a61a..046c2fabf 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c | |||
@@ -30,6 +30,5 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) | |||
30 | argv[1] = (char *) "-i"; | 30 | argv[1] = (char *) "-i"; |
31 | } | 31 | } |
32 | 32 | ||
33 | BB_EXECVP(*argv, argv); | 33 | BB_EXECVP_or_die(argv); |
34 | bb_perror_msg_and_die("can't execute '%s'", *argv); | ||
35 | } | 34 | } |
diff --git a/coreutils/env.c b/coreutils/env.c index 9635d2b22..d4eab191b 100644 --- a/coreutils/env.c +++ b/coreutils/env.c | |||
@@ -76,11 +76,8 @@ int env_main(int argc UNUSED_PARAM, char **argv) | |||
76 | ++argv; | 76 | ++argv; |
77 | } | 77 | } |
78 | 78 | ||
79 | if (*argv) { | 79 | if (argv[0]) { |
80 | BB_EXECVP(*argv, argv); | 80 | BB_EXECVP_or_die(argv); |
81 | /* SUSv3-mandated exit codes. */ | ||
82 | xfunc_error_retval = (errno == ENOENT) ? 127 : 126; | ||
83 | bb_simple_perror_msg_and_die(*argv); | ||
84 | } | 81 | } |
85 | 82 | ||
86 | if (environ) { /* clearenv() may set environ == NULL! */ | 83 | if (environ) { /* clearenv() may set environ == NULL! */ |
diff --git a/coreutils/nice.c b/coreutils/nice.c index d24a95b45..ff3eb1140 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c | |||
@@ -47,9 +47,5 @@ int nice_main(int argc, char **argv) | |||
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
50 | BB_EXECVP(*argv, argv); /* Now exec the desired program. */ | 50 | BB_EXECVP_or_die(argv); |
51 | |||
52 | /* The exec failed... */ | ||
53 | xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */ | ||
54 | bb_simple_perror_msg_and_die(*argv); | ||
55 | } | 51 | } |
diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 4f6385f8e..3dc531409 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c | |||
@@ -75,6 +75,6 @@ int nohup_main(int argc UNUSED_PARAM, char **argv) | |||
75 | 75 | ||
76 | signal(SIGHUP, SIG_IGN); | 76 | signal(SIGHUP, SIG_IGN); |
77 | 77 | ||
78 | BB_EXECVP(argv[1], argv+1); | 78 | argv++; |
79 | bb_simple_perror_msg_and_die(argv[1]); | 79 | BB_EXECVP_or_die(argv); |
80 | } | 80 | } |
diff --git a/coreutils/realpath.c b/coreutils/realpath.c index 90a71ed7d..3bc40ee04 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c | |||
@@ -23,7 +23,7 @@ int realpath_main(int argc UNUSED_PARAM, char **argv) | |||
23 | 23 | ||
24 | do { | 24 | do { |
25 | char *resolved_path = xmalloc_realpath(*argv); | 25 | char *resolved_path = xmalloc_realpath(*argv); |
26 | if (resolved_path != NULL) { | 26 | if (resolved_path != NULL) { |
27 | puts(resolved_path); | 27 | puts(resolved_path); |
28 | free(resolved_path); | 28 | free(resolved_path); |
29 | } else { | 29 | } else { |
diff --git a/debianutils/mktemp.c b/debianutils/mktemp.c index c40211476..2c4e19670 100644 --- a/debianutils/mktemp.c +++ b/debianutils/mktemp.c | |||
@@ -50,7 +50,8 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv) | |||
50 | opts = getopt32(argv, "dqtp:", &path); | 50 | opts = getopt32(argv, "dqtp:", &path); |
51 | 51 | ||
52 | chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX"); | 52 | chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX"); |
53 | chp = concat_path_file(path, chp); | 53 | if (chp[0] != '/' || (opts & 8)) |
54 | chp = concat_path_file(path, chp); | ||
54 | 55 | ||
55 | if (opts & 1) { /* -d */ | 56 | if (opts & 1) { /* -d */ |
56 | if (mkdtemp(chp) == NULL) | 57 | if (mkdtemp(chp) == NULL) |
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 0a0802575..665f38fbd 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c | |||
@@ -409,9 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
409 | /* DAEMON_DEVNULL_STDIO is superfluous - | 409 | /* DAEMON_DEVNULL_STDIO is superfluous - |
410 | * it's always done by bb_daemonize() */ | 410 | * it's always done by bb_daemonize() */ |
411 | #else | 411 | #else |
412 | pid_t pid = vfork(); | 412 | pid_t pid = xvfork(); |
413 | if (pid < 0) /* error */ | ||
414 | bb_perror_msg_and_die("vfork"); | ||
415 | if (pid != 0) { | 413 | if (pid != 0) { |
416 | /* parent */ | 414 | /* parent */ |
417 | /* why _exit? the child may have changed the stack, | 415 | /* why _exit? the child may have changed the stack, |
@@ -448,5 +446,5 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
448 | } | 446 | } |
449 | #endif | 447 | #endif |
450 | execvp(startas, argv); | 448 | execvp(startas, argv); |
451 | bb_perror_msg_and_die("can't start %s", startas); | 449 | bb_perror_msg_and_die("can't execute '%s'", startas); |
452 | } | 450 | } |
diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c index dc029b65a..2a66d728a 100644 --- a/e2fsprogs/old_e2fsprogs/fsck.c +++ b/e2fsprogs/old_e2fsprogs/fsck.c | |||
@@ -612,7 +612,7 @@ static int execute(const char *type, const char *device, const char *mntpt, | |||
612 | if (noexecute) | 612 | if (noexecute) |
613 | pid = -1; | 613 | pid = -1; |
614 | else if ((pid = fork()) < 0) { | 614 | else if ((pid = fork()) < 0) { |
615 | perror("fork"); | 615 | perror("vfork"+1); |
616 | return errno; | 616 | return errno; |
617 | } else if (pid == 0) { | 617 | } else if (pid == 0) { |
618 | if (!interactive) | 618 | if (!interactive) |
diff --git a/editors/diff.c b/editors/diff.c index 07594e8d8..a3ca2b660 100644 --- a/editors/diff.c +++ b/editors/diff.c | |||
@@ -121,6 +121,7 @@ typedef struct FILE_and_pos_t { | |||
121 | struct globals { | 121 | struct globals { |
122 | smallint exit_status; | 122 | smallint exit_status; |
123 | int opt_U_context; | 123 | int opt_U_context; |
124 | const char *other_dir; | ||
124 | char *label[2]; | 125 | char *label[2]; |
125 | struct stat stb[2]; | 126 | struct stat stb[2]; |
126 | }; | 127 | }; |
@@ -760,9 +761,11 @@ static int FAST_FUNC add_to_dirlist(const char *filename, | |||
760 | void *userdata, int depth UNUSED_PARAM) | 761 | void *userdata, int depth UNUSED_PARAM) |
761 | { | 762 | { |
762 | struct dlist *const l = userdata; | 763 | struct dlist *const l = userdata; |
764 | const char *file = filename + l->len; | ||
765 | while (*file == '/') | ||
766 | file++; | ||
763 | l->dl = xrealloc_vector(l->dl, 6, l->e); | 767 | l->dl = xrealloc_vector(l->dl, 6, l->e); |
764 | /* + 1 skips "/" after dirname */ | 768 | l->dl[l->e] = xstrdup(file); |
765 | l->dl[l->e] = xstrdup(filename + l->len + 1); | ||
766 | l->e++; | 769 | l->e++; |
767 | return TRUE; | 770 | return TRUE; |
768 | } | 771 | } |
@@ -778,6 +781,25 @@ static int FAST_FUNC skip_dir(const char *filename, | |||
778 | add_to_dirlist(filename, sb, userdata, depth); | 781 | add_to_dirlist(filename, sb, userdata, depth); |
779 | return SKIP; | 782 | return SKIP; |
780 | } | 783 | } |
784 | if (!(option_mask32 & FLAG(N))) { | ||
785 | /* -r without -N: no need to recurse into dirs | ||
786 | * which do not exist on the "other side". | ||
787 | * Testcase: diff -r /tmp / | ||
788 | * (it would recurse deep into /proc without this code) */ | ||
789 | struct dlist *const l = userdata; | ||
790 | filename += l->len; | ||
791 | if (filename[0]) { | ||
792 | struct stat osb; | ||
793 | char *othername = concat_path_file(G.other_dir, filename); | ||
794 | int r = stat(othername, &osb); | ||
795 | free(othername); | ||
796 | if (r != 0 || !S_ISDIR(osb.st_mode)) { | ||
797 | /* other dir doesn't have similarly named | ||
798 | * directory, don't recurse */ | ||
799 | return SKIP; | ||
800 | } | ||
801 | } | ||
802 | } | ||
781 | return TRUE; | 803 | return TRUE; |
782 | } | 804 | } |
783 | 805 | ||
@@ -791,6 +813,7 @@ static void diffdir(char *p[2], const char *s_start) | |||
791 | /*list[i].s = list[i].e = 0; - memset did it */ | 813 | /*list[i].s = list[i].e = 0; - memset did it */ |
792 | /*list[i].dl = NULL; */ | 814 | /*list[i].dl = NULL; */ |
793 | 815 | ||
816 | G.other_dir = p[1 - i]; | ||
794 | /* We need to trim root directory prefix. | 817 | /* We need to trim root directory prefix. |
795 | * Using list.len to specify its length, | 818 | * Using list.len to specify its length, |
796 | * add_to_dirlist will remove it. */ | 819 | * add_to_dirlist will remove it. */ |
diff --git a/editors/sed.c b/editors/sed.c index 28f0c7318..7af8f867a 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -1333,7 +1333,6 @@ int sed_main(int argc UNUSED_PARAM, char **argv) | |||
1333 | if (opt & OPT_in_place) | 1333 | if (opt & OPT_in_place) |
1334 | bb_error_msg_and_die(bb_msg_requires_arg, "-i"); | 1334 | bb_error_msg_and_die(bb_msg_requires_arg, "-i"); |
1335 | add_input_file(stdin); | 1335 | add_input_file(stdin); |
1336 | process_files(); | ||
1337 | } else { | 1336 | } else { |
1338 | int i; | 1337 | int i; |
1339 | FILE *file; | 1338 | FILE *file; |
@@ -1379,9 +1378,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv) | |||
1379 | free(G.outname); | 1378 | free(G.outname); |
1380 | G.outname = NULL; | 1379 | G.outname = NULL; |
1381 | } | 1380 | } |
1382 | if (G.input_file_count > G.current_input_file) | 1381 | /* Here, to handle "sed 'cmds' nonexistent_file" case we did: |
1383 | process_files(); | 1382 | * if (G.current_input_file >= G.input_file_count) |
1383 | * return status; | ||
1384 | * but it's not needed since process_files() works correctly | ||
1385 | * in this case too. */ | ||
1384 | } | 1386 | } |
1387 | process_files(); | ||
1385 | 1388 | ||
1386 | return status; | 1389 | return status; |
1387 | } | 1390 | } |
diff --git a/editors/vi.c b/editors/vi.c index 9b050e115..0f412c362 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -2385,7 +2385,6 @@ static int file_write(char *fn, char *first, char *last) | |||
2385 | status_line_bold("No current filename"); | 2385 | status_line_bold("No current filename"); |
2386 | return -2; | 2386 | return -2; |
2387 | } | 2387 | } |
2388 | charcnt = 0; | ||
2389 | /* By popular request we do not open file with O_TRUNC, | 2388 | /* By popular request we do not open file with O_TRUNC, |
2390 | * but instead ftruncate() it _after_ successful write. | 2389 | * but instead ftruncate() it _after_ successful write. |
2391 | * Might reduce amount of data lost on power fail etc. | 2390 | * Might reduce amount of data lost on power fail etc. |
diff --git a/findutils/xargs.c b/findutils/xargs.c index 46a62cbf1..7b9f1fb73 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -59,14 +59,6 @@ | |||
59 | //config: are not special. | 59 | //config: are not special. |
60 | 60 | ||
61 | #include "libbb.h" | 61 | #include "libbb.h" |
62 | /* COMPAT: SYSV version defaults size (and has a max value of) to 470. | ||
63 | We try to make it as large as possible. */ | ||
64 | #if !defined(ARG_MAX) && defined(_SC_ARG_MAX) | ||
65 | # define ARG_MAX sysconf(_SC_ARG_MAX) | ||
66 | #endif | ||
67 | #if !defined(ARG_MAX) | ||
68 | # define ARG_MAX 470 | ||
69 | #endif | ||
70 | 62 | ||
71 | /* This is a NOEXEC applet. Be very careful! */ | 63 | /* This is a NOEXEC applet. Be very careful! */ |
72 | 64 | ||
@@ -440,35 +432,43 @@ int xargs_main(int argc, char **argv) | |||
440 | argc++; | 432 | argc++; |
441 | } | 433 | } |
442 | 434 | ||
443 | /* The Open Group Base Specifications Issue 6: | 435 | /* -s NUM default. fileutils-4.4.2 uses 128k, but I heasitate |
436 | * to use such a big value - first need to change code to use | ||
437 | * growable buffer instead of fixed one. | ||
438 | */ | ||
439 | n_max_chars = 32 * 1024; | ||
440 | /* Make smaller if system does not allow our default value. | ||
441 | * The Open Group Base Specifications Issue 6: | ||
444 | * "The xargs utility shall limit the command line length such that | 442 | * "The xargs utility shall limit the command line length such that |
445 | * when the command line is invoked, the combined argument | 443 | * when the command line is invoked, the combined argument |
446 | * and environment lists (see the exec family of functions | 444 | * and environment lists (see the exec family of functions |
447 | * in the System Interfaces volume of IEEE Std 1003.1-2001) | 445 | * in the System Interfaces volume of IEEE Std 1003.1-2001) |
448 | * shall not exceed {ARG_MAX}-2048 bytes". | 446 | * shall not exceed {ARG_MAX}-2048 bytes". |
449 | */ | 447 | */ |
450 | n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ | 448 | { |
451 | if (n_max_chars < 4*1024); /* paranoia */ | 449 | long arg_max = 0; |
452 | n_max_chars = 4*1024; | 450 | #if defined _SC_ARG_MAX |
453 | n_max_chars -= 2048; | 451 | arg_max = sysconf(_SC_ARG_MAX) - 2048; |
454 | /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which | 452 | #elif defined ARG_MAX |
455 | * have it at 1 meg). Things will work fine with a large ARG_MAX | 453 | arg_max = ARG_MAX - 2048; |
456 | * but it will probably hurt the system more than it needs to; | 454 | #endif |
457 | * an array of this size is allocated. | 455 | if (arg_max > 0 && n_max_chars > arg_max) |
458 | */ | 456 | n_max_chars = arg_max; |
459 | if (n_max_chars > 20 * 1024) | 457 | } |
460 | n_max_chars = 20 * 1024; | ||
461 | |||
462 | if (opt & OPT_UPTO_SIZE) { | 458 | if (opt & OPT_UPTO_SIZE) { |
463 | size_t n_chars = 0; | ||
464 | n_max_chars = xatou_range(max_chars, 1, INT_MAX); | 459 | n_max_chars = xatou_range(max_chars, 1, INT_MAX); |
460 | } | ||
461 | /* Account for prepended fixed arguments */ | ||
462 | { | ||
463 | size_t n_chars = 0; | ||
465 | for (i = 0; argv[i]; i++) { | 464 | for (i = 0; argv[i]; i++) { |
466 | n_chars += strlen(argv[i]) + 1; | 465 | n_chars += strlen(argv[i]) + 1; |
467 | } | 466 | } |
468 | n_max_chars -= n_chars; | 467 | n_max_chars -= n_chars; |
469 | if (n_max_chars <= 0) { | 468 | } |
470 | bb_error_msg_and_die("can't fit single argument within argument list size limit"); | 469 | /* Sanity check */ |
471 | } | 470 | if (n_max_chars <= 0) { |
471 | bb_error_msg_and_die("can't fit single argument within argument list size limit"); | ||
472 | } | 472 | } |
473 | 473 | ||
474 | buf = xzalloc(n_max_chars + 1); | 474 | buf = xzalloc(n_max_chars + 1); |
@@ -476,6 +476,8 @@ int xargs_main(int argc, char **argv) | |||
476 | n_max_arg = n_max_chars; | 476 | n_max_arg = n_max_chars; |
477 | if (opt & OPT_UPTO_NUMBER) { | 477 | if (opt & OPT_UPTO_NUMBER) { |
478 | n_max_arg = xatou_range(max_args, 1, INT_MAX); | 478 | n_max_arg = xatou_range(max_args, 1, INT_MAX); |
479 | /* Not necessary, we use growable args[]: */ | ||
480 | /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */ | ||
479 | } | 481 | } |
480 | 482 | ||
481 | /* Allocate pointers for execvp */ | 483 | /* Allocate pointers for execvp */ |
diff --git a/include/applets.src.h b/include/applets.src.h index 9162b66c7..5d84597b0 100644 --- a/include/applets.src.h +++ b/include/applets.src.h | |||
@@ -76,7 +76,6 @@ IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) | |||
76 | IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) | 76 | IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) |
77 | IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) | 77 | IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) |
78 | IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) | 78 | IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) |
79 | IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) | ||
80 | IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) | 79 | IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) |
81 | //IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) | 80 | //IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) |
82 | IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 81 | IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
@@ -183,7 +182,6 @@ IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdu | |||
183 | IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) | 182 | IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) |
184 | IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) | 183 | IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) |
185 | IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) | 184 | IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) |
186 | IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
187 | IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) | 185 | IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) |
188 | IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 186 | IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
189 | IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) | 187 | IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) |
@@ -218,7 +216,6 @@ IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_DROP)) | |||
218 | IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) | 216 | IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) |
219 | IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) | 217 | IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) |
220 | IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) | 218 | IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) |
221 | IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
222 | IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 219 | IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
223 | IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) | 220 | IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) |
224 | IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 221 | IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
@@ -273,7 +270,6 @@ IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) | |||
273 | IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) | 270 | IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) |
274 | IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) | 271 | IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) |
275 | IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) | 272 | IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) |
276 | IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
277 | IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) | 273 | IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) |
278 | IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) | 274 | IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) |
279 | IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) | 275 | IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) |
@@ -349,7 +345,6 @@ IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) | |||
349 | IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 345 | IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
350 | IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) | 346 | IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) |
351 | IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) | 347 | IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) |
352 | IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) | ||
353 | IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) | 348 | IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) |
354 | IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) | 349 | IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) |
355 | IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) | 350 | IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) |
diff --git a/include/busybox.h b/include/busybox.h index 48ce856ea..48fc0b4c8 100644 --- a/include/busybox.h +++ b/include/busybox.h | |||
@@ -35,18 +35,21 @@ extern const uint16_t applet_nameofs[]; | |||
35 | extern const uint8_t applet_install_loc[]; | 35 | extern const uint8_t applet_install_loc[]; |
36 | 36 | ||
37 | #if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS | 37 | #if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS |
38 | #define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) | 38 | # define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) |
39 | #else | 39 | #else |
40 | #define APPLET_NAME(i) (applet_names + applet_nameofs[i]) | 40 | # define APPLET_NAME(i) (applet_names + applet_nameofs[i]) |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | #if ENABLE_FEATURE_PREFER_APPLETS | 43 | #if ENABLE_FEATURE_PREFER_APPLETS |
44 | #define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) | 44 | # define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) |
45 | #define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) | 45 | # define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) |
46 | #else | ||
47 | # define APPLET_IS_NOFORK(i) 0 | ||
48 | # define APPLET_IS_NOEXEC(i) 0 | ||
46 | #endif | 49 | #endif |
47 | 50 | ||
48 | #if ENABLE_FEATURE_SUID | 51 | #if ENABLE_FEATURE_SUID |
49 | #define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) | 52 | # define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) |
50 | #endif | 53 | #endif |
51 | 54 | ||
52 | #if ENABLE_FEATURE_INSTALLER | 55 | #if ENABLE_FEATURE_INSTALLER |
diff --git a/include/libbb.h b/include/libbb.h index 0836b684e..26656de2e 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -419,6 +419,7 @@ void xchdir(const char *path) FAST_FUNC; | |||
419 | void xchroot(const char *path) FAST_FUNC; | 419 | void xchroot(const char *path) FAST_FUNC; |
420 | void xsetenv(const char *key, const char *value) FAST_FUNC; | 420 | void xsetenv(const char *key, const char *value) FAST_FUNC; |
421 | void bb_unsetenv(const char *key) FAST_FUNC; | 421 | void bb_unsetenv(const char *key) FAST_FUNC; |
422 | void bb_unsetenv_and_free(char *key) FAST_FUNC; | ||
422 | void xunlink(const char *pathname) FAST_FUNC; | 423 | void xunlink(const char *pathname) FAST_FUNC; |
423 | void xstat(const char *pathname, struct stat *buf) FAST_FUNC; | 424 | void xstat(const char *pathname, struct stat *buf) FAST_FUNC; |
424 | int xopen(const char *pathname, int flags) FAST_FUNC; | 425 | int xopen(const char *pathname, int flags) FAST_FUNC; |
@@ -854,6 +855,20 @@ int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; | |||
854 | #define BB_EXECVP(prog,cmd) execvp(prog,cmd) | 855 | #define BB_EXECVP(prog,cmd) execvp(prog,cmd) |
855 | #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) | 856 | #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) |
856 | #endif | 857 | #endif |
858 | int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; | ||
859 | |||
860 | /* xvfork() can't be a _function_, return after vfork mangles stack | ||
861 | * in the parent. It must be a macro. */ | ||
862 | #define xvfork() \ | ||
863 | ({ \ | ||
864 | pid_t bb__xvfork_pid = vfork(); \ | ||
865 | if (bb__xvfork_pid < 0) \ | ||
866 | bb_perror_msg_and_die("vfork"); \ | ||
867 | bb__xvfork_pid; \ | ||
868 | }) | ||
869 | #if BB_MMU | ||
870 | pid_t xfork(void) FAST_FUNC; | ||
871 | #endif | ||
857 | 872 | ||
858 | /* NOMMU friendy fork+exec: */ | 873 | /* NOMMU friendy fork+exec: */ |
859 | pid_t spawn(char **argv) FAST_FUNC; | 874 | pid_t spawn(char **argv) FAST_FUNC; |
@@ -900,7 +915,7 @@ int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char ** | |||
900 | * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty | 915 | * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty |
901 | * (will do setsid()). | 916 | * (will do setsid()). |
902 | * | 917 | * |
903 | * fork_or_rexec(argv) = bare-bones "fork" on MMU, | 918 | * fork_or_rexec(argv) = bare-bones fork on MMU, |
904 | * "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid(). | 919 | * "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid(). |
905 | * On MMU ignores argv. | 920 | * On MMU ignores argv. |
906 | * | 921 | * |
@@ -916,19 +931,19 @@ enum { | |||
916 | DAEMON_ONLY_SANITIZE = 8, /* internal use */ | 931 | DAEMON_ONLY_SANITIZE = 8, /* internal use */ |
917 | }; | 932 | }; |
918 | #if BB_MMU | 933 | #if BB_MMU |
919 | pid_t fork_or_rexec(void) FAST_FUNC; | ||
920 | enum { re_execed = 0 }; | 934 | enum { re_execed = 0 }; |
921 | # define fork_or_rexec(argv) fork_or_rexec() | 935 | # define fork_or_rexec(argv) xfork() |
922 | # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) | 936 | # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) |
923 | # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) | 937 | # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) |
924 | #else | 938 | #else |
939 | extern bool re_execed; | ||
925 | void re_exec(char **argv) NORETURN FAST_FUNC; | 940 | void re_exec(char **argv) NORETURN FAST_FUNC; |
926 | pid_t fork_or_rexec(char **argv) FAST_FUNC; | 941 | pid_t fork_or_rexec(char **argv) FAST_FUNC; |
927 | extern bool re_execed; | ||
928 | int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; | 942 | int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; |
929 | int BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC; | 943 | int BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC; |
930 | void BUG_bb_daemonize_is_unavailable_on_nommu(void) FAST_FUNC; | 944 | void BUG_bb_daemonize_is_unavailable_on_nommu(void) FAST_FUNC; |
931 | # define fork() BUG_fork_is_unavailable_on_nommu() | 945 | # define fork() BUG_fork_is_unavailable_on_nommu() |
946 | # define xfork() BUG_fork_is_unavailable_on_nommu() | ||
932 | # define daemon(a,b) BUG_daemon_is_unavailable_on_nommu() | 947 | # define daemon(a,b) BUG_daemon_is_unavailable_on_nommu() |
933 | # define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() | 948 | # define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() |
934 | #endif | 949 | #endif |
@@ -1141,6 +1156,7 @@ typedef struct parser_t { | |||
1141 | } parser_t; | 1156 | } parser_t; |
1142 | parser_t* config_open(const char *filename) FAST_FUNC; | 1157 | parser_t* config_open(const char *filename) FAST_FUNC; |
1143 | parser_t* config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) FAST_FUNC; | 1158 | parser_t* config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) FAST_FUNC; |
1159 | /* delims[0] is a comment char (use '\0' to disable), the rest are token delimiters */ | ||
1144 | int config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) FAST_FUNC; | 1160 | int config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) FAST_FUNC; |
1145 | #define config_read(parser, tokens, max, min, str, flags) \ | 1161 | #define config_read(parser, tokens, max, min, str, flags) \ |
1146 | config_read(parser, tokens, ((flags) | (((min) & 0xFF) << 8) | ((max) & 0xFF)), str) | 1162 | config_read(parser, tokens, ((flags) | (((min) & 0xFF) << 8) | ((max) & 0xFF)), str) |
@@ -1171,7 +1187,6 @@ char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; | |||
1171 | extern void bb_do_delay(int seconds) FAST_FUNC; | 1187 | extern void bb_do_delay(int seconds) FAST_FUNC; |
1172 | extern void change_identity(const struct passwd *pw) FAST_FUNC; | 1188 | extern void change_identity(const struct passwd *pw) FAST_FUNC; |
1173 | extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC; | 1189 | extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC; |
1174 | extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) FAST_FUNC; | ||
1175 | #if ENABLE_SELINUX | 1190 | #if ENABLE_SELINUX |
1176 | extern void renew_current_security_context(void) FAST_FUNC; | 1191 | extern void renew_current_security_context(void) FAST_FUNC; |
1177 | extern void set_current_security_context(security_context_t sid) FAST_FUNC; | 1192 | extern void set_current_security_context(security_context_t sid) FAST_FUNC; |
@@ -1611,12 +1626,12 @@ extern struct globals *const ptr_to_globals; | |||
1611 | * use bb_default_login_shell and following defines. | 1626 | * use bb_default_login_shell and following defines. |
1612 | * If you change LIBBB_DEFAULT_LOGIN_SHELL, | 1627 | * If you change LIBBB_DEFAULT_LOGIN_SHELL, |
1613 | * don't forget to change increment constant. */ | 1628 | * don't forget to change increment constant. */ |
1614 | #define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" | 1629 | #define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" |
1615 | extern const char bb_default_login_shell[]; | 1630 | extern const char bb_default_login_shell[]; |
1616 | /* "/bin/sh" */ | 1631 | /* "/bin/sh" */ |
1617 | #define DEFAULT_SHELL (bb_default_login_shell+1) | 1632 | #define DEFAULT_SHELL (bb_default_login_shell+1) |
1618 | /* "sh" */ | 1633 | /* "sh" */ |
1619 | #define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) | 1634 | #define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) |
1620 | 1635 | ||
1621 | #if ENABLE_FEATURE_DEVFS | 1636 | #if ENABLE_FEATURE_DEVFS |
1622 | # define CURRENT_VC "/dev/vc/0" | 1637 | # define CURRENT_VC "/dev/vc/0" |
@@ -1625,18 +1640,18 @@ extern const char bb_default_login_shell[]; | |||
1625 | # define VC_3 "/dev/vc/3" | 1640 | # define VC_3 "/dev/vc/3" |
1626 | # define VC_4 "/dev/vc/4" | 1641 | # define VC_4 "/dev/vc/4" |
1627 | # define VC_5 "/dev/vc/5" | 1642 | # define VC_5 "/dev/vc/5" |
1628 | #if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) | 1643 | # if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) |
1629 | /* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their | 1644 | /* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their |
1630 | respective serial ports .. as such, we can't use the common device paths for | 1645 | respective serial ports .. as such, we can't use the common device paths for |
1631 | these. -- PFM */ | 1646 | these. -- PFM */ |
1632 | # define SC_0 "/dev/ttsc/0" | 1647 | # define SC_0 "/dev/ttsc/0" |
1633 | # define SC_1 "/dev/ttsc/1" | 1648 | # define SC_1 "/dev/ttsc/1" |
1634 | # define SC_FORMAT "/dev/ttsc/%d" | 1649 | # define SC_FORMAT "/dev/ttsc/%d" |
1635 | #else | 1650 | # else |
1636 | # define SC_0 "/dev/tts/0" | 1651 | # define SC_0 "/dev/tts/0" |
1637 | # define SC_1 "/dev/tts/1" | 1652 | # define SC_1 "/dev/tts/1" |
1638 | # define SC_FORMAT "/dev/tts/%d" | 1653 | # define SC_FORMAT "/dev/tts/%d" |
1639 | #endif | 1654 | # endif |
1640 | # define VC_FORMAT "/dev/vc/%d" | 1655 | # define VC_FORMAT "/dev/vc/%d" |
1641 | # define LOOP_FORMAT "/dev/loop/%d" | 1656 | # define LOOP_FORMAT "/dev/loop/%d" |
1642 | # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) | 1657 | # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) |
@@ -1649,15 +1664,15 @@ extern const char bb_default_login_shell[]; | |||
1649 | # define VC_3 "/dev/tty3" | 1664 | # define VC_3 "/dev/tty3" |
1650 | # define VC_4 "/dev/tty4" | 1665 | # define VC_4 "/dev/tty4" |
1651 | # define VC_5 "/dev/tty5" | 1666 | # define VC_5 "/dev/tty5" |
1652 | #if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) | 1667 | # if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) |
1653 | # define SC_0 "/dev/ttySC0" | 1668 | # define SC_0 "/dev/ttySC0" |
1654 | # define SC_1 "/dev/ttySC1" | 1669 | # define SC_1 "/dev/ttySC1" |
1655 | # define SC_FORMAT "/dev/ttySC%d" | 1670 | # define SC_FORMAT "/dev/ttySC%d" |
1656 | #else | 1671 | # else |
1657 | # define SC_0 "/dev/ttyS0" | 1672 | # define SC_0 "/dev/ttyS0" |
1658 | # define SC_1 "/dev/ttyS1" | 1673 | # define SC_1 "/dev/ttyS1" |
1659 | # define SC_FORMAT "/dev/ttyS%d" | 1674 | # define SC_FORMAT "/dev/ttyS%d" |
1660 | #endif | 1675 | # endif |
1661 | # define VC_FORMAT "/dev/tty%d" | 1676 | # define VC_FORMAT "/dev/tty%d" |
1662 | # define LOOP_FORMAT "/dev/loop%d" | 1677 | # define LOOP_FORMAT "/dev/loop%d" |
1663 | # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) | 1678 | # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) |
diff --git a/include/platform.h b/include/platform.h index d1ac391eb..9458e2e02 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #define HAVE_SETBIT 1 | 26 | #define HAVE_SETBIT 1 |
27 | #define HAVE_STRCASESTR 1 | 27 | #define HAVE_STRCASESTR 1 |
28 | #define HAVE_STRCHRNUL 1 | 28 | #define HAVE_STRCHRNUL 1 |
29 | #define HAVE_STRSEP 1 | ||
29 | #define HAVE_STRSIGNAL 1 | 30 | #define HAVE_STRSIGNAL 1 |
30 | #define HAVE_VASPRINTF 1 | 31 | #define HAVE_VASPRINTF 1 |
31 | 32 | ||
@@ -185,10 +186,10 @@ | |||
185 | #if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ | 186 | #if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ |
186 | # define BB_BIG_ENDIAN 1 | 187 | # define BB_BIG_ENDIAN 1 |
187 | # define BB_LITTLE_ENDIAN 0 | 188 | # define BB_LITTLE_ENDIAN 0 |
188 | #elif __BYTE_ORDER == __BIG_ENDIAN | 189 | #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN |
189 | # define BB_BIG_ENDIAN 1 | 190 | # define BB_BIG_ENDIAN 1 |
190 | # define BB_LITTLE_ENDIAN 0 | 191 | # define BB_LITTLE_ENDIAN 0 |
191 | #elif __BYTE_ORDER == __LITTLE_ENDIAN | 192 | #elif (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || defined(__386__) |
192 | # define BB_BIG_ENDIAN 0 | 193 | # define BB_BIG_ENDIAN 0 |
193 | # define BB_LITTLE_ENDIAN 1 | 194 | # define BB_LITTLE_ENDIAN 1 |
194 | #else | 195 | #else |
@@ -381,6 +382,7 @@ typedef unsigned smalluint; | |||
381 | # undef HAVE_SETBIT | 382 | # undef HAVE_SETBIT |
382 | # undef HAVE_STRCASESTR | 383 | # undef HAVE_STRCASESTR |
383 | # undef HAVE_STRCHRNUL | 384 | # undef HAVE_STRCHRNUL |
385 | # undef HAVE_STRSEP | ||
384 | # undef HAVE_STRSIGNAL | 386 | # undef HAVE_STRSIGNAL |
385 | # undef HAVE_VASPRINTF | 387 | # undef HAVE_VASPRINTF |
386 | #endif | 388 | #endif |
@@ -419,6 +421,10 @@ extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC; | |||
419 | extern char *strchrnul(const char *s, int c) FAST_FUNC; | 421 | extern char *strchrnul(const char *s, int c) FAST_FUNC; |
420 | #endif | 422 | #endif |
421 | 423 | ||
424 | #ifndef HAVE_STRSEP | ||
425 | extern char *strsep(char **stringp, const char *delim) FAST_FUNC; | ||
426 | #endif | ||
427 | |||
422 | #ifndef HAVE_STRSIGNAL | 428 | #ifndef HAVE_STRSIGNAL |
423 | /* Not exactly the same: instead of "Stopped" it shows "STOP" etc */ | 429 | /* Not exactly the same: instead of "Stopped" it shows "STOP" etc */ |
424 | # define strsignal(sig) get_signame(sig) | 430 | # define strsignal(sig) get_signame(sig) |
diff --git a/include/unarchive.h b/include/unarchive.h index 8009de282..b55af6d9d 100644 --- a/include/unarchive.h +++ b/include/unarchive.h | |||
@@ -7,16 +7,23 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | |||
7 | enum { | 7 | enum { |
8 | #if BB_BIG_ENDIAN | 8 | #if BB_BIG_ENDIAN |
9 | COMPRESS_MAGIC = 0x1f9d, | 9 | COMPRESS_MAGIC = 0x1f9d, |
10 | GZIP_MAGIC = 0x1f8b, | 10 | GZIP_MAGIC = 0x1f8b, |
11 | BZIP2_MAGIC = ('B'<<8) + 'Z', | 11 | BZIP2_MAGIC = 'B' * 256 + 'Z', |
12 | XZ_MAGIC1 = (0xfd<<8) + '7', | 12 | /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ |
13 | XZ_MAGIC2 = ((((('z'<<8) + 'X')<<8) + 'Z')<<8) + 0, | 13 | /* More info at: http://tukaani.org/xz/xz-file-format.txt */ |
14 | XZ_MAGIC1 = 0xfd * 256 + '7', | ||
15 | XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, | ||
16 | /* Different form: 32 bits, then 16 bits: */ | ||
17 | XZ_MAGIC1a = ((0xfd * 256 + '7') * 256 + 'z') * 256 + 'X', | ||
18 | XZ_MAGIC2a = 'Z' * 256 + 0, | ||
14 | #else | 19 | #else |
15 | COMPRESS_MAGIC = 0x9d1f, | 20 | COMPRESS_MAGIC = 0x9d1f, |
16 | GZIP_MAGIC = 0x8b1f, | 21 | GZIP_MAGIC = 0x8b1f, |
17 | BZIP2_MAGIC = ('Z'<<8) + 'B', | 22 | BZIP2_MAGIC = 'Z' * 256 + 'B', |
18 | XZ_MAGIC1 = ('7'<<8) + 0xfd, | 23 | XZ_MAGIC1 = '7' * 256 + 0xfd, |
19 | XZ_MAGIC2 = (((((0<<8) + 'Z')<<8) + 'X')<<8) + 'z', | 24 | XZ_MAGIC2 = ((0 * 256 + 'Z') * 256 + 'X') * 256 + 'z', |
25 | XZ_MAGIC1a = (('X' * 256 + 'z') * 256 + '7') * 256 + 0xfd, | ||
26 | XZ_MAGIC2a = 0 * 256 + 'Z', | ||
20 | #endif | 27 | #endif |
21 | }; | 28 | }; |
22 | 29 | ||
@@ -75,6 +82,9 @@ typedef struct archive_handle_t { | |||
75 | char* tar__longname; | 82 | char* tar__longname; |
76 | char* tar__linkname; | 83 | char* tar__linkname; |
77 | # endif | 84 | # endif |
85 | #if ENABLE_FEATURE_TAR_TO_COMMAND | ||
86 | char* tar__to_command; | ||
87 | #endif | ||
78 | # if ENABLE_FEATURE_TAR_SELINUX | 88 | # if ENABLE_FEATURE_TAR_SELINUX |
79 | char* tar__global_sctx; | 89 | char* tar__global_sctx; |
80 | char* tar__next_file_sctx; | 90 | char* tar__next_file_sctx; |
@@ -110,6 +120,39 @@ typedef struct archive_handle_t { | |||
110 | #define ARCHIVE_O_TRUNC (1 << 8) | 120 | #define ARCHIVE_O_TRUNC (1 << 8) |
111 | 121 | ||
112 | 122 | ||
123 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ | ||
124 | #define TAR_BLOCK_SIZE 512 | ||
125 | #define NAME_SIZE 100 | ||
126 | #define NAME_SIZE_STR "100" | ||
127 | typedef struct tar_header_t { /* byte offset */ | ||
128 | char name[NAME_SIZE]; /* 0-99 */ | ||
129 | char mode[8]; /* 100-107 */ | ||
130 | char uid[8]; /* 108-115 */ | ||
131 | char gid[8]; /* 116-123 */ | ||
132 | char size[12]; /* 124-135 */ | ||
133 | char mtime[12]; /* 136-147 */ | ||
134 | char chksum[8]; /* 148-155 */ | ||
135 | char typeflag; /* 156-156 */ | ||
136 | char linkname[NAME_SIZE]; /* 157-256 */ | ||
137 | /* POSIX: "ustar" NUL "00" */ | ||
138 | /* GNU tar: "ustar " NUL */ | ||
139 | /* Normally it's defined as magic[6] followed by | ||
140 | * version[2], but we put them together to save code. | ||
141 | */ | ||
142 | char magic[8]; /* 257-264 */ | ||
143 | char uname[32]; /* 265-296 */ | ||
144 | char gname[32]; /* 297-328 */ | ||
145 | char devmajor[8]; /* 329-336 */ | ||
146 | char devminor[8]; /* 337-344 */ | ||
147 | char prefix[155]; /* 345-499 */ | ||
148 | char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ | ||
149 | } tar_header_t; | ||
150 | struct BUG_tar_header { | ||
151 | char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; | ||
152 | }; | ||
153 | |||
154 | |||
155 | |||
113 | /* Info struct unpackers can fill out to inform users of thing like | 156 | /* Info struct unpackers can fill out to inform users of thing like |
114 | * timestamps of unpacked files */ | 157 | * timestamps of unpacked files */ |
115 | typedef struct unpack_info_t { | 158 | typedef struct unpack_info_t { |
@@ -128,6 +171,7 @@ extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; | |||
128 | extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; | 171 | extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; |
129 | extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; | 172 | extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; |
130 | extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; | 173 | extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; |
174 | extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; | ||
131 | 175 | ||
132 | extern void header_skip(const file_header_t *file_header) FAST_FUNC; | 176 | extern void header_skip(const file_header_t *file_header) FAST_FUNC; |
133 | extern void header_list(const file_header_t *file_header) FAST_FUNC; | 177 | extern void header_list(const file_header_t *file_header) FAST_FUNC; |
@@ -159,7 +203,7 @@ typedef struct inflate_unzip_result { | |||
159 | } inflate_unzip_result; | 203 | } inflate_unzip_result; |
160 | 204 | ||
161 | IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; | 205 | IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; |
162 | /* xz unpacker takes .xz stream from offset 0 */ | 206 | /* xz unpacker takes .xz stream from offset 6 */ |
163 | IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; | 207 | IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; |
164 | /* lzma unpacker takes .lzma stream from offset 0 */ | 208 | /* lzma unpacker takes .lzma stream from offset 0 */ |
165 | IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; | 209 | IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; |
diff --git a/include/usage.src.h b/include/usage.src.h index f30edbc54..b3396006f 100644 --- a/include/usage.src.h +++ b/include/usage.src.h | |||
@@ -119,12 +119,6 @@ INSERT | |||
119 | #define sh_full_usage "" | 119 | #define sh_full_usage "" |
120 | #define ash_trivial_usage NOUSAGE_STR | 120 | #define ash_trivial_usage NOUSAGE_STR |
121 | #define ash_full_usage "" | 121 | #define ash_full_usage "" |
122 | #define hush_trivial_usage NOUSAGE_STR | ||
123 | #define hush_full_usage "" | ||
124 | #define lash_trivial_usage NOUSAGE_STR | ||
125 | #define lash_full_usage "" | ||
126 | #define msh_trivial_usage NOUSAGE_STR | ||
127 | #define msh_full_usage "" | ||
128 | #define bash_trivial_usage NOUSAGE_STR | 122 | #define bash_trivial_usage NOUSAGE_STR |
129 | #define bash_full_usage "" | 123 | #define bash_full_usage "" |
130 | 124 | ||
@@ -163,16 +157,6 @@ INSERT | |||
163 | #define blkid_full_usage "\n\n" \ | 157 | #define blkid_full_usage "\n\n" \ |
164 | "Print UUIDs of all filesystems" | 158 | "Print UUIDs of all filesystems" |
165 | 159 | ||
166 | #define bootchartd_trivial_usage \ | ||
167 | "start [PROG ARGS]|stop|init" | ||
168 | #define bootchartd_full_usage "\n\n" \ | ||
169 | "Create /var/log/bootchart.tgz with boot chart data\n" \ | ||
170 | "\nOptions:" \ | ||
171 | "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" \ | ||
172 | "\nstop: send USR1 to all bootchartd processes" \ | ||
173 | "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" \ | ||
174 | "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" \ | ||
175 | |||
176 | #define brctl_trivial_usage \ | 160 | #define brctl_trivial_usage \ |
177 | "COMMAND [BRIDGE [INTERFACE]]" | 161 | "COMMAND [BRIDGE [INTERFACE]]" |
178 | #define brctl_full_usage "\n\n" \ | 162 | #define brctl_full_usage "\n\n" \ |
@@ -444,7 +428,7 @@ INSERT | |||
444 | " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" \ | 428 | " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" \ |
445 | " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" | 429 | " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" |
446 | #define chpst_full_usage "\n\n" \ | 430 | #define chpst_full_usage "\n\n" \ |
447 | "Change the process state and run PROG\n" \ | 431 | "Change the process state, run PROG\n" \ |
448 | "\nOptions:" \ | 432 | "\nOptions:" \ |
449 | "\n -u USER[:GRP] Set uid and gid" \ | 433 | "\n -u USER[:GRP] Set uid and gid" \ |
450 | "\n -U USER[:GRP] Set $UID and $GID in environment" \ | 434 | "\n -U USER[:GRP] Set $UID and $GID in environment" \ |
@@ -467,17 +451,17 @@ INSERT | |||
467 | #define setuidgid_trivial_usage \ | 451 | #define setuidgid_trivial_usage \ |
468 | "USER PROG ARGS" | 452 | "USER PROG ARGS" |
469 | #define setuidgid_full_usage "\n\n" \ | 453 | #define setuidgid_full_usage "\n\n" \ |
470 | "Set uid and gid to USER's uid and gid, removing all supplementary\n" \ | 454 | "Set uid and gid to USER's uid and gid, drop supplementary group ids,\n" \ |
471 | "groups and run PROG" | 455 | "run PROG" |
472 | #define envuidgid_trivial_usage \ | 456 | #define envuidgid_trivial_usage \ |
473 | "USER PROG ARGS" | 457 | "USER PROG ARGS" |
474 | #define envuidgid_full_usage "\n\n" \ | 458 | #define envuidgid_full_usage "\n\n" \ |
475 | "Set $UID to USER's uid and $GID to USER's gid and run PROG" | 459 | "Set $UID to USER's uid and $GID to USER's gid, run PROG" |
476 | #define envdir_trivial_usage \ | 460 | #define envdir_trivial_usage \ |
477 | "DIR PROG ARGS" | 461 | "DIR PROG ARGS" |
478 | #define envdir_full_usage "\n\n" \ | 462 | #define envdir_full_usage "\n\n" \ |
479 | "Set various environment variables as specified by files\n" \ | 463 | "Set various environment variables as specified by files\n" \ |
480 | "in the directory dir and run PROG" | 464 | "in the directory DIR, run PROG" |
481 | #define softlimit_trivial_usage \ | 465 | #define softlimit_trivial_usage \ |
482 | "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" \ | 466 | "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" \ |
483 | " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" \ | 467 | " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" \ |
@@ -548,24 +532,49 @@ INSERT | |||
548 | #define bbconfig_trivial_usage \ | 532 | #define bbconfig_trivial_usage \ |
549 | "" | 533 | "" |
550 | #define bbconfig_full_usage "\n\n" \ | 534 | #define bbconfig_full_usage "\n\n" \ |
551 | "Print the config file which built busybox" | 535 | "Print the config file used by busybox build" |
552 | 536 | ||
553 | #define chrt_trivial_usage \ | 537 | #define chrt_trivial_usage \ |
554 | "[OPTIONS] [PRIO] [PID | PROG ARGS]" | 538 | "[OPTIONS] [PRIO] [PID | PROG ARGS]" |
555 | #define chrt_full_usage "\n\n" \ | 539 | #define chrt_full_usage "\n\n" \ |
556 | "Manipulate real-time attributes of a process\n" \ | 540 | "Change scheduling priority and class for a process\n" \ |
557 | "\nOptions:" \ | 541 | "\nOptions:" \ |
558 | "\n -p Operate on PID" \ | 542 | "\n -p Operate on PID" \ |
559 | "\n -r Set SCHED_RR scheduling" \ | 543 | "\n -r Set SCHED_RR class" \ |
560 | "\n -f Set SCHED_FIFO scheduling" \ | 544 | "\n -f Set SCHED_FIFO class" \ |
561 | "\n -o Set SCHED_OTHER scheduling" \ | 545 | "\n -o Set SCHED_OTHER class" \ |
562 | "\n -m Show min and max priorities" \ | 546 | "\n -m Show min/max priorities" \ |
563 | 547 | ||
564 | #define chrt_example_usage \ | 548 | #define chrt_example_usage \ |
565 | "$ chrt -r 4 sleep 900; x=$!\n" \ | 549 | "$ chrt -r 4 sleep 900; x=$!\n" \ |
566 | "$ chrt -f -p 3 $x\n" \ | 550 | "$ chrt -f -p 3 $x\n" \ |
567 | "You need CAP_SYS_NICE privileges to set scheduling attributes of a process" | 551 | "You need CAP_SYS_NICE privileges to set scheduling attributes of a process" |
568 | 552 | ||
553 | #define nice_trivial_usage \ | ||
554 | "[-n ADJUST] [PROG ARGS]" | ||
555 | #define nice_full_usage "\n\n" \ | ||
556 | "Change scheduling priority, run PROG\n" \ | ||
557 | "\nOptions:" \ | ||
558 | "\n -n ADJUST Adjust priority by ADJUST" \ | ||
559 | |||
560 | #define renice_trivial_usage \ | ||
561 | "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" | ||
562 | #define renice_full_usage "\n\n" \ | ||
563 | "Change scheduling priority for a running process\n" \ | ||
564 | "\nOptions:" \ | ||
565 | "\n -n Adjust current nice value (smaller is faster)" \ | ||
566 | "\n -p Process id(s) (default)" \ | ||
567 | "\n -g Process group id(s)" \ | ||
568 | "\n -u Process user name(s) and/or id(s)" \ | ||
569 | |||
570 | #define ionice_trivial_usage \ | ||
571 | "[-c 1-3] [-n 0-7] [-p PID] [PROG]" | ||
572 | #define ionice_full_usage "\n\n" \ | ||
573 | "Change I/O priority and class\n" \ | ||
574 | "\nOptions:" \ | ||
575 | "\n -c Class. 1:realtime 2:best-effort 3:idle" \ | ||
576 | "\n -n Priority" \ | ||
577 | |||
569 | #define cp_trivial_usage \ | 578 | #define cp_trivial_usage \ |
570 | "[OPTIONS] SOURCE DEST" | 579 | "[OPTIONS] SOURCE DEST" |
571 | #define cp_full_usage "\n\n" \ | 580 | #define cp_full_usage "\n\n" \ |
@@ -1309,7 +1318,7 @@ INSERT | |||
1309 | #define flock_trivial_usage \ | 1318 | #define flock_trivial_usage \ |
1310 | "[-sxun] FD|{FILE [-c] PROG ARGS}" | 1319 | "[-sxun] FD|{FILE [-c] PROG ARGS}" |
1311 | #define flock_full_usage "\n\n" \ | 1320 | #define flock_full_usage "\n\n" \ |
1312 | "[Un]lock file descriptor, or lock FILE and run PROG\n" \ | 1321 | "[Un]lock file descriptor, or lock FILE, run PROG\n" \ |
1313 | "\nOptions:" \ | 1322 | "\nOptions:" \ |
1314 | "\n -s Shared lock" \ | 1323 | "\n -s Shared lock" \ |
1315 | "\n -x Exclusive lock (default)" \ | 1324 | "\n -x Exclusive lock (default)" \ |
@@ -2048,14 +2057,6 @@ INSERT | |||
2048 | "\n -Z Set security context" \ | 2057 | "\n -Z Set security context" \ |
2049 | ) | 2058 | ) |
2050 | 2059 | ||
2051 | #define ionice_trivial_usage \ | ||
2052 | "[-c 1-3] [-n 0-7] [-p PID] [PROG]" | ||
2053 | #define ionice_full_usage "\n\n" \ | ||
2054 | "Change I/O scheduling class and priority\n" \ | ||
2055 | "\nOptions:" \ | ||
2056 | "\n -c Class. 1:realtime 2:best-effort 3:idle" \ | ||
2057 | "\n -n Priority" \ | ||
2058 | |||
2059 | /* would need to make the " | " optional depending on more than one selected: */ | 2060 | /* would need to make the " | " optional depending on more than one selected: */ |
2060 | #define ip_trivial_usage \ | 2061 | #define ip_trivial_usage \ |
2061 | "[OPTIONS] {" \ | 2062 | "[OPTIONS] {" \ |
@@ -2954,84 +2955,6 @@ INSERT | |||
2954 | " or\n" \ | 2955 | " or\n" \ |
2955 | "$ nameif -c /etc/my_mactab_file\n" \ | 2956 | "$ nameif -c /etc/my_mactab_file\n" \ |
2956 | 2957 | ||
2957 | #if !ENABLE_DESKTOP | ||
2958 | |||
2959 | #if ENABLE_NC_SERVER || ENABLE_NC_EXTRA | ||
2960 | #define NC_OPTIONS_STR "\n\nOptions:" | ||
2961 | #else | ||
2962 | #define NC_OPTIONS_STR | ||
2963 | #endif | ||
2964 | |||
2965 | #define nc_trivial_usage \ | ||
2966 | IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ") \ | ||
2967 | "["IF_NC_EXTRA("-f FILENAME|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]") | ||
2968 | #define nc_full_usage "\n\n" \ | ||
2969 | "Open a pipe to IP:port" IF_NC_EXTRA(" or file") \ | ||
2970 | NC_OPTIONS_STR \ | ||
2971 | IF_NC_EXTRA( \ | ||
2972 | "\n -e PROG Run PROG after connect" \ | ||
2973 | "\n -i SEC Delay interval for lines sent" \ | ||
2974 | "\n -w SEC Timeout for connect" \ | ||
2975 | "\n -f FILE Use file (ala /dev/ttyS0) instead of network" \ | ||
2976 | ) \ | ||
2977 | IF_NC_SERVER( \ | ||
2978 | "\n -l Listen mode, for inbound connects" \ | ||
2979 | IF_NC_EXTRA( \ | ||
2980 | "\n (use -l twice with -e for persistent server)") \ | ||
2981 | "\n -p PORT Local port" \ | ||
2982 | ) | ||
2983 | |||
2984 | #define nc_notes_usage "" \ | ||
2985 | IF_NC_EXTRA( \ | ||
2986 | "To use netcat as a terminal emulator on a serial port:\n\n" \ | ||
2987 | "$ stty 115200 -F /dev/ttyS0\n" \ | ||
2988 | "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" \ | ||
2989 | ) | ||
2990 | |||
2991 | #define nc_example_usage \ | ||
2992 | "$ nc foobar.somedomain.com 25\n" \ | ||
2993 | "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \ | ||
2994 | "help\n" \ | ||
2995 | "214-Commands supported:\n" \ | ||
2996 | "214- HELO EHLO MAIL RCPT DATA AUTH\n" \ | ||
2997 | "214 NOOP QUIT RSET HELP\n" \ | ||
2998 | "quit\n" \ | ||
2999 | "221 foobar closing connection\n" | ||
3000 | |||
3001 | #else /* DESKTOP nc - much more compatible with nc 1.10 */ | ||
3002 | |||
3003 | #define nc_trivial_usage \ | ||
3004 | "[OPTIONS] HOST PORT - connect" \ | ||
3005 | IF_NC_SERVER("\n" \ | ||
3006 | "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") | ||
3007 | #define nc_full_usage "\n\n" \ | ||
3008 | "Options:" \ | ||
3009 | "\n -e PROG Run PROG after connect (must be last)" \ | ||
3010 | IF_NC_SERVER( \ | ||
3011 | "\n -l Listen mode, for inbound connects" \ | ||
3012 | ) \ | ||
3013 | "\n -n Don't do DNS resolution" \ | ||
3014 | "\n -s ADDR Local address" \ | ||
3015 | "\n -p PORT Local port" \ | ||
3016 | "\n -u UDP mode" \ | ||
3017 | "\n -v Verbose" \ | ||
3018 | "\n -w SEC Timeout for connects and final net reads" \ | ||
3019 | IF_NC_EXTRA( \ | ||
3020 | "\n -i SEC Delay interval for lines sent" /* ", ports scanned" */ \ | ||
3021 | "\n -o FILE Hex dump traffic" \ | ||
3022 | "\n -z Zero-I/O mode (scanning)" \ | ||
3023 | ) \ | ||
3024 | /* "\n -r Randomize local and remote ports" */ | ||
3025 | /* "\n -g gateway Source-routing hop point[s], up to 8" */ | ||
3026 | /* "\n -G num Source-routing pointer: 4, 8, 12, ..." */ | ||
3027 | /* "\nport numbers can be individual or ranges: lo-hi [inclusive]" */ | ||
3028 | |||
3029 | /* -e PROG can take ARGS too: "nc ... -e ls -l", but we don't document it | ||
3030 | * in help text: nc 1.10 does not allow that. We don't want to entice | ||
3031 | * users to use this incompatibility */ | ||
3032 | |||
3033 | #endif | ||
3034 | |||
3035 | #define netstat_trivial_usage \ | 2958 | #define netstat_trivial_usage \ |
3036 | "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" | 2959 | "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" |
3037 | #define netstat_full_usage "\n\n" \ | 2960 | #define netstat_full_usage "\n\n" \ |
@@ -3053,13 +2976,6 @@ INSERT | |||
3053 | "\n -p Display PID/Program name for sockets" \ | 2976 | "\n -p Display PID/Program name for sockets" \ |
3054 | ) | 2977 | ) |
3055 | 2978 | ||
3056 | #define nice_trivial_usage \ | ||
3057 | "[-n ADJUST] [PROG ARGS]" | ||
3058 | #define nice_full_usage "\n\n" \ | ||
3059 | "Run PROG with modified scheduling priority\n" \ | ||
3060 | "\nOptions:" \ | ||
3061 | "\n -n ADJUST Adjust priority by ADJUST" \ | ||
3062 | |||
3063 | #define nmeter_trivial_usage \ | 2979 | #define nmeter_trivial_usage \ |
3064 | "format_string" | 2980 | "format_string" |
3065 | #define nmeter_full_usage "\n\n" \ | 2981 | #define nmeter_full_usage "\n\n" \ |
@@ -3513,16 +3429,6 @@ INSERT | |||
3513 | "\n" \ | 3429 | "\n" \ |
3514 | "\nOther options are silently ignored" \ | 3430 | "\nOther options are silently ignored" \ |
3515 | 3431 | ||
3516 | #define renice_trivial_usage \ | ||
3517 | "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" | ||
3518 | #define renice_full_usage "\n\n" \ | ||
3519 | "Change priority of running processes\n" \ | ||
3520 | "\nOptions:" \ | ||
3521 | "\n -n Adjust current nice value (smaller is faster)" \ | ||
3522 | "\n -p Process id(s) (default)" \ | ||
3523 | "\n -g Process group id(s)" \ | ||
3524 | "\n -u Process user name(s) and/or id(s)" \ | ||
3525 | |||
3526 | #define scriptreplay_trivial_usage \ | 3432 | #define scriptreplay_trivial_usage \ |
3527 | "timingfile [typescript [divisor]]" | 3433 | "timingfile [typescript [divisor]]" |
3528 | #define scriptreplay_full_usage "\n\n" \ | 3434 | #define scriptreplay_full_usage "\n\n" \ |
@@ -4273,54 +4179,6 @@ INSERT | |||
4273 | #define tac_full_usage "\n\n" \ | 4179 | #define tac_full_usage "\n\n" \ |
4274 | "Concatenate FILEs and print them in reverse" | 4180 | "Concatenate FILEs and print them in reverse" |
4275 | 4181 | ||
4276 | #define tar_trivial_usage \ | ||
4277 | "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") \ | ||
4278 | IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") \ | ||
4279 | IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " \ | ||
4280 | IF_FEATURE_TAR_FROM("[-X FILE] ") \ | ||
4281 | "[-f TARFILE] [-C DIR] [FILE]..." | ||
4282 | #define tar_full_usage "\n\n" \ | ||
4283 | IF_FEATURE_TAR_CREATE("Create, extract, ") \ | ||
4284 | IF_NOT_FEATURE_TAR_CREATE("Extract ") \ | ||
4285 | "or list files from a tar file\n" \ | ||
4286 | "\nOptions:" \ | ||
4287 | IF_FEATURE_TAR_CREATE( \ | ||
4288 | "\n c Create" \ | ||
4289 | ) \ | ||
4290 | "\n x Extract" \ | ||
4291 | "\n t List" \ | ||
4292 | "\nArchive format selection:" \ | ||
4293 | IF_FEATURE_SEAMLESS_GZ( \ | ||
4294 | "\n z Filter the archive through gzip" \ | ||
4295 | ) \ | ||
4296 | IF_FEATURE_SEAMLESS_BZ2( \ | ||
4297 | "\n j Filter the archive through bzip2" \ | ||
4298 | ) \ | ||
4299 | IF_FEATURE_SEAMLESS_LZMA( \ | ||
4300 | "\n a Filter the archive through lzma" \ | ||
4301 | ) \ | ||
4302 | IF_FEATURE_SEAMLESS_Z( \ | ||
4303 | "\n Z Filter the archive through compress" \ | ||
4304 | ) \ | ||
4305 | IF_FEATURE_TAR_NOPRESERVE_TIME( \ | ||
4306 | "\n m Do not restore mtime" \ | ||
4307 | ) \ | ||
4308 | "\nFile selection:" \ | ||
4309 | "\n f Name of TARFILE or \"-\" for stdin" \ | ||
4310 | "\n O Extract to stdout" \ | ||
4311 | IF_FEATURE_TAR_FROM( \ | ||
4312 | IF_FEATURE_TAR_LONG_OPTIONS( \ | ||
4313 | "\n exclude File to exclude" \ | ||
4314 | ) \ | ||
4315 | "\n X File with names to exclude" \ | ||
4316 | ) \ | ||
4317 | "\n C Change to DIR before operation" \ | ||
4318 | "\n v Verbose" \ | ||
4319 | |||
4320 | #define tar_example_usage \ | ||
4321 | "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \ | ||
4322 | "$ tar -cf /tmp/tarball.tar /usr/local\n" | ||
4323 | |||
4324 | #define taskset_trivial_usage \ | 4182 | #define taskset_trivial_usage \ |
4325 | "[-p] [MASK] [PID | PROG ARGS]" | 4183 | "[-p] [MASK] [PID | PROG ARGS]" |
4326 | #define taskset_full_usage "\n\n" \ | 4184 | #define taskset_full_usage "\n\n" \ |
diff --git a/init/Config.src b/init/Config.src index 2e9208150..590e29890 100644 --- a/init/Config.src +++ b/init/Config.src | |||
@@ -122,18 +122,4 @@ config MESG | |||
122 | Mesg controls access to your terminal by others. It is typically | 122 | Mesg controls access to your terminal by others. It is typically |
123 | used to allow or disallow other users to write to your terminal | 123 | used to allow or disallow other users to write to your terminal |
124 | 124 | ||
125 | config BOOTCHARTD | ||
126 | bool "bootchartd" | ||
127 | default y | ||
128 | help | ||
129 | bootchartd is commonly used to profile the boot process | ||
130 | for the purpose of speeding it up. In this case, it is started | ||
131 | by the kernel as the init process. This is configured by adding | ||
132 | the init=/sbin/bootchartd option to the kernel command line. | ||
133 | |||
134 | It can also be used to monitor the resource usage of a specific | ||
135 | application or the running system in general. In this case, | ||
136 | bootchartd is started interactively by running bootchartd start | ||
137 | and stopped using bootchartd stop. | ||
138 | |||
139 | endmenu | 125 | endmenu |
diff --git a/init/bootchartd.c b/init/bootchartd.c index d1f9ed30e..dae2fe6e9 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c | |||
@@ -2,7 +2,49 @@ | |||
2 | /* | 2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 3 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
4 | */ | 4 | */ |
5 | |||
6 | //config:config BOOTCHARTD | ||
7 | //config: bool "bootchartd" | ||
8 | //config: default y | ||
9 | //config: help | ||
10 | //config: bootchartd is commonly used to profile the boot process | ||
11 | //config: for the purpose of speeding it up. In this case, it is started | ||
12 | //config: by the kernel as the init process. This is configured by adding | ||
13 | //config: the init=/sbin/bootchartd option to the kernel command line. | ||
14 | //config: | ||
15 | //config: It can also be used to monitor the resource usage of a specific | ||
16 | //config: application or the running system in general. In this case, | ||
17 | //config: bootchartd is started interactively by running bootchartd start | ||
18 | //config: and stopped using bootchartd stop. | ||
19 | //config: | ||
20 | //config:config FEATURE_BOOTCHARTD_BLOATED_HEADER | ||
21 | //config: bool "Compatible, bloated header" | ||
22 | //config: default y | ||
23 | //config: depends on BOOTCHARTD | ||
24 | //config: help | ||
25 | //config: Create extended header file compatible with "big" bootchartd. | ||
26 | //config: "Big" bootchartd is a shell script and it dumps some | ||
27 | //config: "convenient" info int the header, such as: | ||
28 | //config: title = Boot chart for `hostname` (`date`) | ||
29 | //config: system.uname = `uname -srvm` | ||
30 | //config: system.release = `cat /etc/DISTRO-release` | ||
31 | //config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) | ||
32 | //config: system.kernel.options = `cat /proc/cmdline` | ||
33 | //config: This data is not mandatory for bootchart graph generation, | ||
34 | //config: and is considered bloat. Nevertheless, this option | ||
35 | //config: makes bootchartd applet to dump a subset of it. | ||
36 | //config: | ||
37 | //config:config FEATURE_BOOTCHARTD_CONFIG_FILE | ||
38 | //config: bool "Support bootchartd.conf" | ||
39 | //config: default y | ||
40 | //config: depends on BOOTCHARTD | ||
41 | //config: help | ||
42 | //config: Enable reading and parsing of $PWD/bootchartd.conf | ||
43 | //config: and /etc/bootchartd.conf files. | ||
44 | |||
5 | #include "libbb.h" | 45 | #include "libbb.h" |
46 | /* After libbb.h, since it needs sys/types.h on some systems */ | ||
47 | #include <sys/utsname.h> | ||
6 | #include <sys/mount.h> | 48 | #include <sys/mount.h> |
7 | #ifndef MS_SILENT | 49 | #ifndef MS_SILENT |
8 | # define MS_SILENT (1 << 15) | 50 | # define MS_SILENT (1 << 15) |
@@ -19,15 +61,16 @@ | |||
19 | #define DO_SIGNAL_SYNC 1 | 61 | #define DO_SIGNAL_SYNC 1 |
20 | 62 | ||
21 | 63 | ||
22 | //Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf | 64 | //$PWD/bootchartd.conf and /etc/bootchartd.conf: |
23 | 65 | //supported options: | |
66 | //# Sampling period (in seconds) | ||
67 | //SAMPLE_PERIOD=0.2 | ||
68 | // | ||
69 | //not yet supported: | ||
24 | //# tmpfs size | 70 | //# tmpfs size |
25 | //# (32 MB should suffice for ~20 minutes worth of log data, but YMMV) | 71 | //# (32 MB should suffice for ~20 minutes worth of log data, but YMMV) |
26 | //TMPFS_SIZE=32m | 72 | //TMPFS_SIZE=32m |
27 | // | 73 | // |
28 | //# Sampling period (in seconds) | ||
29 | //SAMPLE_PERIOD=0.2 | ||
30 | // | ||
31 | //# Whether to enable and store BSD process accounting information. The | 74 | //# Whether to enable and store BSD process accounting information. The |
32 | //# kernel needs to be configured to enable v3 accounting | 75 | //# kernel needs to be configured to enable v3 accounting |
33 | //# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities | 76 | //# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities |
@@ -113,7 +156,7 @@ static int dump_procs(FILE *fp, int look_for_login_process) | |||
113 | continue; | 156 | continue; |
114 | p++; | 157 | p++; |
115 | strchrnul(p, ')')[0] = '\0'; | 158 | strchrnul(p, ')')[0] = '\0'; |
116 | /* If is gdm, kdm or a getty? */ | 159 | /* Is it gdm, kdm or a getty? */ |
117 | if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm') | 160 | if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm') |
118 | || strstr(p, "getty") | 161 | || strstr(p, "getty") |
119 | ) { | 162 | ) { |
@@ -126,7 +169,7 @@ static int dump_procs(FILE *fp, int look_for_login_process) | |||
126 | return found_login_process; | 169 | return found_login_process; |
127 | } | 170 | } |
128 | 171 | ||
129 | static char *make_tempdir(const char *prog) | 172 | static char *make_tempdir(void) |
130 | { | 173 | { |
131 | char template[] = "/tmp/bootchart.XXXXXX"; | 174 | char template[] = "/tmp/bootchart.XXXXXX"; |
132 | char *tempdir = xstrdup(mkdtemp(template)); | 175 | char *tempdir = xstrdup(mkdtemp(template)); |
@@ -151,18 +194,10 @@ static char *make_tempdir(const char *prog) | |||
151 | } else { | 194 | } else { |
152 | xchdir(tempdir); | 195 | xchdir(tempdir); |
153 | } | 196 | } |
154 | { | ||
155 | FILE *header_fp = xfopen("header", "w"); | ||
156 | if (prog) | ||
157 | fprintf(header_fp, "profile.process = %s\n", prog); | ||
158 | fputs("version = "BC_VERSION_STR"\n", header_fp); | ||
159 | fclose(header_fp); | ||
160 | } | ||
161 | |||
162 | return tempdir; | 197 | return tempdir; |
163 | } | 198 | } |
164 | 199 | ||
165 | static void do_logging(void) | 200 | static void do_logging(unsigned sample_period_us) |
166 | { | 201 | { |
167 | //# Enable process accounting if configured | 202 | //# Enable process accounting if configured |
168 | //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then | 203 | //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then |
@@ -175,7 +210,7 @@ static void do_logging(void) | |||
175 | //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); | 210 | //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); |
176 | FILE *proc_ps = xfopen("proc_ps.log", "w"); | 211 | FILE *proc_ps = xfopen("proc_ps.log", "w"); |
177 | int look_for_login_process = (getppid() == 1); | 212 | int look_for_login_process = (getppid() == 1); |
178 | unsigned count = 60*1000*1000 / (200*1000); /* ~1 minute */ | 213 | unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ |
179 | 214 | ||
180 | while (--count && !bb_got_signal) { | 215 | while (--count && !bb_got_signal) { |
181 | char *p; | 216 | char *p; |
@@ -200,31 +235,65 @@ static void do_logging(void) | |||
200 | /* dump_procs saw a getty or {g,k,x}dm | 235 | /* dump_procs saw a getty or {g,k,x}dm |
201 | * stop logging in 2 seconds: | 236 | * stop logging in 2 seconds: |
202 | */ | 237 | */ |
203 | if (count > 2*1000*1000 / (200*1000)) | 238 | if (count > 2*1000*1000 / sample_period_us) |
204 | count = 2*1000*1000 / (200*1000); | 239 | count = 2*1000*1000 / sample_period_us; |
205 | } | 240 | } |
206 | fflush_all(); | 241 | fflush_all(); |
207 | wait_more: | 242 | wait_more: |
208 | usleep(200*1000); | 243 | usleep(sample_period_us); |
209 | } | 244 | } |
210 | 245 | ||
211 | // [ -e kernel_pacct ] && accton off | 246 | // [ -e kernel_pacct ] && accton off |
212 | } | 247 | } |
213 | 248 | ||
214 | static void finalize(char *tempdir) | 249 | static void finalize(char *tempdir, const char *prog) |
215 | { | 250 | { |
216 | //# Stop process accounting if configured | 251 | //# Stop process accounting if configured |
217 | //local pacct= | 252 | //local pacct= |
218 | //[ -e kernel_pacct ] && pacct=kernel_pacct | 253 | //[ -e kernel_pacct ] && pacct=kernel_pacct |
219 | 254 | ||
220 | //( | 255 | FILE *header_fp = xfopen("header", "w"); |
221 | // echo "version = $VERSION" | 256 | |
222 | // echo "title = Boot chart for $( hostname | sed q ) ($( date ))" | 257 | if (prog) |
223 | // echo "system.uname = $( uname -srvm | sed q )" | 258 | fprintf(header_fp, "profile.process = %s\n", prog); |
224 | // echo "system.release = $( sed q /etc/SuSE-release )" | 259 | |
225 | // echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)" | 260 | fputs("version = "BC_VERSION_STR"\n", header_fp); |
226 | // echo "system.kernel.options = $( sed q /proc/cmdline )" | 261 | if (ENABLE_FEATURE_BOOTCHARTD_BLOATED_HEADER) { |
227 | //) >> header | 262 | char *hostname; |
263 | char *kcmdline; | ||
264 | time_t t; | ||
265 | struct tm tm_time; | ||
266 | /* x2 for possible localized weekday/month names */ | ||
267 | char date_buf[sizeof("Mon Jun 21 05:29:03 CEST 2010") * 2]; | ||
268 | struct utsname unamebuf; | ||
269 | |||
270 | hostname = safe_gethostname(); | ||
271 | time(&t); | ||
272 | localtime_r(&t, &tm_time); | ||
273 | strftime(date_buf, sizeof(date_buf), "%a %b %e %H:%M:%S %Z %Y", &tm_time); | ||
274 | fprintf(header_fp, "title = Boot chart for %s (%s)\n", hostname, date_buf); | ||
275 | if (ENABLE_FEATURE_CLEAN_UP) | ||
276 | free(hostname); | ||
277 | |||
278 | uname(&unamebuf); /* never fails */ | ||
279 | /* same as uname -srvm */ | ||
280 | fprintf(header_fp, "system.uname = %s %s %s %s\n", | ||
281 | unamebuf.sysname, | ||
282 | unamebuf.release, | ||
283 | unamebuf.version, | ||
284 | unamebuf.machine | ||
285 | ); | ||
286 | |||
287 | //system.release = `cat /etc/DISTRO-release` | ||
288 | //system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) | ||
289 | |||
290 | kcmdline = xmalloc_open_read_close("/proc/cmdline", NULL); | ||
291 | /* kcmdline includes trailing "\n" */ | ||
292 | fprintf(header_fp, "system.kernel.options = %s", kcmdline); | ||
293 | if (ENABLE_FEATURE_CLEAN_UP) | ||
294 | free(kcmdline); | ||
295 | } | ||
296 | fclose(header_fp); | ||
228 | 297 | ||
229 | /* Package log files */ | 298 | /* Package log files */ |
230 | system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct | 299 | system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct |
@@ -243,19 +312,20 @@ static void finalize(char *tempdir) | |||
243 | */ | 312 | */ |
244 | } | 313 | } |
245 | 314 | ||
246 | /* Usage: | 315 | //usage:#define bootchartd_trivial_usage |
247 | * bootchartd start [PROG ARGS]: start logging in background, USR1 stops it. | 316 | //usage: "start [PROG ARGS]|stop|init" |
248 | * With PROG, runs PROG, then kills background logging. | 317 | //usage:#define bootchartd_full_usage "\n\n" |
249 | * bootchartd stop: same as "killall -USR1 bootchartd" | 318 | //usage: "Create /var/log/bootchart.tgz with boot chart data\n" |
250 | * bootchartd init: start logging in background | 319 | //usage: "\nOptions:" |
251 | * Stop when getty/gdm is seen (if AUTO_STOP_LOGGER = yes). | 320 | //usage: "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" |
252 | * Meant to be used from init scripts. | 321 | //usage: "\nstop: send USR1 to all bootchartd processes" |
253 | * bootchartd (pid==1): as init, but then execs $bootchart_init, /init, /sbin/init | 322 | //usage: "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" |
254 | * Meant to be used as kernel's init process. | 323 | //usage: "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" |
255 | */ | 324 | |
256 | int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 325 | int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
257 | int bootchartd_main(int argc UNUSED_PARAM, char **argv) | 326 | int bootchartd_main(int argc UNUSED_PARAM, char **argv) |
258 | { | 327 | { |
328 | unsigned sample_period_us; | ||
259 | pid_t parent_pid, logger_pid; | 329 | pid_t parent_pid, logger_pid; |
260 | smallint cmd; | 330 | smallint cmd; |
261 | enum { | 331 | enum { |
@@ -287,7 +357,25 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) | |||
287 | cmd = CMD_PID1; | 357 | cmd = CMD_PID1; |
288 | } | 358 | } |
289 | 359 | ||
290 | /* Here we are in START or INIT state. Create logger child: */ | 360 | /* Here we are in START, INIT or CMD_PID1 state */ |
361 | |||
362 | /* Read config file: */ | ||
363 | sample_period_us = 200 * 1000; | ||
364 | if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { | ||
365 | char* token[2]; | ||
366 | parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); | ||
367 | if (!parser) | ||
368 | parser = config_open2("/etc/bootchartd.conf", fopen_for_read); | ||
369 | while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { | ||
370 | if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) | ||
371 | sample_period_us = atof(token[1]) * 1000000; | ||
372 | } | ||
373 | config_close(parser); | ||
374 | } | ||
375 | if ((int)sample_period_us <= 0) | ||
376 | sample_period_us = 1; /* prevent division by 0 */ | ||
377 | |||
378 | /* Create logger child: */ | ||
291 | logger_pid = fork_or_rexec(argv); | 379 | logger_pid = fork_or_rexec(argv); |
292 | 380 | ||
293 | if (logger_pid == 0) { /* child */ | 381 | if (logger_pid == 0) { /* child */ |
@@ -312,9 +400,9 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) | |||
312 | if (cmd == CMD_PID1 && !getenv("PATH")) | 400 | if (cmd == CMD_PID1 && !getenv("PATH")) |
313 | putenv((char*)bb_PATH_root_path); | 401 | putenv((char*)bb_PATH_root_path); |
314 | 402 | ||
315 | tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL); | 403 | tempdir = make_tempdir(); |
316 | do_logging(); | 404 | do_logging(sample_period_us); |
317 | finalize(tempdir); | 405 | finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); |
318 | return EXIT_SUCCESS; | 406 | return EXIT_SUCCESS; |
319 | } | 407 | } |
320 | 408 | ||
@@ -335,17 +423,15 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) | |||
335 | execl(bootchart_init, bootchart_init, NULL); | 423 | execl(bootchart_init, bootchart_init, NULL); |
336 | execl("/init", "init", NULL); | 424 | execl("/init", "init", NULL); |
337 | execl("/sbin/init", "init", NULL); | 425 | execl("/sbin/init", "init", NULL); |
338 | bb_perror_msg_and_die("can't exec '%s'", "/sbin/init"); | 426 | bb_perror_msg_and_die("can't execute '%s'", "/sbin/init"); |
339 | } | 427 | } |
340 | 428 | ||
341 | if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ | 429 | if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ |
342 | pid_t pid = vfork(); | 430 | pid_t pid = xvfork(); |
343 | if (pid < 0) | ||
344 | bb_perror_msg_and_die("vfork"); | ||
345 | if (pid == 0) { /* child */ | 431 | if (pid == 0) { /* child */ |
346 | argv += 2; | 432 | argv += 2; |
347 | execvp(argv[0], argv); | 433 | execvp(argv[0], argv); |
348 | bb_perror_msg_and_die("can't exec '%s'", argv[0]); | 434 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); |
349 | } | 435 | } |
350 | /* parent */ | 436 | /* parent */ |
351 | waitpid(pid, NULL, 0); | 437 | waitpid(pid, NULL, 0); |
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 2a50a1ae3..a4f77414b 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src | |||
@@ -4,6 +4,8 @@ | |||
4 | # | 4 | # |
5 | # Licensed under the GPL v2, see the file LICENSE in this tarball. | 5 | # Licensed under the GPL v2, see the file LICENSE in this tarball. |
6 | 6 | ||
7 | libbb/appletlib.o: include/usage_compressed.h | ||
8 | |||
7 | lib-y:= | 9 | lib-y:= |
8 | 10 | ||
9 | INSERT | 11 | INSERT |
@@ -30,8 +32,6 @@ lib-y += create_icmp_socket.o | |||
30 | lib-y += default_error_retval.o | 32 | lib-y += default_error_retval.o |
31 | lib-y += device_open.o | 33 | lib-y += device_open.o |
32 | lib-y += dump.o | 34 | lib-y += dump.o |
33 | lib-y += error_msg.o | ||
34 | lib-y += error_msg_and_die.o | ||
35 | lib-y += execable.o | 35 | lib-y += execable.o |
36 | lib-y += fclose_nonstdin.o | 36 | lib-y += fclose_nonstdin.o |
37 | lib-y += fflush_stdout_and_exit.o | 37 | lib-y += fflush_stdout_and_exit.o |
@@ -44,7 +44,6 @@ lib-y += get_line_from_file.o | |||
44 | lib-y += getopt32.o | 44 | lib-y += getopt32.o |
45 | lib-y += get_volsize.o | 45 | lib-y += get_volsize.o |
46 | lib-y += herror_msg.o | 46 | lib-y += herror_msg.o |
47 | lib-y += herror_msg_and_die.o | ||
48 | lib-y += human_readable.o | 47 | lib-y += human_readable.o |
49 | lib-y += info_msg.o | 48 | lib-y += info_msg.o |
50 | lib-y += inode_hash.o | 49 | lib-y += inode_hash.o |
@@ -63,7 +62,6 @@ lib-y += obscure.o | |||
63 | lib-y += parse_mode.o | 62 | lib-y += parse_mode.o |
64 | lib-y += parse_config.o | 63 | lib-y += parse_config.o |
65 | lib-y += perror_msg.o | 64 | lib-y += perror_msg.o |
66 | lib-y += perror_msg_and_die.o | ||
67 | lib-y += perror_nomsg.o | 65 | lib-y += perror_nomsg.o |
68 | lib-y += perror_nomsg_and_die.o | 66 | lib-y += perror_nomsg_and_die.o |
69 | lib-y += pidfile.o | 67 | lib-y += pidfile.o |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 922f7d26b..cae7da48a 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -61,11 +61,11 @@ | |||
61 | static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; | 61 | static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; |
62 | #else | 62 | #else |
63 | # define usage_messages 0 | 63 | # define usage_messages 0 |
64 | #endif /* SHOW_USAGE */ | 64 | #endif |
65 | 65 | ||
66 | #if ENABLE_FEATURE_COMPRESS_USAGE | 66 | #if ENABLE_FEATURE_COMPRESS_USAGE |
67 | 67 | ||
68 | static const char packed_usage[] = { PACKED_USAGE }; | 68 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; |
69 | # include "unarchive.h" | 69 | # include "unarchive.h" |
70 | static const char *unpack_usage_messages(void) | 70 | static const char *unpack_usage_messages(void) |
71 | { | 71 | { |
@@ -195,7 +195,11 @@ void lbb_prepare(const char *applet | |||
195 | #if ENABLE_FEATURE_INDIVIDUAL | 195 | #if ENABLE_FEATURE_INDIVIDUAL |
196 | /* Redundant for busybox (run_applet_and_exit covers that case) | 196 | /* Redundant for busybox (run_applet_and_exit covers that case) |
197 | * but needed for "individual applet" mode */ | 197 | * but needed for "individual applet" mode */ |
198 | if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) { | 198 | if (argv[1] |
199 | && !argv[2] | ||
200 | && strcmp(argv[1], "--help") == 0 | ||
201 | && strncmp(applet, "busybox", 7) != 0 | ||
202 | ) { | ||
199 | /* Special case. POSIX says "test --help" | 203 | /* Special case. POSIX says "test --help" |
200 | * should be no different from e.g. "test --foo". */ | 204 | * should be no different from e.g. "test --foo". */ |
201 | if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) | 205 | if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) |
diff --git a/libbb/copyfd.c b/libbb/copyfd.c index f42eb7623..82622c06f 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c | |||
@@ -9,19 +9,29 @@ | |||
9 | 9 | ||
10 | #include "libbb.h" | 10 | #include "libbb.h" |
11 | 11 | ||
12 | /* Used by NOFORK applets (e.g. cat) - must not use xmalloc */ | 12 | /* Used by NOFORK applets (e.g. cat) - must not use xmalloc. |
13 | 13 | * size < 0 means "ignore write errors", used by tar --to-command | |
14 | * size = 0 means "copy till EOF" | ||
15 | */ | ||
14 | static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | 16 | static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) |
15 | { | 17 | { |
16 | int status = -1; | 18 | int status = -1; |
17 | off_t total = 0; | 19 | off_t total = 0; |
20 | bool continue_on_write_error = 0; | ||
18 | #if CONFIG_FEATURE_COPYBUF_KB <= 4 | 21 | #if CONFIG_FEATURE_COPYBUF_KB <= 4 |
19 | char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; | 22 | char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; |
20 | enum { buffer_size = sizeof(buffer) }; | 23 | enum { buffer_size = sizeof(buffer) }; |
21 | #else | 24 | #else |
22 | char *buffer; | 25 | char *buffer; |
23 | int buffer_size; | 26 | int buffer_size; |
27 | #endif | ||
24 | 28 | ||
29 | if (size < 0) { | ||
30 | size = -size; | ||
31 | continue_on_write_error = 1; | ||
32 | } | ||
33 | |||
34 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | ||
25 | if (size > 0 && size <= 4 * 1024) | 35 | if (size > 0 && size <= 4 * 1024) |
26 | goto use_small_buf; | 36 | goto use_small_buf; |
27 | /* We want page-aligned buffer, just in case kernel is clever | 37 | /* We want page-aligned buffer, just in case kernel is clever |
@@ -63,8 +73,11 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | |||
63 | if (dst_fd >= 0) { | 73 | if (dst_fd >= 0) { |
64 | ssize_t wr = full_write(dst_fd, buffer, rd); | 74 | ssize_t wr = full_write(dst_fd, buffer, rd); |
65 | if (wr < rd) { | 75 | if (wr < rd) { |
66 | bb_perror_msg(bb_msg_write_error); | 76 | if (!continue_on_write_error) { |
67 | break; | 77 | bb_perror_msg(bb_msg_write_error); |
78 | break; | ||
79 | } | ||
80 | dst_fd = -1; | ||
68 | } | 81 | } |
69 | } | 82 | } |
70 | total += rd; | 83 | total += rd; |
@@ -108,7 +121,7 @@ off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size) | |||
108 | void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) | 121 | void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) |
109 | { | 122 | { |
110 | off_t sz = bb_copyfd_size(fd1, fd2, size); | 123 | off_t sz = bb_copyfd_size(fd1, fd2, size); |
111 | if (sz == size) | 124 | if (sz == (size >= 0 ? size : -size)) |
112 | return; | 125 | return; |
113 | if (sz != -1) | 126 | if (sz != -1) |
114 | bb_error_msg_and_die("short read"); | 127 | bb_error_msg_and_die("short read"); |
diff --git a/libbb/error_msg.c b/libbb/error_msg.c deleted file mode 100644 index 802fd5715..000000000 --- a/libbb/error_msg.c +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | void FAST_FUNC bb_error_msg(const char *s, ...) | ||
13 | { | ||
14 | va_list p; | ||
15 | |||
16 | va_start(p, s); | ||
17 | bb_verror_msg(s, p, NULL); | ||
18 | va_end(p); | ||
19 | } | ||
diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c deleted file mode 100644 index 243433b2d..000000000 --- a/libbb/error_msg_and_die.c +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | void FAST_FUNC bb_error_msg_and_die(const char *s, ...) | ||
13 | { | ||
14 | va_list p; | ||
15 | |||
16 | va_start(p, s); | ||
17 | bb_verror_msg(s, p, NULL); | ||
18 | va_end(p); | ||
19 | xfunc_die(); | ||
20 | } | ||
diff --git a/libbb/execable.c b/libbb/execable.c index 06b1c534b..de368fad0 100644 --- a/libbb/execable.c +++ b/libbb/execable.c | |||
@@ -109,3 +109,11 @@ int FAST_FUNC bb_execvp(const char *file, char *const argv[]) | |||
109 | argv); | 109 | argv); |
110 | } | 110 | } |
111 | #endif | 111 | #endif |
112 | |||
113 | int FAST_FUNC BB_EXECVP_or_die(char **argv) | ||
114 | { | ||
115 | BB_EXECVP(argv[0], argv); | ||
116 | /* SUSv3-mandated exit codes */ | ||
117 | xfunc_error_retval = (errno == ENOENT) ? 127 : 126; | ||
118 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | ||
119 | } | ||
diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c index 7e4f64045..ca9274cf7 100644 --- a/libbb/herror_msg.c +++ b/libbb/herror_msg.c | |||
@@ -6,7 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | */ | 8 | */ |
9 | |||
10 | #include "libbb.h" | 9 | #include "libbb.h" |
11 | 10 | ||
12 | void FAST_FUNC bb_herror_msg(const char *s, ...) | 11 | void FAST_FUNC bb_herror_msg(const char *s, ...) |
@@ -17,3 +16,13 @@ void FAST_FUNC bb_herror_msg(const char *s, ...) | |||
17 | bb_verror_msg(s, p, hstrerror(h_errno)); | 16 | bb_verror_msg(s, p, hstrerror(h_errno)); |
18 | va_end(p); | 17 | va_end(p); |
19 | } | 18 | } |
19 | |||
20 | void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) | ||
21 | { | ||
22 | va_list p; | ||
23 | |||
24 | va_start(p, s); | ||
25 | bb_verror_msg(s, p, hstrerror(h_errno)); | ||
26 | va_end(p); | ||
27 | xfunc_die(); | ||
28 | } | ||
diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c deleted file mode 100644 index 230fe645a..000000000 --- a/libbb/herror_msg_and_die.c +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) | ||
13 | { | ||
14 | va_list p; | ||
15 | |||
16 | va_start(p, s); | ||
17 | bb_verror_msg(s, p, hstrerror(h_errno)); | ||
18 | va_end(p); | ||
19 | xfunc_die(); | ||
20 | } | ||
diff --git a/libbb/parse_config.c b/libbb/parse_config.c index c511d97fb..b7c3a00e0 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c | |||
@@ -128,8 +128,8 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
128 | int ntokens, mintokens; | 128 | int ntokens, mintokens; |
129 | int t, len; | 129 | int t, len; |
130 | 130 | ||
131 | ntokens = flags & 0xFF; | 131 | ntokens = (uint8_t)flags; |
132 | mintokens = (flags & 0xFF00) >> 8; | 132 | mintokens = (uint8_t)(flags >> 8); |
133 | 133 | ||
134 | if (parser == NULL) | 134 | if (parser == NULL) |
135 | return 0; | 135 | return 0; |
@@ -159,7 +159,8 @@ again: | |||
159 | parser->data = xstrdup(line); | 159 | parser->data = xstrdup(line); |
160 | 160 | ||
161 | /* Tokenize the line */ | 161 | /* Tokenize the line */ |
162 | for (t = 0; *line && *line != delims[0] && t < ntokens; t++) { | 162 | t = 0; |
163 | do { | ||
163 | /* Pin token */ | 164 | /* Pin token */ |
164 | tokens[t] = line; | 165 | tokens[t] = line; |
165 | 166 | ||
@@ -179,10 +180,10 @@ again: | |||
179 | } | 180 | } |
180 | 181 | ||
181 | /* Token not terminated? */ | 182 | /* Token not terminated? */ |
182 | if (line[0] == delims[0]) | 183 | if (*line == delims[0]) |
183 | *line = '\0'; | 184 | *line = '\0'; |
184 | else if (line[0] != '\0') | 185 | else if (*line != '\0') |
185 | *(line++) = '\0'; | 186 | *line++ = '\0'; |
186 | 187 | ||
187 | #if 0 /* unused so far */ | 188 | #if 0 /* unused so far */ |
188 | if (flags & PARSE_ESCAPE) { | 189 | if (flags & PARSE_ESCAPE) { |
@@ -201,17 +202,20 @@ again: | |||
201 | *to = '\0'; | 202 | *to = '\0'; |
202 | } | 203 | } |
203 | #endif | 204 | #endif |
204 | |||
205 | /* Skip possible delimiters */ | 205 | /* Skip possible delimiters */ |
206 | if (flags & PARSE_COLLAPSE) | 206 | if (flags & PARSE_COLLAPSE) |
207 | line += strspn(line, delims + 1); | 207 | line += strspn(line, delims + 1); |
208 | } | 208 | |
209 | t++; | ||
210 | } while (*line && *line != delims[0] && t < ntokens); | ||
209 | 211 | ||
210 | if (t < mintokens) { | 212 | if (t < mintokens) { |
211 | bb_error_msg("bad line %u: %d tokens found, %d needed", | 213 | bb_error_msg("bad line %u: %d tokens found, %d needed", |
212 | parser->lineno, t, mintokens); | 214 | parser->lineno, t, mintokens); |
213 | if (flags & PARSE_MIN_DIE) | 215 | if (flags & PARSE_MIN_DIE) |
214 | xfunc_die(); | 216 | xfunc_die(); |
217 | if (flags & PARSE_KEEP_COPY) | ||
218 | free(parser->data); | ||
215 | goto again; | 219 | goto again; |
216 | } | 220 | } |
217 | 221 | ||
diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c index 6c8e1b51e..cbba805fb 100644 --- a/libbb/perror_msg.c +++ b/libbb/perror_msg.c | |||
@@ -6,7 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | */ | 8 | */ |
9 | |||
10 | #include "libbb.h" | 9 | #include "libbb.h" |
11 | 10 | ||
12 | void FAST_FUNC bb_perror_msg(const char *s, ...) | 11 | void FAST_FUNC bb_perror_msg(const char *s, ...) |
@@ -19,7 +18,23 @@ void FAST_FUNC bb_perror_msg(const char *s, ...) | |||
19 | va_end(p); | 18 | va_end(p); |
20 | } | 19 | } |
21 | 20 | ||
21 | void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) | ||
22 | { | ||
23 | va_list p; | ||
24 | |||
25 | va_start(p, s); | ||
26 | /* Guard against "<error message>: Success" */ | ||
27 | bb_verror_msg(s, p, errno ? strerror(errno) : NULL); | ||
28 | va_end(p); | ||
29 | xfunc_die(); | ||
30 | } | ||
31 | |||
22 | void FAST_FUNC bb_simple_perror_msg(const char *s) | 32 | void FAST_FUNC bb_simple_perror_msg(const char *s) |
23 | { | 33 | { |
24 | bb_perror_msg("%s", s); | 34 | bb_perror_msg("%s", s); |
25 | } | 35 | } |
36 | |||
37 | void FAST_FUNC bb_simple_perror_msg_and_die(const char *s) | ||
38 | { | ||
39 | bb_perror_msg_and_die("%s", s); | ||
40 | } | ||
diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c deleted file mode 100644 index 15615fa22..000000000 --- a/libbb/perror_msg_and_die.c +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) | ||
13 | { | ||
14 | va_list p; | ||
15 | |||
16 | va_start(p, s); | ||
17 | /* Guard against "<error message>: Success" */ | ||
18 | bb_verror_msg(s, p, errno ? strerror(errno) : NULL); | ||
19 | va_end(p); | ||
20 | xfunc_die(); | ||
21 | } | ||
22 | |||
23 | void FAST_FUNC bb_simple_perror_msg_and_die(const char *s) | ||
24 | { | ||
25 | bb_perror_msg_and_die("%s", s); | ||
26 | } | ||
diff --git a/libbb/platform.c b/libbb/platform.c index 8642337d4..67048648f 100644 --- a/libbb/platform.c +++ b/libbb/platform.c | |||
@@ -120,3 +120,30 @@ char* FAST_FUNC strcasestr(const char *s, const char *pattern) | |||
120 | return 0; | 120 | return 0; |
121 | } | 121 | } |
122 | #endif | 122 | #endif |
123 | |||
124 | #ifndef HAVE_STRSEP | ||
125 | /* Copyright (C) 2004 Free Software Foundation, Inc. */ | ||
126 | char* FAST_FUNC strsep(char **stringp, const char *delim) | ||
127 | { | ||
128 | char *start = *stringp; | ||
129 | char *ptr; | ||
130 | |||
131 | if (!start) | ||
132 | return NULL; | ||
133 | |||
134 | if (!*delim) | ||
135 | ptr = start + strlen(start); | ||
136 | else { | ||
137 | ptr = strpbrk(start, delim); | ||
138 | if (!ptr) { | ||
139 | *stringp = NULL; | ||
140 | return start; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | *ptr = '\0'; | ||
145 | *stringp = ptr + 1; | ||
146 | |||
147 | return start; | ||
148 | } | ||
149 | #endif | ||
diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 53f528f5a..1b215f97a 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c | |||
@@ -265,7 +265,7 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) | |||
265 | 265 | ||
266 | /* .gz and .bz2 both have 2-byte signature, and their | 266 | /* .gz and .bz2 both have 2-byte signature, and their |
267 | * unpack_XXX_stream wants this header skipped. */ | 267 | * unpack_XXX_stream wants this header skipped. */ |
268 | xread(fd, magic.b16, sizeof(magic.b16)); | 268 | xread(fd, magic.b16, sizeof(magic.b16[0])); |
269 | if (ENABLE_FEATURE_SEAMLESS_GZ | 269 | if (ENABLE_FEATURE_SEAMLESS_GZ |
270 | && magic.b16[0] == GZIP_MAGIC | 270 | && magic.b16[0] == GZIP_MAGIC |
271 | ) { | 271 | ) { |
@@ -289,15 +289,13 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) | |||
289 | if (ENABLE_FEATURE_SEAMLESS_XZ | 289 | if (ENABLE_FEATURE_SEAMLESS_XZ |
290 | && magic.b16[0] == XZ_MAGIC1 | 290 | && magic.b16[0] == XZ_MAGIC1 |
291 | ) { | 291 | ) { |
292 | /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ | ||
293 | /* More info at: http://tukaani.org/xz/xz-file-format.txt */ | ||
294 | offset = -6; | 292 | offset = -6; |
295 | xread(fd, magic.b32, sizeof(magic.b32)); | 293 | xread(fd, magic.b32, sizeof(magic.b32[0])); |
296 | if (magic.b32[0] == XZ_MAGIC2) { | 294 | if (magic.b32[0] == XZ_MAGIC2) { |
297 | # if BB_MMU | 295 | # if BB_MMU |
298 | xformer = unpack_xz_stream; | 296 | xformer = unpack_xz_stream; |
299 | /* unpack_xz_stream wants fd at position 0 */ | 297 | /* unpack_xz_stream wants fd at position 6, no need to seek */ |
300 | xlseek(fd, offset, SEEK_CUR); | 298 | //xlseek(fd, offset, SEEK_CUR); |
301 | # else | 299 | # else |
302 | xformer_prog = "unxz"; | 300 | xformer_prog = "unxz"; |
303 | # endif | 301 | # endif |
diff --git a/libbb/run_shell.c b/libbb/run_shell.c index 6f98bd695..4d92c3caa 100644 --- a/libbb/run_shell.c +++ b/libbb/run_shell.c | |||
@@ -49,15 +49,14 @@ void FAST_FUNC set_current_security_context(security_context_t sid) | |||
49 | 49 | ||
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | /* Run SHELL, or DEFAULT_SHELL if SHELL is empty. | 52 | /* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL. |
53 | If COMMAND is nonzero, pass it to the shell with the -c option. | 53 | * If COMMAND is nonzero, pass it to the shell with the -c option. |
54 | If ADDITIONAL_ARGS is nonzero, pass it to the shell as more | 54 | * If ADDITIONAL_ARGS is nonzero, pass it to the shell as more |
55 | arguments. */ | 55 | * arguments. */ |
56 | |||
57 | void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) | 56 | void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) |
58 | { | 57 | { |
59 | const char **args; | 58 | const char **args; |
60 | int argno = 1; | 59 | int argno; |
61 | int additional_args_cnt = 0; | 60 | int additional_args_cnt = 0; |
62 | 61 | ||
63 | for (args = additional_args; args && *args; args++) | 62 | for (args = additional_args; args && *args; args++) |
@@ -65,11 +64,13 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, | |||
65 | 64 | ||
66 | args = xmalloc(sizeof(char*) * (4 + additional_args_cnt)); | 65 | args = xmalloc(sizeof(char*) * (4 + additional_args_cnt)); |
67 | 66 | ||
68 | args[0] = bb_get_last_path_component_nostrip(xstrdup(shell)); | 67 | if (!shell || !shell[0]) |
68 | shell = DEFAULT_SHELL; | ||
69 | 69 | ||
70 | args[0] = bb_get_last_path_component_nostrip(shell); | ||
70 | if (loginshell) | 71 | if (loginshell) |
71 | args[0] = xasprintf("-%s", args[0]); | 72 | args[0] = xasprintf("-%s", args[0]); |
72 | 73 | argno = 1; | |
73 | if (command) { | 74 | if (command) { |
74 | args[argno++] = "-c"; | 75 | args[argno++] = "-c"; |
75 | args[argno++] = command; | 76 | args[argno++] = command; |
@@ -79,6 +80,7 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, | |||
79 | args[argno++] = *additional_args; | 80 | args[argno++] = *additional_args; |
80 | } | 81 | } |
81 | args[argno] = NULL; | 82 | args[argno] = NULL; |
83 | |||
82 | #if ENABLE_SELINUX | 84 | #if ENABLE_SELINUX |
83 | if (current_sid) | 85 | if (current_sid) |
84 | setexeccon(current_sid); | 86 | setexeccon(current_sid); |
@@ -86,5 +88,5 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, | |||
86 | freecon(current_sid); | 88 | freecon(current_sid); |
87 | #endif | 89 | #endif |
88 | execv(shell, (char **) args); | 90 | execv(shell, (char **) args); |
89 | bb_perror_msg_and_die("can't run '%s'", shell); | 91 | bb_perror_msg_and_die("can't execute '%s'", shell); |
90 | } | 92 | } |
diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c index 13e60d8e4..a95fbc5bf 100644 --- a/libbb/setup_environment.c +++ b/libbb/setup_environment.c | |||
@@ -43,7 +43,7 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct pass | |||
43 | const char *term; | 43 | const char *term; |
44 | 44 | ||
45 | /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. | 45 | /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. |
46 | Unset all other environment variables. */ | 46 | * Unset all other environment variables. */ |
47 | term = getenv("TERM"); | 47 | term = getenv("TERM"); |
48 | clearenv(); | 48 | clearenv(); |
49 | if (term) | 49 | if (term) |
@@ -57,7 +57,7 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct pass | |||
57 | //xsetenv("SHELL", shell); | 57 | //xsetenv("SHELL", shell); |
58 | } else if (flags & SETUP_ENV_CHANGEENV) { | 58 | } else if (flags & SETUP_ENV_CHANGEENV) { |
59 | /* Set HOME, SHELL, and if not becoming a super-user, | 59 | /* Set HOME, SHELL, and if not becoming a super-user, |
60 | USER and LOGNAME. */ | 60 | * USER and LOGNAME. */ |
61 | if (pw->pw_uid) { | 61 | if (pw->pw_uid) { |
62 | shortcut: | 62 | shortcut: |
63 | xsetenv("USER", pw->pw_name); | 63 | xsetenv("USER", pw->pw_name); |
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c index 613432906..c5fbc380c 100644 --- a/libbb/verror_msg.c +++ b/libbb/verror_msg.c | |||
@@ -76,12 +76,9 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) | |||
76 | free(msg); | 76 | free(msg); |
77 | } | 77 | } |
78 | 78 | ||
79 | |||
80 | #ifdef VERSION_WITH_WRITEV | 79 | #ifdef VERSION_WITH_WRITEV |
81 | |||
82 | /* Code size is approximately the same, but currently it's the only user | 80 | /* Code size is approximately the same, but currently it's the only user |
83 | * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */ | 81 | * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */ |
84 | |||
85 | void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) | 82 | void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) |
86 | { | 83 | { |
87 | int strerr_len, msgeol_len; | 84 | int strerr_len, msgeol_len; |
@@ -139,3 +136,23 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) | |||
139 | free(msgc); | 136 | free(msgc); |
140 | } | 137 | } |
141 | #endif | 138 | #endif |
139 | |||
140 | |||
141 | void FAST_FUNC bb_error_msg_and_die(const char *s, ...) | ||
142 | { | ||
143 | va_list p; | ||
144 | |||
145 | va_start(p, s); | ||
146 | bb_verror_msg(s, p, NULL); | ||
147 | va_end(p); | ||
148 | xfunc_die(); | ||
149 | } | ||
150 | |||
151 | void FAST_FUNC bb_error_msg(const char *s, ...) | ||
152 | { | ||
153 | va_list p; | ||
154 | |||
155 | va_start(p, s); | ||
156 | bb_verror_msg(s, p, NULL); | ||
157 | va_end(p); | ||
158 | } | ||
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 08d9199c1..2b6ee9e74 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c | |||
@@ -70,40 +70,6 @@ pid_t FAST_FUNC xspawn(char **argv) | |||
70 | return pid; | 70 | return pid; |
71 | } | 71 | } |
72 | 72 | ||
73 | pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) | ||
74 | { | ||
75 | pid_t r; | ||
76 | |||
77 | do | ||
78 | r = waitpid(pid, wstat, options); | ||
79 | while ((r == -1) && (errno == EINTR)); | ||
80 | return r; | ||
81 | } | ||
82 | |||
83 | pid_t FAST_FUNC wait_any_nohang(int *wstat) | ||
84 | { | ||
85 | return safe_waitpid(-1, wstat, WNOHANG); | ||
86 | } | ||
87 | |||
88 | // Wait for the specified child PID to exit, returning child's error return. | ||
89 | int FAST_FUNC wait4pid(pid_t pid) | ||
90 | { | ||
91 | int status; | ||
92 | |||
93 | if (pid <= 0) { | ||
94 | /*errno = ECHILD; -- wrong. */ | ||
95 | /* we expect errno to be already set from failed [v]fork/exec */ | ||
96 | return -1; | ||
97 | } | ||
98 | if (safe_waitpid(pid, &status, 0) == -1) | ||
99 | return -1; | ||
100 | if (WIFEXITED(status)) | ||
101 | return WEXITSTATUS(status); | ||
102 | if (WIFSIGNALED(status)) | ||
103 | return WTERMSIG(status) + 0x180; | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | #if ENABLE_FEATURE_PREFER_APPLETS | 73 | #if ENABLE_FEATURE_PREFER_APPLETS |
108 | void FAST_FUNC save_nofork_data(struct nofork_save_area *save) | 74 | void FAST_FUNC save_nofork_data(struct nofork_save_area *save) |
109 | { | 75 | { |
@@ -252,7 +218,7 @@ void FAST_FUNC re_exec(char **argv) | |||
252 | * "we have (already) re-execed, don't do it again" flag */ | 218 | * "we have (already) re-execed, don't do it again" flag */ |
253 | argv[0][0] |= 0x80; | 219 | argv[0][0] |= 0x80; |
254 | execv(bb_busybox_exec_path, argv); | 220 | execv(bb_busybox_exec_path, argv); |
255 | bb_perror_msg_and_die("exec %s", bb_busybox_exec_path); | 221 | bb_perror_msg_and_die("can't execute '%s'", bb_busybox_exec_path); |
256 | } | 222 | } |
257 | 223 | ||
258 | pid_t FAST_FUNC fork_or_rexec(char **argv) | 224 | pid_t FAST_FUNC fork_or_rexec(char **argv) |
@@ -261,26 +227,12 @@ pid_t FAST_FUNC fork_or_rexec(char **argv) | |||
261 | /* Maybe we are already re-execed and come here again? */ | 227 | /* Maybe we are already re-execed and come here again? */ |
262 | if (re_execed) | 228 | if (re_execed) |
263 | return 0; | 229 | return 0; |
264 | pid = vfork(); | 230 | pid = xvfork(); |
265 | if (pid < 0) /* wtf? */ | ||
266 | bb_perror_msg_and_die("vfork"); | ||
267 | if (pid) /* parent */ | 231 | if (pid) /* parent */ |
268 | return pid; | 232 | return pid; |
269 | /* child - re-exec ourself */ | 233 | /* child - re-exec ourself */ |
270 | re_exec(argv); | 234 | re_exec(argv); |
271 | } | 235 | } |
272 | #else | ||
273 | /* Dance around (void)...*/ | ||
274 | #undef fork_or_rexec | ||
275 | pid_t FAST_FUNC fork_or_rexec(void) | ||
276 | { | ||
277 | pid_t pid; | ||
278 | pid = fork(); | ||
279 | if (pid < 0) /* wtf? */ | ||
280 | bb_perror_msg_and_die("fork"); | ||
281 | return pid; | ||
282 | } | ||
283 | #define fork_or_rexec(argv) fork_or_rexec() | ||
284 | #endif | 236 | #endif |
285 | 237 | ||
286 | /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - | 238 | /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - |
diff --git a/libbb/xconnect.c b/libbb/xconnect.c index c3ee633e4..2de6de7c5 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <sys/types.h> | ||
10 | #include <sys/socket.h> /* netinet/in.h needs it */ | 11 | #include <sys/socket.h> /* netinet/in.h needs it */ |
11 | #include <netinet/in.h> | 12 | #include <netinet/in.h> |
12 | #include <net/if.h> | 13 | #include <net/if.h> |
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 65437211d..275dd4b62 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c | |||
@@ -268,3 +268,37 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) | |||
268 | { | 268 | { |
269 | return tcsetattr(STDIN_FILENO, TCSANOW, tp); | 269 | return tcsetattr(STDIN_FILENO, TCSANOW, tp); |
270 | } | 270 | } |
271 | |||
272 | pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) | ||
273 | { | ||
274 | pid_t r; | ||
275 | |||
276 | do | ||
277 | r = waitpid(pid, wstat, options); | ||
278 | while ((r == -1) && (errno == EINTR)); | ||
279 | return r; | ||
280 | } | ||
281 | |||
282 | pid_t FAST_FUNC wait_any_nohang(int *wstat) | ||
283 | { | ||
284 | return safe_waitpid(-1, wstat, WNOHANG); | ||
285 | } | ||
286 | |||
287 | // Wait for the specified child PID to exit, returning child's error return. | ||
288 | int FAST_FUNC wait4pid(pid_t pid) | ||
289 | { | ||
290 | int status; | ||
291 | |||
292 | if (pid <= 0) { | ||
293 | /*errno = ECHILD; -- wrong. */ | ||
294 | /* we expect errno to be already set from failed [v]fork/exec */ | ||
295 | return -1; | ||
296 | } | ||
297 | if (safe_waitpid(pid, &status, 0) == -1) | ||
298 | return -1; | ||
299 | if (WIFEXITED(status)) | ||
300 | return WEXITSTATUS(status); | ||
301 | if (WIFSIGNALED(status)) | ||
302 | return WTERMSIG(status) + 0x180; | ||
303 | return 0; | ||
304 | } | ||
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index 7feb58036..3e189c2d1 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c | |||
@@ -337,6 +337,11 @@ void FAST_FUNC bb_unsetenv(const char *var) | |||
337 | free(tp); | 337 | free(tp); |
338 | } | 338 | } |
339 | 339 | ||
340 | void FAST_FUNC bb_unsetenv_and_free(char *var) | ||
341 | { | ||
342 | bb_unsetenv(var); | ||
343 | free(var); | ||
344 | } | ||
340 | 345 | ||
341 | // Die with an error message if we can't set gid. (Because resource limits may | 346 | // Die with an error message if we can't set gid. (Because resource limits may |
342 | // limit this user to a given number of processes, and if that fills up the | 347 | // limit this user to a given number of processes, and if that fills up the |
@@ -598,3 +603,14 @@ void FAST_FUNC generate_uuid(uint8_t *buf) | |||
598 | /* variant = 10x */ | 603 | /* variant = 10x */ |
599 | buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80; | 604 | buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80; |
600 | } | 605 | } |
606 | |||
607 | #if BB_MMU | ||
608 | pid_t FAST_FUNC xfork(void) | ||
609 | { | ||
610 | pid_t pid; | ||
611 | pid = fork(); | ||
612 | if (pid < 0) /* wtf? */ | ||
613 | bb_perror_msg_and_die("vfork"+1); | ||
614 | return pid; | ||
615 | } | ||
616 | #endif | ||
diff --git a/loginutils/login.c b/loginutils/login.c index 078cd68ed..88ed0af78 100644 --- a/loginutils/login.c +++ b/loginutils/login.c | |||
@@ -201,7 +201,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
201 | }; | 201 | }; |
202 | char *fromhost; | 202 | char *fromhost; |
203 | char username[USERNAME_SIZE]; | 203 | char username[USERNAME_SIZE]; |
204 | const char *tmp; | 204 | const char *shell; |
205 | int run_by_root; | 205 | int run_by_root; |
206 | unsigned opt; | 206 | unsigned opt; |
207 | int count = 0; | 207 | int count = 0; |
@@ -389,10 +389,10 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
389 | run_login_script(pw, full_tty); | 389 | run_login_script(pw, full_tty); |
390 | 390 | ||
391 | change_identity(pw); | 391 | change_identity(pw); |
392 | tmp = pw->pw_shell; | 392 | shell = pw->pw_shell; |
393 | if (!tmp || !*tmp) | 393 | if (!shell || !shell[0]) |
394 | tmp = DEFAULT_SHELL; | 394 | shell = DEFAULT_SHELL; |
395 | setup_environment(tmp, | 395 | setup_environment(shell, |
396 | (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, | 396 | (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, |
397 | pw); | 397 | pw); |
398 | 398 | ||
@@ -427,7 +427,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
427 | signal(SIGINT, SIG_DFL); | 427 | signal(SIGINT, SIG_DFL); |
428 | 428 | ||
429 | /* Exec login shell with no additional parameters */ | 429 | /* Exec login shell with no additional parameters */ |
430 | run_shell(tmp, 1, NULL, NULL); | 430 | run_shell(shell, 1, NULL, NULL); |
431 | 431 | ||
432 | /* return EXIT_FAILURE; - not reached */ | 432 | /* return EXIT_FAILURE; - not reached */ |
433 | } | 433 | } |
diff --git a/loginutils/su.c b/loginutils/su.c index af25655fd..9bae37551 100644 --- a/loginutils/su.c +++ b/loginutils/su.c | |||
@@ -10,23 +10,27 @@ | |||
10 | 10 | ||
11 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS | 11 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS |
12 | /* Return 1 if SHELL is a restricted shell (one not returned by | 12 | /* Return 1 if SHELL is a restricted shell (one not returned by |
13 | getusershell), else 0, meaning it is a standard shell. */ | 13 | * getusershell), else 0, meaning it is a standard shell. */ |
14 | static int restricted_shell(const char *shell) | 14 | static int restricted_shell(const char *shell) |
15 | { | 15 | { |
16 | char *line; | 16 | char *line; |
17 | int result = 1; | ||
17 | 18 | ||
18 | /*setusershell(); - getusershell does it itself*/ | 19 | /*setusershell(); - getusershell does it itself*/ |
19 | while ((line = getusershell()) != NULL) { | 20 | while ((line = getusershell()) != NULL) { |
20 | if (/* *line != '#' && */ strcmp(line, shell) == 0) | 21 | if (/* *line != '#' && */ strcmp(line, shell) == 0) { |
21 | return 0; | 22 | result = 0; |
23 | break; | ||
24 | } | ||
22 | } | 25 | } |
23 | endusershell(); | 26 | if (ENABLE_FEATURE_CLEAN_UP) |
24 | return 1; | 27 | endusershell(); |
28 | return result; | ||
25 | } | 29 | } |
26 | #endif | 30 | #endif |
27 | 31 | ||
28 | #define SU_OPT_mp (3) | 32 | #define SU_OPT_mp (3) |
29 | #define SU_OPT_l (4) | 33 | #define SU_OPT_l (4) |
30 | 34 | ||
31 | int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 35 | int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
32 | int su_main(int argc UNUSED_PARAM, char **argv) | 36 | int su_main(int argc UNUSED_PARAM, char **argv) |
@@ -38,7 +42,8 @@ int su_main(int argc UNUSED_PARAM, char **argv) | |||
38 | struct passwd *pw; | 42 | struct passwd *pw; |
39 | uid_t cur_uid = getuid(); | 43 | uid_t cur_uid = getuid(); |
40 | const char *tty; | 44 | const char *tty; |
41 | char *old_user; | 45 | char user_buf[64]; |
46 | const char *old_user; | ||
42 | 47 | ||
43 | flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); | 48 | flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); |
44 | //argc -= optind; | 49 | //argc -= optind; |
@@ -56,21 +61,18 @@ int su_main(int argc UNUSED_PARAM, char **argv) | |||
56 | } | 61 | } |
57 | 62 | ||
58 | if (ENABLE_FEATURE_SU_SYSLOG) { | 63 | if (ENABLE_FEATURE_SU_SYSLOG) { |
59 | /* The utmp entry (via getlogin) is probably the best way to identify | 64 | /* The utmp entry (via getlogin) is probably the best way to |
60 | * the user, especially if someone su's from a su-shell. | 65 | * identify the user, especially if someone su's from a su-shell. |
61 | * But getlogin can fail -- usually due to lack of utmp entry. | 66 | * But getlogin can fail -- usually due to lack of utmp entry. |
62 | * in this case resort to getpwuid. */ | 67 | * in this case resort to getpwuid. */ |
63 | const char *user; | ||
64 | #if ENABLE_FEATURE_UTMP | 68 | #if ENABLE_FEATURE_UTMP |
65 | char user_buf[64]; | 69 | old_user = user_buf; |
66 | user = user_buf; | ||
67 | if (getlogin_r(user_buf, sizeof(user_buf)) != 0) | 70 | if (getlogin_r(user_buf, sizeof(user_buf)) != 0) |
68 | #endif | 71 | #endif |
69 | { | 72 | { |
70 | pw = getpwuid(cur_uid); | 73 | pw = getpwuid(cur_uid); |
71 | user = pw ? pw->pw_name : ""; | 74 | old_user = pw ? xstrdup(pw->pw_name) : ""; |
72 | } | 75 | } |
73 | old_user = xstrdup(user); | ||
74 | tty = xmalloc_ttyname(2); | 76 | tty = xmalloc_ttyname(2); |
75 | if (!tty) { | 77 | if (!tty) { |
76 | tty = "none"; | 78 | tty = "none"; |
@@ -80,13 +82,7 @@ int su_main(int argc UNUSED_PARAM, char **argv) | |||
80 | 82 | ||
81 | pw = xgetpwnam(opt_username); | 83 | pw = xgetpwnam(opt_username); |
82 | 84 | ||
83 | /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER | 85 | if (cur_uid == 0 || correct_password(pw)) { |
84 | is a username that is retrieved via NIS (YP), but that doesn't have | ||
85 | a default shell listed. */ | ||
86 | if (!pw->pw_shell || !pw->pw_shell[0]) | ||
87 | pw->pw_shell = (char *)DEFAULT_SHELL; | ||
88 | |||
89 | if ((cur_uid == 0) || correct_password(pw)) { | ||
90 | if (ENABLE_FEATURE_SU_SYSLOG) | 86 | if (ENABLE_FEATURE_SU_SYSLOG) |
91 | syslog(LOG_NOTICE, "%c %s %s:%s", | 87 | syslog(LOG_NOTICE, "%c %s %s:%s", |
92 | '+', tty, old_user, opt_username); | 88 | '+', tty, old_user, opt_username); |
@@ -99,21 +95,30 @@ int su_main(int argc UNUSED_PARAM, char **argv) | |||
99 | 95 | ||
100 | if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { | 96 | if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { |
101 | closelog(); | 97 | closelog(); |
102 | free(old_user); | ||
103 | } | 98 | } |
104 | 99 | ||
105 | if (!opt_shell && (flags & SU_OPT_mp)) | 100 | if (!opt_shell && (flags & SU_OPT_mp)) { |
101 | /* -s SHELL is not given, but "preserve env" opt is */ | ||
106 | opt_shell = getenv("SHELL"); | 102 | opt_shell = getenv("SHELL"); |
103 | } | ||
104 | |||
105 | /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER | ||
106 | * is a username that is retrieved via NIS (YP), that doesn't have | ||
107 | * a default shell listed. */ | ||
108 | if (!pw->pw_shell || !pw->pw_shell[0]) | ||
109 | pw->pw_shell = (char *)DEFAULT_SHELL; | ||
107 | 110 | ||
108 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS | 111 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS |
109 | if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) { | 112 | if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) { |
110 | /* The user being su'd to has a nonstandard shell, and so is | 113 | /* The user being su'd to has a nonstandard shell, and so is |
111 | probably a uucp account or has restricted access. Don't | 114 | * probably a uucp account or has restricted access. Don't |
112 | compromise the account by allowing access with a standard | 115 | * compromise the account by allowing access with a standard |
113 | shell. */ | 116 | * shell. */ |
114 | bb_error_msg("using restricted shell"); | 117 | bb_error_msg("using restricted shell"); |
115 | opt_shell = NULL; | 118 | opt_shell = NULL; |
116 | } | 119 | } |
120 | /* else: user can run whatever he wants via "su -s PROG USER". | ||
121 | * This is safe since PROG is run under user's uid/gid. */ | ||
117 | #endif | 122 | #endif |
118 | if (!opt_shell) | 123 | if (!opt_shell) |
119 | opt_shell = pw->pw_shell; | 124 | opt_shell = pw->pw_shell; |
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c index 6e3d3b019..3516013f1 100644 --- a/loginutils/sulogin.c +++ b/loginutils/sulogin.c | |||
@@ -101,11 +101,9 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) | |||
101 | shell = getenv("SUSHELL"); | 101 | shell = getenv("SUSHELL"); |
102 | if (!shell) | 102 | if (!shell) |
103 | shell = getenv("sushell"); | 103 | shell = getenv("sushell"); |
104 | if (!shell) { | 104 | if (!shell) |
105 | shell = "/bin/sh"; | 105 | shell = pwd->pw_shell; |
106 | if (pwd->pw_shell[0]) | 106 | |
107 | shell = pwd->pw_shell; | ||
108 | } | ||
109 | /* Exec login shell with no additional parameters. Never returns. */ | 107 | /* Exec login shell with no additional parameters. Never returns. */ |
110 | run_shell(shell, 1, NULL, NULL); | 108 | run_shell(shell, 1, NULL, NULL); |
111 | 109 | ||
diff --git a/mailutils/mail.c b/mailutils/mail.c index 64a5b996f..bcd358302 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c | |||
@@ -54,9 +54,7 @@ void FAST_FUNC launch_helper(const char **argv) | |||
54 | + (1 << SIGALRM) | 54 | + (1 << SIGALRM) |
55 | , signal_handler); | 55 | , signal_handler); |
56 | 56 | ||
57 | G.helper_pid = vfork(); | 57 | G.helper_pid = xvfork(); |
58 | if (G.helper_pid < 0) | ||
59 | bb_perror_msg_and_die("vfork"); | ||
60 | 58 | ||
61 | i = (!G.helper_pid) * 2; // for parent:0, for child:2 | 59 | i = (!G.helper_pid) * 2; // for parent:0, for child:2 |
62 | close(pipes[i + 1]); // 1 or 3 - closing one write end | 60 | close(pipes[i + 1]); // 1 or 3 - closing one write end |
@@ -67,8 +65,7 @@ void FAST_FUNC launch_helper(const char **argv) | |||
67 | if (!G.helper_pid) { | 65 | if (!G.helper_pid) { |
68 | // child: try to execute connection helper | 66 | // child: try to execute connection helper |
69 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec | 67 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec |
70 | BB_EXECVP(*argv, (char **)argv); | 68 | BB_EXECVP_or_die((char**)argv); |
71 | _exit(127); | ||
72 | } | 69 | } |
73 | 70 | ||
74 | // parent | 71 | // parent |
diff --git a/mailutils/mime.c b/mailutils/mime.c index ee147802e..5eb8ef6f2 100644 --- a/mailutils/mime.c +++ b/mailutils/mime.c | |||
@@ -288,8 +288,7 @@ static int parse(const char *boundary, char **argv) | |||
288 | xsetenv("CHARSET", charset); | 288 | xsetenv("CHARSET", charset); |
289 | xsetenv("ENCODING", encoding); | 289 | xsetenv("ENCODING", encoding); |
290 | xsetenv("FILENAME", filename); | 290 | xsetenv("FILENAME", filename); |
291 | BB_EXECVP(*argv, argv); | 291 | BB_EXECVP_or_die(argv); |
292 | _exit(EXIT_FAILURE); | ||
293 | } | 292 | } |
294 | // parent dumps to fd[1] | 293 | // parent dumps to fd[1] |
295 | close(fd[0]); | 294 | close(fd[0]); |
diff --git a/miscutils/Config.src b/miscutils/Config.src index 012132e7b..2f7c50271 100644 --- a/miscutils/Config.src +++ b/miscutils/Config.src | |||
@@ -276,28 +276,28 @@ config FBSPLASH | |||
276 | 276 | ||
277 | config FLASHCP | 277 | config FLASHCP |
278 | bool "flashcp" | 278 | bool "flashcp" |
279 | default y | 279 | default n # doesn't build on Ubuntu 8.04 |
280 | help | 280 | help |
281 | The flashcp binary, inspired by mtd-utils as of git head 5eceb74f7. | 281 | The flashcp binary, inspired by mtd-utils as of git head 5eceb74f7. |
282 | This utility is used to copy images into a MTD device. | 282 | This utility is used to copy images into a MTD device. |
283 | 283 | ||
284 | config FLASH_LOCK | 284 | config FLASH_LOCK |
285 | bool "flash_lock" | 285 | bool "flash_lock" |
286 | default y | 286 | default n # doesn't build on Ubuntu 8.04 |
287 | help | 287 | help |
288 | The flash_lock binary from mtd-utils as of git head 5ec0c10d0. This | 288 | The flash_lock binary from mtd-utils as of git head 5ec0c10d0. This |
289 | utility locks part or all of the flash device. | 289 | utility locks part or all of the flash device. |
290 | 290 | ||
291 | config FLASH_UNLOCK | 291 | config FLASH_UNLOCK |
292 | bool "flash_unlock" | 292 | bool "flash_unlock" |
293 | default y | 293 | default n # doesn't build on Ubuntu 8.04 |
294 | help | 294 | help |
295 | The flash_unlock binary from mtd-utils as of git head 5ec0c10d0. This | 295 | The flash_unlock binary from mtd-utils as of git head 5ec0c10d0. This |
296 | utility unlocks part or all of the flash device. | 296 | utility unlocks part or all of the flash device. |
297 | 297 | ||
298 | config FLASH_ERASEALL | 298 | config FLASH_ERASEALL |
299 | bool "flash_eraseall" | 299 | bool "flash_eraseall" |
300 | default y | 300 | default n # doesn't build on Ubuntu 8.04 |
301 | help | 301 | help |
302 | The flash_eraseall binary from mtd-utils as of git head c4c6a59eb. | 302 | The flash_eraseall binary from mtd-utils as of git head c4c6a59eb. |
303 | This utility is used to erase the whole MTD device. | 303 | This utility is used to erase the whole MTD device. |
@@ -311,7 +311,7 @@ config IONICE | |||
311 | 311 | ||
312 | config INOTIFYD | 312 | config INOTIFYD |
313 | bool "inotifyd" | 313 | bool "inotifyd" |
314 | default y | 314 | default n # doesn't build on Knoppix 5 |
315 | help | 315 | help |
316 | Simple inotify daemon. Reports filesystem changes. Requires | 316 | Simple inotify daemon. Reports filesystem changes. Requires |
317 | kernel >= 2.6.13 | 317 | kernel >= 2.6.13 |
@@ -549,7 +549,7 @@ config READAHEAD | |||
549 | 549 | ||
550 | config RFKILL | 550 | config RFKILL |
551 | bool "rfkill" | 551 | bool "rfkill" |
552 | default n | 552 | default n # doesn't build on Ubuntu 9.04 |
553 | help | 553 | help |
554 | Enable/disable wireless devices. | 554 | Enable/disable wireless devices. |
555 | 555 | ||
@@ -588,7 +588,7 @@ config STRINGS | |||
588 | 588 | ||
589 | config TASKSET | 589 | config TASKSET |
590 | bool "taskset" | 590 | bool "taskset" |
591 | default y | 591 | default n # doesn't build on some non-x86 targets (m68k) |
592 | help | 592 | help |
593 | Retrieve or set a processes's CPU affinity. | 593 | Retrieve or set a processes's CPU affinity. |
594 | This requires sched_{g,s}etaffinity support in your libc. | 594 | This requires sched_{g,s}etaffinity support in your libc. |
diff --git a/miscutils/chrt.c b/miscutils/chrt.c index cc5660be7..d5f87c4d7 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c | |||
@@ -5,33 +5,35 @@ | |||
5 | * | 5 | * |
6 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 6 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
7 | */ | 7 | */ |
8 | |||
9 | #include <sched.h> | 8 | #include <sched.h> |
10 | #include "libbb.h" | 9 | #include "libbb.h" |
11 | #ifndef _POSIX_PRIORITY_SCHEDULING | 10 | #ifndef _POSIX_PRIORITY_SCHEDULING |
12 | #warning your system may be foobared | 11 | #warning your system may be foobared |
13 | #endif | 12 | #endif |
13 | |||
14 | static const struct { | 14 | static const struct { |
15 | int policy; | 15 | int policy; |
16 | char name[12]; | 16 | char name[sizeof("SCHED_OTHER")]; |
17 | } policies[] = { | 17 | } policies[] = { |
18 | {SCHED_OTHER, "SCHED_OTHER"}, | 18 | {SCHED_OTHER, "SCHED_OTHER"}, |
19 | {SCHED_FIFO, "SCHED_FIFO"}, | 19 | {SCHED_FIFO, "SCHED_FIFO"}, |
20 | {SCHED_RR, "SCHED_RR"} | 20 | {SCHED_RR, "SCHED_RR"} |
21 | }; | 21 | }; |
22 | 22 | ||
23 | //TODO: add | ||
24 | // -b, SCHED_BATCH | ||
25 | // -i, SCHED_IDLE | ||
26 | |||
23 | static void show_min_max(int pol) | 27 | static void show_min_max(int pol) |
24 | { | 28 | { |
25 | const char *fmt = "%s min/max priority\t: %d/%d\n\0%s not supported?\n"; | 29 | const char *fmt = "%s min/max priority\t: %u/%u\n"; |
26 | int max, min; | 30 | int max, min; |
31 | |||
27 | max = sched_get_priority_max(pol); | 32 | max = sched_get_priority_max(pol); |
28 | min = sched_get_priority_min(pol); | 33 | min = sched_get_priority_min(pol); |
29 | if (max >= 0 && min >= 0) | 34 | if ((max|min) < 0) |
30 | printf(fmt, policies[pol].name, min, max); | 35 | fmt = "%s not supported\n"; |
31 | else { | 36 | printf(fmt, policies[pol].name, min, max); |
32 | fmt += 29; | ||
33 | printf(fmt, policies[pol].name); | ||
34 | } | ||
35 | } | 37 | } |
36 | 38 | ||
37 | #define OPT_m (1<<0) | 39 | #define OPT_m (1<<0) |
@@ -115,9 +117,8 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) | |||
115 | if (sched_setscheduler(pid, policy, &sp) < 0) | 117 | if (sched_setscheduler(pid, policy, &sp) < 0) |
116 | bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid); | 118 | bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid); |
117 | 119 | ||
118 | if (!*argv) /* "-p <priority> <pid> [...]" */ | 120 | if (!argv[0]) /* "-p <priority> <pid> [...]" */ |
119 | goto print_rt_info; | 121 | goto print_rt_info; |
120 | 122 | ||
121 | BB_EXECVP(*argv, argv); | 123 | BB_EXECVP_or_die(argv); |
122 | bb_simple_perror_msg_and_die(*argv); | ||
123 | } | 124 | } |
diff --git a/miscutils/conspy.c b/miscutils/conspy.c new file mode 100644 index 000000000..509a0f271 --- /dev/null +++ b/miscutils/conspy.c | |||
@@ -0,0 +1,547 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * A text-mode VNC like program for Linux virtual terminals. | ||
4 | * | ||
5 | * pascal.bellard@ads-lu.com | ||
6 | * | ||
7 | * Based on Russell Stuart's conspy.c | ||
8 | * http://ace-host.stuart.id.au/russell/files/conspy.c | ||
9 | * | ||
10 | * Licensed under GPLv2 or later, see file License in this tarball for details. | ||
11 | */ | ||
12 | |||
13 | //applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
14 | |||
15 | //kbuild:lib-$(CONFIG_CONSPY) += conspy.o | ||
16 | |||
17 | //config:config CONSPY | ||
18 | //config: bool "conspy" | ||
19 | //config: default n | ||
20 | //config: help | ||
21 | //config: A text-mode VNC like program for Linux virtual terminals. | ||
22 | //config: example: conspy NUM shared access to console num | ||
23 | //config: or conspy -nd NUM screenshot of console num | ||
24 | //config: or conspy -cs NUM poor man's GNU screen like | ||
25 | |||
26 | //usage:#define conspy_trivial_usage | ||
27 | //usage: "[-vcsndf] [-x COL] [-y LINE] [CONSOLE_NO]" | ||
28 | //usage:#define conspy_full_usage "\n\n" | ||
29 | //usage: "A text-mode VNC like program for Linux virtual consoles." | ||
30 | //usage: "\nTo exit, quickly press ESC 3 times." | ||
31 | //usage: "\n" | ||
32 | //usage: "\nOptions:" | ||
33 | //usage: "\n -v Don't send keystrokes to the console" | ||
34 | //usage: "\n -c Create missing devices in /dev" | ||
35 | //usage: "\n -s Open a SHELL session" | ||
36 | //usage: "\n -n Black & white" | ||
37 | //usage: "\n -d Dump console to stdout" | ||
38 | //usage: "\n -f Follow cursor" | ||
39 | //usage: "\n -x COL Starting column" | ||
40 | //usage: "\n -y LINE Starting line" | ||
41 | |||
42 | #include "libbb.h" | ||
43 | #include <sys/kd.h> | ||
44 | |||
45 | struct screen_info { | ||
46 | unsigned char lines, cols, cursor_x, cursor_y; | ||
47 | }; | ||
48 | |||
49 | #define CHAR(x) (*(uint8_t*)(x)) | ||
50 | #define ATTR(x) (((uint8_t*)(x))[1]) | ||
51 | #define NEXT(x) ((x) += 2) | ||
52 | #define DATA(x) (*(uint16_t*)(x)) | ||
53 | |||
54 | struct globals { | ||
55 | char* data; | ||
56 | int size; | ||
57 | int x, y; | ||
58 | int kbd_fd; | ||
59 | int ioerror_count; | ||
60 | int key_count; | ||
61 | int escape_count; | ||
62 | int nokeys; | ||
63 | int current; | ||
64 | int first_line_offset; | ||
65 | int last_attr; | ||
66 | // cached local tty parameters | ||
67 | unsigned width; | ||
68 | unsigned height; | ||
69 | unsigned col; | ||
70 | unsigned line; | ||
71 | smallint curoff; // unknown:0 cursor on:-1 cursor off:1 | ||
72 | char attrbuf[sizeof("\033[0;1;5;30;40m")]; | ||
73 | // remote console | ||
74 | struct screen_info remote; | ||
75 | // saved local tty terminfo | ||
76 | struct termios term_orig; | ||
77 | char vcsa_name[sizeof("/dev/vcsaNN")]; | ||
78 | }; | ||
79 | |||
80 | #define G (*ptr_to_globals) | ||
81 | #define INIT_G() do { \ | ||
82 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | ||
83 | G.attrbuf[0] = '\033'; \ | ||
84 | G.attrbuf[1] = '['; \ | ||
85 | G.width = G.height = UINT_MAX; \ | ||
86 | G.last_attr--; \ | ||
87 | } while (0) | ||
88 | |||
89 | enum { | ||
90 | FLAG_v, // view only | ||
91 | FLAG_c, // create device if need | ||
92 | FLAG_s, // session | ||
93 | FLAG_n, // no colors | ||
94 | FLAG_d, // dump screen | ||
95 | FLAG_f, // follow cursor | ||
96 | }; | ||
97 | #define FLAG(x) (1 << FLAG_##x) | ||
98 | #define BW (option_mask32 & FLAG(n)) | ||
99 | |||
100 | static void clrscr(void) | ||
101 | { | ||
102 | // Home, clear till end of screen | ||
103 | fputs("\033[1;1H" "\033[J", stdout); | ||
104 | G.col = G.line = 0; | ||
105 | } | ||
106 | |||
107 | static void set_cursor(int state) | ||
108 | { | ||
109 | if (G.curoff != state) { | ||
110 | G.curoff = state; | ||
111 | fputs("\033[?25", stdout); | ||
112 | bb_putchar("h?l"[1 + state]); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static void gotoxy(int col, int line) | ||
117 | { | ||
118 | if (G.col != col || G.line != line) { | ||
119 | G.col = col; | ||
120 | G.line = line; | ||
121 | printf("\033[%u;%uH", line + 1, col + 1); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static void cleanup(int code) | ||
126 | { | ||
127 | set_cursor(-1); // cursor on | ||
128 | tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); | ||
129 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
130 | close(G.kbd_fd); | ||
131 | } | ||
132 | // Reset attributes | ||
133 | if (!BW) | ||
134 | fputs("\033[0m", stdout); | ||
135 | bb_putchar('\n'); | ||
136 | if (code > 1) | ||
137 | kill_myself_with_sig(code); | ||
138 | exit(code); | ||
139 | } | ||
140 | |||
141 | static void screen_read_close(void) | ||
142 | { | ||
143 | unsigned i, j; | ||
144 | int vcsa_fd; | ||
145 | char *data; | ||
146 | |||
147 | // Close & re-open vcsa in case they have swapped virtual consoles | ||
148 | vcsa_fd = xopen(G.vcsa_name, O_RDONLY); | ||
149 | xread(vcsa_fd, &G.remote, 4); | ||
150 | i = G.remote.cols * 2; | ||
151 | G.first_line_offset = G.y * i; | ||
152 | i *= G.remote.lines; | ||
153 | if (G.data == NULL) { | ||
154 | G.size = i; | ||
155 | G.data = xzalloc(2 * i); | ||
156 | } | ||
157 | else if (G.size != i) { | ||
158 | cleanup(1); | ||
159 | } | ||
160 | data = G.data + G.current; | ||
161 | xread(vcsa_fd, data, G.size); | ||
162 | close(vcsa_fd); | ||
163 | for (i = 0; i < G.remote.lines; i++) { | ||
164 | for (j = 0; j < G.remote.cols; j++, NEXT(data)) { | ||
165 | unsigned x = j - G.x; // if will catch j < G.x too | ||
166 | unsigned y = i - G.y; // if will catch i < G.y too | ||
167 | |||
168 | if (CHAR(data) < ' ') | ||
169 | CHAR(data) = ' '; | ||
170 | if (y >= G.height || x >= G.width) | ||
171 | DATA(data) = 0; | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void screen_char(char *data) | ||
177 | { | ||
178 | if (!BW) { | ||
179 | uint8_t attr = ATTR(data); | ||
180 | //uint8_t attr = ATTR(data) >> 1; // for framebuffer console | ||
181 | uint8_t attr_diff = G.last_attr ^ attr; | ||
182 | |||
183 | if (attr_diff) { | ||
184 | // Attribute layout for VGA compatible text videobuffer: | ||
185 | // blinking text | ||
186 | // |red bkgd | ||
187 | // ||green bkgd | ||
188 | // |||blue bkgd | ||
189 | // vvvv | ||
190 | // 00000000 <- lsb bit on the right | ||
191 | // bold text / text 8th bit | ||
192 | // red text | ||
193 | // green text | ||
194 | // blue text | ||
195 | // TODO: apparently framebuffer-based console uses different layout | ||
196 | // (bug? attempt to get 8th text bit in better position?) | ||
197 | // red bkgd | ||
198 | // |green bkgd | ||
199 | // ||blue bkgd | ||
200 | // vvv | ||
201 | // 00000000 <- lsb bit on the right | ||
202 | // bold text | ||
203 | // red text | ||
204 | // green text | ||
205 | // blue text | ||
206 | // text 8th bit | ||
207 | // converting RGB color bit triad to BGR: | ||
208 | static const char color[8] = "04261537"; | ||
209 | const uint8_t fg_mask = 0x07, bold_mask = 0x08; | ||
210 | const uint8_t bg_mask = 0x70, blink_mask = 0x80; | ||
211 | char *ptr; | ||
212 | |||
213 | ptr = G.attrbuf + 2; // skip "ESC [" | ||
214 | |||
215 | // (G.last_attr & ~attr) has 1 only where | ||
216 | // G.last_attr has 1 but attr has 0. | ||
217 | // Here we check whether we have transition | ||
218 | // bold->non-bold or blink->non-blink: | ||
219 | if (G.last_attr < 0 // initial value | ||
220 | || ((G.last_attr & ~attr) & (bold_mask | blink_mask)) != 0 | ||
221 | ) { | ||
222 | *ptr++ = '0'; // "reset all attrs" | ||
223 | *ptr++ = ';'; | ||
224 | // must set fg & bg, maybe need to set bold or blink: | ||
225 | attr_diff = attr | ~(bold_mask | blink_mask); | ||
226 | } | ||
227 | G.last_attr = attr; | ||
228 | if (attr_diff & bold_mask) { | ||
229 | *ptr++ = '1'; | ||
230 | *ptr++ = ';'; | ||
231 | } | ||
232 | if (attr_diff & blink_mask) { | ||
233 | *ptr++ = '5'; | ||
234 | *ptr++ = ';'; | ||
235 | } | ||
236 | if (attr_diff & fg_mask) { | ||
237 | *ptr++ = '3'; | ||
238 | *ptr++ = color[attr & fg_mask]; | ||
239 | *ptr++ = ';'; | ||
240 | } | ||
241 | if (attr_diff & bg_mask) { | ||
242 | *ptr++ = '4'; | ||
243 | *ptr++ = color[(attr & bg_mask) >> 4]; | ||
244 | *ptr++ = ';'; | ||
245 | } | ||
246 | if (ptr != G.attrbuf + 2) { | ||
247 | ptr[-1] = 'm'; | ||
248 | *ptr = '\0'; | ||
249 | fputs(G.attrbuf, stdout); | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | putchar(CHAR(data)); | ||
254 | G.col++; | ||
255 | } | ||
256 | |||
257 | static void screen_dump(void) | ||
258 | { | ||
259 | int linefeed_cnt; | ||
260 | int line, col; | ||
261 | int linecnt = G.remote.lines - G.y; | ||
262 | char *data = G.data + G.current + G.first_line_offset; | ||
263 | |||
264 | linefeed_cnt = 0; | ||
265 | for (line = 0; line < linecnt && line < G.height; line++) { | ||
266 | int space_cnt = 0; | ||
267 | for (col = 0; col < G.remote.cols; col++, NEXT(data)) { | ||
268 | unsigned tty_col = col - G.x; // if will catch col < G.x too | ||
269 | |||
270 | if (tty_col >= G.width) | ||
271 | continue; | ||
272 | space_cnt++; | ||
273 | if (BW && CHAR(data) == ' ') | ||
274 | continue; | ||
275 | while (linefeed_cnt != 0) { | ||
276 | //bb_putchar('\r'); - tty driver does it for us | ||
277 | bb_putchar('\n'); | ||
278 | linefeed_cnt--; | ||
279 | } | ||
280 | while (--space_cnt) | ||
281 | bb_putchar(' '); | ||
282 | screen_char(data); | ||
283 | } | ||
284 | linefeed_cnt++; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void curmove(void) | ||
289 | { | ||
290 | unsigned cx = G.remote.cursor_x - G.x; | ||
291 | unsigned cy = G.remote.cursor_y - G.y; | ||
292 | int cursor = 1; | ||
293 | |||
294 | if (cx < G.width && cy < G.height) { | ||
295 | gotoxy(cx, cy); | ||
296 | cursor = -1; | ||
297 | } | ||
298 | set_cursor(cursor); | ||
299 | } | ||
300 | |||
301 | static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) | ||
302 | { | ||
303 | int fd = open(name, O_RDONLY); | ||
304 | if (fd != -1) | ||
305 | close(fd); | ||
306 | else if (errno == ENOENT) | ||
307 | mknod(name, S_IFCHR | 0660, dev); | ||
308 | } | ||
309 | |||
310 | static NOINLINE void start_shell_in_child(const char* tty_name) | ||
311 | { | ||
312 | int pid = xvfork(); | ||
313 | if (pid == 0) { | ||
314 | struct termios termchild; | ||
315 | char *shell = getenv("SHELL"); | ||
316 | |||
317 | if (!shell) | ||
318 | shell = (char *) DEFAULT_SHELL; | ||
319 | signal(SIGHUP, SIG_IGN); | ||
320 | // set tty as a controlling tty | ||
321 | setsid(); | ||
322 | // make tty to be input, output, error | ||
323 | close(0); | ||
324 | xopen(tty_name, O_RDWR); // uses fd 0 | ||
325 | xdup2(0, 1); | ||
326 | xdup2(0, 2); | ||
327 | ioctl(0, TIOCSCTTY, 1); | ||
328 | tcsetpgrp(0, getpid()); | ||
329 | tcgetattr(0, &termchild); | ||
330 | termchild.c_lflag |= ECHO; | ||
331 | termchild.c_oflag |= ONLCR | XTABS; | ||
332 | termchild.c_iflag |= ICRNL; | ||
333 | termchild.c_iflag &= ~IXOFF; | ||
334 | tcsetattr_stdin_TCSANOW(&termchild); | ||
335 | execl(shell, shell, "-i", (char *) NULL); | ||
336 | bb_simple_perror_msg_and_die(shell); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
341 | int conspy_main(int argc UNUSED_PARAM, char **argv) | ||
342 | { | ||
343 | char tty_name[sizeof("/dev/ttyNN")]; | ||
344 | #define keybuf bb_common_bufsiz1 | ||
345 | struct termios termbuf; | ||
346 | unsigned opts; | ||
347 | unsigned ttynum; | ||
348 | int poll_timeout_ms; | ||
349 | #if ENABLE_LONG_OPTS | ||
350 | static const char getopt_longopts[] ALIGN1 = | ||
351 | "viewonly\0" No_argument "v" | ||
352 | "createdevice\0" No_argument "c" | ||
353 | "session\0" No_argument "s" | ||
354 | "nocolors\0" No_argument "n" | ||
355 | "dump\0" No_argument "d" | ||
356 | "follow\0" No_argument "f" | ||
357 | ; | ||
358 | |||
359 | applet_long_options = getopt_longopts; | ||
360 | #endif | ||
361 | INIT_G(); | ||
362 | strcpy(G.vcsa_name, "/dev/vcsa"); | ||
363 | |||
364 | opt_complementary = "x+:y+"; // numeric params | ||
365 | opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); | ||
366 | argv += optind; | ||
367 | ttynum = 0; | ||
368 | if (argv[0]) { | ||
369 | ttynum = xatou_range(argv[0], 0, 63); | ||
370 | sprintf(G.vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); | ||
371 | } | ||
372 | sprintf(tty_name, "%s%u", "/dev/tty", ttynum); | ||
373 | if (opts & FLAG(c)) { | ||
374 | if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) | ||
375 | create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); | ||
376 | create_cdev_if_doesnt_exist(G.vcsa_name, makedev(7, 128 + ttynum)); | ||
377 | } | ||
378 | if ((opts & FLAG(s)) && ttynum) { | ||
379 | start_shell_in_child(tty_name); | ||
380 | } | ||
381 | |||
382 | screen_read_close(); | ||
383 | if (opts & FLAG(d)) { | ||
384 | screen_dump(); | ||
385 | bb_putchar('\n'); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | bb_signals(BB_FATAL_SIGS, cleanup); | ||
390 | |||
391 | // All characters must be passed through to us unaltered | ||
392 | G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); | ||
393 | tcgetattr(G.kbd_fd, &G.term_orig); | ||
394 | termbuf = G.term_orig; | ||
395 | termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); | ||
396 | //termbuf.c_oflag &= ~(OPOST); - no, we still want \n -> \r\n | ||
397 | termbuf.c_lflag &= ~(ISIG|ICANON|ECHO); | ||
398 | termbuf.c_cc[VMIN] = 1; | ||
399 | termbuf.c_cc[VTIME] = 0; | ||
400 | tcsetattr(G.kbd_fd, TCSANOW, &termbuf); | ||
401 | |||
402 | poll_timeout_ms = 250; | ||
403 | while (1) { | ||
404 | struct pollfd pfd; | ||
405 | int bytes_read; | ||
406 | int i, j; | ||
407 | char *data, *old; | ||
408 | |||
409 | // in the first loop G.width = G.height = 0: refresh | ||
410 | i = G.width; | ||
411 | j = G.height; | ||
412 | get_terminal_width_height(G.kbd_fd, &G.width, &G.height); | ||
413 | if (option_mask32 & FLAG(f)) { | ||
414 | int nx = G.remote.cursor_x - G.width + 1; | ||
415 | int ny = G.remote.cursor_y - G.height + 1; | ||
416 | |||
417 | if (G.remote.cursor_x < G.x) { | ||
418 | G.x = G.remote.cursor_x; | ||
419 | i = 0; // force refresh | ||
420 | } | ||
421 | if (nx > G.x) { | ||
422 | G.x = nx; | ||
423 | i = 0; // force refresh | ||
424 | } | ||
425 | if (G.remote.cursor_y < G.y) { | ||
426 | G.y = G.remote.cursor_y; | ||
427 | i = 0; // force refresh | ||
428 | } | ||
429 | if (ny > G.y) { | ||
430 | G.y = ny; | ||
431 | i = 0; // force refresh | ||
432 | } | ||
433 | } | ||
434 | |||
435 | // Scan console data and redraw our tty where needed | ||
436 | old = G.data + G.current; | ||
437 | G.current = G.size - G.current; | ||
438 | data = G.data + G.current; | ||
439 | screen_read_close(); | ||
440 | if (i != G.width || j != G.height) { | ||
441 | clrscr(); | ||
442 | screen_dump(); | ||
443 | } else { | ||
444 | // For each remote line | ||
445 | old += G.first_line_offset; | ||
446 | data += G.first_line_offset; | ||
447 | for (i = G.y; i < G.remote.lines; i++) { | ||
448 | char *first = NULL; // first char which needs updating | ||
449 | char *last = last; // last char which needs updating | ||
450 | unsigned iy = i - G.y; | ||
451 | |||
452 | if (iy >= G.height) | ||
453 | break; | ||
454 | for (j = 0; j < G.remote.cols; j++, NEXT(old), NEXT(data)) { | ||
455 | unsigned jx = j - G.x; // if will catch j >= G.x too | ||
456 | |||
457 | if (jx < G.width && DATA(data) != DATA(old)) { | ||
458 | last = data; | ||
459 | if (!first) { | ||
460 | first = data; | ||
461 | gotoxy(jx, iy); | ||
462 | } | ||
463 | } | ||
464 | } | ||
465 | if (first) { | ||
466 | // Rewrite updated data on the local screen | ||
467 | for (; first <= last; NEXT(first)) | ||
468 | screen_char(first); | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | curmove(); | ||
473 | |||
474 | // Wait for local user keypresses | ||
475 | fflush_all(); | ||
476 | pfd.fd = G.kbd_fd; | ||
477 | pfd.events = POLLIN; | ||
478 | bytes_read = 0; | ||
479 | switch (poll(&pfd, 1, poll_timeout_ms)) { | ||
480 | char *k; | ||
481 | case -1: | ||
482 | if (errno != EINTR) | ||
483 | cleanup(1); | ||
484 | break; | ||
485 | case 0: | ||
486 | if (++G.nokeys >= 4) | ||
487 | G.nokeys = G.escape_count = 0; | ||
488 | break; | ||
489 | default: | ||
490 | // Read the keys pressed | ||
491 | k = keybuf + G.key_count; | ||
492 | bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count); | ||
493 | if (bytes_read < 0) | ||
494 | cleanup(1); | ||
495 | |||
496 | // Do exit processing | ||
497 | for (i = 0; i < bytes_read; i++) { | ||
498 | if (k[i] != '\033') | ||
499 | G.escape_count = 0; | ||
500 | else if (++G.escape_count >= 3) | ||
501 | cleanup(0); | ||
502 | } | ||
503 | } | ||
504 | poll_timeout_ms = 250; | ||
505 | |||
506 | // Insert all keys pressed into the virtual console's input | ||
507 | // buffer. Don't do this if the virtual console is in scan | ||
508 | // code mode - giving ASCII characters to a program expecting | ||
509 | // scan codes will confuse it. | ||
510 | if (!(option_mask32 & FLAG(v)) && G.escape_count == 0) { | ||
511 | int handle, result; | ||
512 | long kbd_mode; | ||
513 | |||
514 | G.key_count += bytes_read; | ||
515 | handle = xopen(tty_name, O_WRONLY); | ||
516 | result = ioctl(handle, KDGKBMODE, &kbd_mode); | ||
517 | if (result >= 0) { | ||
518 | char *p = keybuf; | ||
519 | |||
520 | if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) { | ||
521 | G.key_count = 0; // scan code mode | ||
522 | } | ||
523 | for (; G.key_count != 0; p++, G.key_count--) { | ||
524 | result = ioctl(handle, TIOCSTI, p); | ||
525 | if (result < 0) { | ||
526 | memmove(keybuf, p, G.key_count); | ||
527 | break; | ||
528 | } | ||
529 | // If there is an application on console which reacts | ||
530 | // to keypresses, we need to make our first sleep | ||
531 | // shorter to quickly redraw whatever it printed there. | ||
532 | poll_timeout_ms = 20; | ||
533 | } | ||
534 | } | ||
535 | // Close & re-open tty in case they have | ||
536 | // swapped virtual consoles | ||
537 | close(handle); | ||
538 | |||
539 | // We sometimes get spurious IO errors on the TTY | ||
540 | // as programs close and re-open it | ||
541 | if (result >= 0) | ||
542 | G.ioerror_count = 0; | ||
543 | else if (errno != EIO || ++G.ioerror_count > 4) | ||
544 | cleanup(1); | ||
545 | } | ||
546 | } /* while (1) */ | ||
547 | } | ||
diff --git a/miscutils/crond.c b/miscutils/crond.c index f51159233..66110bb85 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -17,56 +17,55 @@ | |||
17 | /* glibc frees previous setenv'ed value when we do next setenv() | 17 | /* glibc frees previous setenv'ed value when we do next setenv() |
18 | * of the same variable. uclibc does not do this! */ | 18 | * of the same variable. uclibc does not do this! */ |
19 | #if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */ | 19 | #if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */ |
20 | #define SETENV_LEAKS 0 | 20 | # define SETENV_LEAKS 0 |
21 | #else | 21 | #else |
22 | #define SETENV_LEAKS 1 | 22 | # define SETENV_LEAKS 1 |
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | 25 | ||
26 | #define TMPDIR CONFIG_FEATURE_CROND_DIR | 26 | #define TMPDIR CONFIG_FEATURE_CROND_DIR |
27 | #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" | 27 | #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" |
28 | #ifndef SENDMAIL | 28 | #ifndef SENDMAIL |
29 | #define SENDMAIL "sendmail" | 29 | # define SENDMAIL "sendmail" |
30 | #endif | 30 | #endif |
31 | #ifndef SENDMAIL_ARGS | 31 | #ifndef SENDMAIL_ARGS |
32 | #define SENDMAIL_ARGS "-ti", NULL | 32 | # define SENDMAIL_ARGS "-ti" |
33 | #endif | 33 | #endif |
34 | #ifndef CRONUPDATE | 34 | #ifndef CRONUPDATE |
35 | #define CRONUPDATE "cron.update" | 35 | # define CRONUPDATE "cron.update" |
36 | #endif | 36 | #endif |
37 | #ifndef MAXLINES | 37 | #ifndef MAXLINES |
38 | #define MAXLINES 256 /* max lines in non-root crontabs */ | 38 | # define MAXLINES 256 /* max lines in non-root crontabs */ |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | 41 | ||
42 | typedef struct CronFile { | 42 | typedef struct CronFile { |
43 | struct CronFile *cf_Next; | 43 | struct CronFile *cf_next; |
44 | struct CronLine *cf_LineBase; | 44 | struct CronLine *cf_lines; |
45 | char *cf_User; /* username */ | 45 | char *cf_username; |
46 | smallint cf_Ready; /* bool: one or more jobs ready */ | 46 | smallint cf_wants_starting; /* bool: one or more jobs ready */ |
47 | smallint cf_Running; /* bool: one or more jobs running */ | 47 | smallint cf_has_running; /* bool: one or more jobs running */ |
48 | smallint cf_Deleted; /* marked for deletion, ignore */ | 48 | smallint cf_deleted; /* marked for deletion (but still has running jobs) */ |
49 | } CronFile; | 49 | } CronFile; |
50 | 50 | ||
51 | typedef struct CronLine { | 51 | typedef struct CronLine { |
52 | struct CronLine *cl_Next; | 52 | struct CronLine *cl_next; |
53 | char *cl_Shell; /* shell command */ | 53 | char *cl_cmd; /* shell command */ |
54 | pid_t cl_Pid; /* running pid, 0, or armed (-1) */ | 54 | pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */ |
55 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 55 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
56 | int cl_MailPos; /* 'empty file' size */ | 56 | int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ |
57 | smallint cl_MailFlag; /* running pid is for mail */ | 57 | char *cl_mailto; /* whom to mail results, may be NULL */ |
58 | char *cl_MailTo; /* whom to mail results */ | ||
59 | #endif | 58 | #endif |
60 | /* ordered by size, not in natural order. makes code smaller: */ | 59 | /* ordered by size, not in natural order. makes code smaller: */ |
61 | char cl_Dow[7]; /* 0-6, beginning sunday */ | 60 | char cl_Dow[7]; /* 0-6, beginning sunday */ |
62 | char cl_Mons[12]; /* 0-11 */ | 61 | char cl_Mons[12]; /* 0-11 */ |
63 | char cl_Hrs[24]; /* 0-23 */ | 62 | char cl_Hrs[24]; /* 0-23 */ |
64 | char cl_Days[32]; /* 1-31 */ | 63 | char cl_Days[32]; /* 1-31 */ |
65 | char cl_Mins[60]; /* 0-59 */ | 64 | char cl_Mins[60]; /* 0-59 */ |
66 | } CronLine; | 65 | } CronLine; |
67 | 66 | ||
68 | 67 | ||
69 | #define DaemonUid 0 | 68 | #define DAEMON_UID 0 |
70 | 69 | ||
71 | 70 | ||
72 | enum { | 71 | enum { |
@@ -79,49 +78,30 @@ enum { | |||
79 | OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, | 78 | OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, |
80 | }; | 79 | }; |
81 | #if ENABLE_FEATURE_CROND_D | 80 | #if ENABLE_FEATURE_CROND_D |
82 | #define DebugOpt (option_mask32 & OPT_d) | 81 | # define DebugOpt (option_mask32 & OPT_d) |
83 | #else | 82 | #else |
84 | #define DebugOpt 0 | 83 | # define DebugOpt 0 |
85 | #endif | 84 | #endif |
86 | 85 | ||
87 | 86 | ||
88 | struct globals { | 87 | struct globals { |
89 | unsigned LogLevel; /* = 8; */ | 88 | unsigned log_level; /* = 8; */ |
90 | const char *LogFile; | 89 | time_t crontab_dir_mtime; |
91 | const char *CDir; /* = CRONTABS; */ | 90 | const char *log_filename; |
92 | CronFile *FileBase; | 91 | const char *crontab_dir_name; /* = CRONTABS; */ |
92 | CronFile *cron_files; | ||
93 | #if SETENV_LEAKS | 93 | #if SETENV_LEAKS |
94 | char *env_var_user; | 94 | char *env_var_user; |
95 | char *env_var_home; | 95 | char *env_var_home; |
96 | #endif | 96 | #endif |
97 | } FIX_ALIASING; | 97 | } FIX_ALIASING; |
98 | #define G (*(struct globals*)&bb_common_bufsiz1) | 98 | #define G (*(struct globals*)&bb_common_bufsiz1) |
99 | #define LogLevel (G.LogLevel ) | ||
100 | #define LogFile (G.LogFile ) | ||
101 | #define CDir (G.CDir ) | ||
102 | #define FileBase (G.FileBase ) | ||
103 | #define env_var_user (G.env_var_user ) | ||
104 | #define env_var_home (G.env_var_home ) | ||
105 | #define INIT_G() do { \ | 99 | #define INIT_G() do { \ |
106 | LogLevel = 8; \ | 100 | G.log_level = 8; \ |
107 | CDir = CRONTABS; \ | 101 | G.crontab_dir_name = CRONTABS; \ |
108 | } while (0) | 102 | } while (0) |
109 | 103 | ||
110 | 104 | ||
111 | static void CheckUpdates(void); | ||
112 | static void SynchronizeDir(void); | ||
113 | static int TestJobs(time_t t1, time_t t2); | ||
114 | static void RunJobs(void); | ||
115 | static int CheckJobs(void); | ||
116 | static void RunJob(const char *user, CronLine *line); | ||
117 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | ||
118 | static void EndJob(const char *user, CronLine *line); | ||
119 | #else | ||
120 | #define EndJob(user, line) ((line)->cl_Pid = 0) | ||
121 | #endif | ||
122 | static void DeleteFile(const char *userName); | ||
123 | |||
124 | |||
125 | /* 0 is the most verbose, default 8 */ | 105 | /* 0 is the most verbose, default 8 */ |
126 | #define LVL5 "\x05" | 106 | #define LVL5 "\x05" |
127 | #define LVL7 "\x07" | 107 | #define LVL7 "\x07" |
@@ -138,12 +118,12 @@ static void crondlog(const char *ctl, ...) | |||
138 | int level = (ctl[0] & 0x1f); | 118 | int level = (ctl[0] & 0x1f); |
139 | 119 | ||
140 | va_start(va, ctl); | 120 | va_start(va, ctl); |
141 | if (level >= (int)LogLevel) { | 121 | if (level >= (int)G.log_level) { |
142 | /* Debug mode: all to (non-redirected) stderr, */ | 122 | /* Debug mode: all to (non-redirected) stderr, */ |
143 | /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ | 123 | /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ |
144 | if (!DebugOpt && LogFile) { | 124 | if (!DebugOpt && G.log_filename) { |
145 | /* Otherwise (log to file): we reopen log file at every write: */ | 125 | /* Otherwise (log to file): we reopen log file at every write: */ |
146 | int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); | 126 | int logfd = open3_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND, 0666); |
147 | if (logfd >= 0) | 127 | if (logfd >= 0) |
148 | xmove_fd(logfd, STDERR_FILENO); | 128 | xmove_fd(logfd, STDERR_FILENO); |
149 | } | 129 | } |
@@ -163,142 +143,6 @@ static void crondlog(const char *ctl, ...) | |||
163 | exit(20); | 143 | exit(20); |
164 | } | 144 | } |
165 | 145 | ||
166 | int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
167 | int crond_main(int argc UNUSED_PARAM, char **argv) | ||
168 | { | ||
169 | unsigned opts; | ||
170 | |||
171 | INIT_G(); | ||
172 | |||
173 | /* "-b after -f is ignored", and so on for every pair a-b */ | ||
174 | opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") | ||
175 | ":l+:d+"; /* -l and -d have numeric param */ | ||
176 | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), | ||
177 | &LogLevel, &LogFile, &CDir | ||
178 | IF_FEATURE_CROND_D(,&LogLevel)); | ||
179 | /* both -d N and -l N set the same variable: LogLevel */ | ||
180 | |||
181 | if (!(opts & OPT_f)) { | ||
182 | /* close stdin, stdout, stderr. | ||
183 | * close unused descriptors - don't need them. */ | ||
184 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); | ||
185 | } | ||
186 | |||
187 | if (!(opts & OPT_d) && LogFile == NULL) { | ||
188 | /* logging to syslog */ | ||
189 | openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); | ||
190 | logmode = LOGMODE_SYSLOG; | ||
191 | } | ||
192 | |||
193 | xchdir(CDir); | ||
194 | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ | ||
195 | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ | ||
196 | crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); | ||
197 | SynchronizeDir(); | ||
198 | |||
199 | /* main loop - synchronize to 1 second after the minute, minimum sleep | ||
200 | * of 1 second. */ | ||
201 | { | ||
202 | time_t t1 = time(NULL); | ||
203 | int rescan = 60; | ||
204 | int sleep_time = 60; | ||
205 | |||
206 | write_pidfile("/var/run/crond.pid"); | ||
207 | for (;;) { | ||
208 | time_t t2; | ||
209 | long dt; | ||
210 | |||
211 | sleep((sleep_time + 1) - (time(NULL) % sleep_time)); | ||
212 | |||
213 | t2 = time(NULL); | ||
214 | dt = (long)t2 - (long)t1; | ||
215 | |||
216 | /* | ||
217 | * The file 'cron.update' is checked to determine new cron | ||
218 | * jobs. The directory is rescanned once an hour to deal | ||
219 | * with any screwups. | ||
220 | * | ||
221 | * check for disparity. Disparities over an hour either way | ||
222 | * result in resynchronization. A reverse-indexed disparity | ||
223 | * less then an hour causes us to effectively sleep until we | ||
224 | * match the original time (i.e. no re-execution of jobs that | ||
225 | * have just been run). A forward-indexed disparity less then | ||
226 | * an hour causes intermediate jobs to be run, but only once | ||
227 | * in the worst case. | ||
228 | * | ||
229 | * when running jobs, the inequality used is greater but not | ||
230 | * equal to t1, and less then or equal to t2. | ||
231 | */ | ||
232 | if (--rescan == 0) { | ||
233 | rescan = 60; | ||
234 | SynchronizeDir(); | ||
235 | } | ||
236 | CheckUpdates(); | ||
237 | if (DebugOpt) | ||
238 | crondlog(LVL5 "wakeup dt=%ld", dt); | ||
239 | if (dt < -60 * 60 || dt > 60 * 60) { | ||
240 | crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); | ||
241 | } else if (dt > 0) { | ||
242 | TestJobs(t1, t2); | ||
243 | RunJobs(); | ||
244 | sleep(5); | ||
245 | if (CheckJobs() > 0) { | ||
246 | sleep_time = 10; | ||
247 | } else { | ||
248 | sleep_time = 60; | ||
249 | } | ||
250 | } | ||
251 | t1 = t2; | ||
252 | } /* for (;;) */ | ||
253 | } | ||
254 | |||
255 | return 0; /* not reached */ | ||
256 | } | ||
257 | |||
258 | #if SETENV_LEAKS | ||
259 | /* We set environment *before* vfork (because we want to use vfork), | ||
260 | * so we cannot use setenv() - repeated calls to setenv() may leak memory! | ||
261 | * Using putenv(), and freeing memory after unsetenv() won't leak */ | ||
262 | static void safe_setenv(char **pvar_val, const char *var, const char *val) | ||
263 | { | ||
264 | char *var_val = *pvar_val; | ||
265 | |||
266 | if (var_val) { | ||
267 | bb_unsetenv(var_val); | ||
268 | free(var_val); | ||
269 | } | ||
270 | *pvar_val = xasprintf("%s=%s", var, val); | ||
271 | putenv(*pvar_val); | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | static void SetEnv(struct passwd *pas) | ||
276 | { | ||
277 | #if SETENV_LEAKS | ||
278 | safe_setenv(&env_var_user, "USER", pas->pw_name); | ||
279 | safe_setenv(&env_var_home, "HOME", pas->pw_dir); | ||
280 | /* if we want to set user's shell instead: */ | ||
281 | /*safe_setenv(env_var_user, "SHELL", pas->pw_shell);*/ | ||
282 | #else | ||
283 | xsetenv("USER", pas->pw_name); | ||
284 | xsetenv("HOME", pas->pw_dir); | ||
285 | #endif | ||
286 | /* currently, we use constant one: */ | ||
287 | /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ | ||
288 | } | ||
289 | |||
290 | static void ChangeUser(struct passwd *pas) | ||
291 | { | ||
292 | /* careful: we're after vfork! */ | ||
293 | change_identity(pas); /* - initgroups, setgid, setuid */ | ||
294 | if (chdir(pas->pw_dir) < 0) { | ||
295 | crondlog(WARN9 "chdir(%s)", pas->pw_dir); | ||
296 | if (chdir(TMPDIR) < 0) { | ||
297 | crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | static const char DowAry[] ALIGN1 = | 146 | static const char DowAry[] ALIGN1 = |
303 | "sun""mon""tue""wed""thu""fri""sat" | 147 | "sun""mon""tue""wed""thu""fri""sat" |
304 | /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */ | 148 | /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */ |
@@ -415,7 +259,7 @@ static void ParseField(char *user, char *ary, int modvalue, int off, | |||
415 | return; | 259 | return; |
416 | } | 260 | } |
417 | 261 | ||
418 | if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */ | 262 | if (DebugOpt && (G.log_level <= 5)) { /* like LVL5 */ |
419 | /* can't use crondlog, it inserts '\n' */ | 263 | /* can't use crondlog, it inserts '\n' */ |
420 | int i; | 264 | int i; |
421 | for (i = 0; i < modvalue; ++i) | 265 | for (i = 0; i < modvalue; ++i) |
@@ -450,7 +294,60 @@ static void FixDayDow(CronLine *line) | |||
450 | } | 294 | } |
451 | } | 295 | } |
452 | 296 | ||
453 | static void SynchronizeFile(const char *fileName) | 297 | /* |
298 | * delete_cronfile() - delete user database | ||
299 | * | ||
300 | * Note: multiple entries for same user may exist if we were unable to | ||
301 | * completely delete a database due to running processes. | ||
302 | */ | ||
303 | //FIXME: we will start a new job even if the old job is running | ||
304 | //if crontab was reloaded: crond thinks that "new" job is different from "old" | ||
305 | //even if they are in fact completely the same. Example | ||
306 | //Crontab was: | ||
307 | // 0-59 * * * * job1 | ||
308 | // 0-59 * * * * long_running_job2 | ||
309 | //User edits crontab to: | ||
310 | // 0-59 * * * * job1_updated | ||
311 | // 0-59 * * * * long_running_job2 | ||
312 | //Bug: crond can now start another long_running_job2 even if old one | ||
313 | //is still running. | ||
314 | //OTOH most other versions of cron do not wait for job termination anyway, | ||
315 | //they end up with multiple copies of jobs if they don't terminate soon enough. | ||
316 | static void delete_cronfile(const char *userName) | ||
317 | { | ||
318 | CronFile **pfile = &G.cron_files; | ||
319 | CronFile *file; | ||
320 | |||
321 | while ((file = *pfile) != NULL) { | ||
322 | if (strcmp(userName, file->cf_username) == 0) { | ||
323 | CronLine **pline = &file->cf_lines; | ||
324 | CronLine *line; | ||
325 | |||
326 | file->cf_has_running = 0; | ||
327 | file->cf_deleted = 1; | ||
328 | |||
329 | while ((line = *pline) != NULL) { | ||
330 | if (line->cl_pid > 0) { | ||
331 | file->cf_has_running = 1; | ||
332 | pline = &line->cl_next; | ||
333 | } else { | ||
334 | *pline = line->cl_next; | ||
335 | free(line->cl_cmd); | ||
336 | free(line); | ||
337 | } | ||
338 | } | ||
339 | if (file->cf_has_running == 0) { | ||
340 | *pfile = file->cf_next; | ||
341 | free(file->cf_username); | ||
342 | free(file); | ||
343 | continue; | ||
344 | } | ||
345 | } | ||
346 | pfile = &file->cf_next; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static void load_crontab(const char *fileName) | ||
454 | { | 351 | { |
455 | struct parser_t *parser; | 352 | struct parser_t *parser; |
456 | struct stat sbuf; | 353 | struct stat sbuf; |
@@ -460,23 +357,26 @@ static void SynchronizeFile(const char *fileName) | |||
460 | char *mailTo = NULL; | 357 | char *mailTo = NULL; |
461 | #endif | 358 | #endif |
462 | 359 | ||
463 | if (!fileName) | 360 | delete_cronfile(fileName); |
361 | |||
362 | if (!getpwnam(fileName)) { | ||
363 | crondlog(LVL7 "ignoring file '%s' (no such user)", fileName); | ||
464 | return; | 364 | return; |
365 | } | ||
465 | 366 | ||
466 | DeleteFile(fileName); | ||
467 | parser = config_open(fileName); | 367 | parser = config_open(fileName); |
468 | if (!parser) | 368 | if (!parser) |
469 | return; | 369 | return; |
470 | 370 | ||
471 | maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES; | 371 | maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES; |
472 | 372 | ||
473 | if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { | 373 | if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) { |
474 | CronFile *file = xzalloc(sizeof(CronFile)); | 374 | CronFile *file = xzalloc(sizeof(CronFile)); |
475 | CronLine **pline; | 375 | CronLine **pline; |
476 | int n; | 376 | int n; |
477 | 377 | ||
478 | file->cf_User = xstrdup(fileName); | 378 | file->cf_username = xstrdup(fileName); |
479 | pline = &file->cf_LineBase; | 379 | pline = &file->cf_lines; |
480 | 380 | ||
481 | while (1) { | 381 | while (1) { |
482 | CronLine *line; | 382 | CronLine *line; |
@@ -503,11 +403,11 @@ static void SynchronizeFile(const char *fileName) | |||
503 | continue; | 403 | continue; |
504 | *pline = line = xzalloc(sizeof(*line)); | 404 | *pline = line = xzalloc(sizeof(*line)); |
505 | /* parse date ranges */ | 405 | /* parse date ranges */ |
506 | ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]); | 406 | ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]); |
507 | ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]); | 407 | ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]); |
508 | ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, tokens[2]); | 408 | ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]); |
509 | ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, tokens[3]); | 409 | ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]); |
510 | ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, tokens[4]); | 410 | ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]); |
511 | /* | 411 | /* |
512 | * fix days and dow - if one is not "*" and the other | 412 | * fix days and dow - if one is not "*" and the other |
513 | * is "*", the other is set to 0, and vise-versa | 413 | * is "*", the other is set to 0, and vise-versa |
@@ -515,20 +415,20 @@ static void SynchronizeFile(const char *fileName) | |||
515 | FixDayDow(line); | 415 | FixDayDow(line); |
516 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 416 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
517 | /* copy mailto (can be NULL) */ | 417 | /* copy mailto (can be NULL) */ |
518 | line->cl_MailTo = xstrdup(mailTo); | 418 | line->cl_mailto = xstrdup(mailTo); |
519 | #endif | 419 | #endif |
520 | /* copy command */ | 420 | /* copy command */ |
521 | line->cl_Shell = xstrdup(tokens[5]); | 421 | line->cl_cmd = xstrdup(tokens[5]); |
522 | if (DebugOpt) { | 422 | if (DebugOpt) { |
523 | crondlog(LVL5 " command:%s", tokens[5]); | 423 | crondlog(LVL5 " command:%s", tokens[5]); |
524 | } | 424 | } |
525 | pline = &line->cl_Next; | 425 | pline = &line->cl_next; |
526 | //bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); | 426 | //bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); |
527 | } | 427 | } |
528 | *pline = NULL; | 428 | *pline = NULL; |
529 | 429 | ||
530 | file->cf_Next = FileBase; | 430 | file->cf_next = G.cron_files; |
531 | FileBase = file; | 431 | G.cron_files = file; |
532 | 432 | ||
533 | if (maxLines == 0) { | 433 | if (maxLines == 0) { |
534 | crondlog(WARN9 "user %s: too many lines", fileName); | 434 | crondlog(WARN9 "user %s: too many lines", fileName); |
@@ -537,7 +437,7 @@ static void SynchronizeFile(const char *fileName) | |||
537 | config_close(parser); | 437 | config_close(parser); |
538 | } | 438 | } |
539 | 439 | ||
540 | static void CheckUpdates(void) | 440 | static void process_cron_update_file(void) |
541 | { | 441 | { |
542 | FILE *fi; | 442 | FILE *fi; |
543 | char buf[256]; | 443 | char buf[256]; |
@@ -547,36 +447,34 @@ static void CheckUpdates(void) | |||
547 | unlink(CRONUPDATE); | 447 | unlink(CRONUPDATE); |
548 | while (fgets(buf, sizeof(buf), fi) != NULL) { | 448 | while (fgets(buf, sizeof(buf), fi) != NULL) { |
549 | /* use first word only */ | 449 | /* use first word only */ |
550 | SynchronizeFile(strtok(buf, " \t\r\n")); | 450 | skip_non_whitespace(buf)[0] = '\0'; |
451 | load_crontab(buf); | ||
551 | } | 452 | } |
552 | fclose(fi); | 453 | fclose(fi); |
553 | } | 454 | } |
554 | } | 455 | } |
555 | 456 | ||
556 | static void SynchronizeDir(void) | 457 | static void rescan_crontab_dir(void) |
557 | { | 458 | { |
558 | CronFile *file; | 459 | CronFile *file; |
559 | /* Attempt to delete the database. */ | 460 | |
461 | /* Delete all files until we only have ones with running jobs (or none) */ | ||
560 | again: | 462 | again: |
561 | for (file = FileBase; file; file = file->cf_Next) { | 463 | for (file = G.cron_files; file; file = file->cf_next) { |
562 | if (!file->cf_Deleted) { | 464 | if (!file->cf_deleted) { |
563 | DeleteFile(file->cf_User); | 465 | delete_cronfile(file->cf_username); |
564 | goto again; | 466 | goto again; |
565 | } | 467 | } |
566 | } | 468 | } |
567 | 469 | ||
568 | /* | 470 | /* Remove cron update file */ |
569 | * Remove cron update file | ||
570 | * | ||
571 | * Re-chdir, in case directory was renamed & deleted, or otherwise | ||
572 | * screwed up. | ||
573 | * | ||
574 | * scan directory and add associated users | ||
575 | */ | ||
576 | unlink(CRONUPDATE); | 471 | unlink(CRONUPDATE); |
577 | if (chdir(CDir) < 0) { | 472 | /* Re-chdir, in case directory was renamed & deleted */ |
578 | crondlog(DIE9 "chdir(%s)", CDir); | 473 | if (chdir(G.crontab_dir_name) < 0) { |
474 | crondlog(DIE9 "chdir(%s)", G.crontab_dir_name); | ||
579 | } | 475 | } |
476 | |||
477 | /* Scan directory and add associated users */ | ||
580 | { | 478 | { |
581 | DIR *dir = opendir("."); | 479 | DIR *dir = opendir("."); |
582 | struct dirent *den; | 480 | struct dirent *den; |
@@ -587,184 +485,63 @@ static void SynchronizeDir(void) | |||
587 | if (strchr(den->d_name, '.') != NULL) { | 485 | if (strchr(den->d_name, '.') != NULL) { |
588 | continue; | 486 | continue; |
589 | } | 487 | } |
590 | if (getpwnam(den->d_name)) { | 488 | load_crontab(den->d_name); |
591 | SynchronizeFile(den->d_name); | ||
592 | } else { | ||
593 | crondlog(LVL7 "ignoring %s", den->d_name); | ||
594 | } | ||
595 | } | 489 | } |
596 | closedir(dir); | 490 | closedir(dir); |
597 | } | 491 | } |
598 | } | 492 | } |
599 | 493 | ||
600 | /* | 494 | #if SETENV_LEAKS |
601 | * DeleteFile() - delete user database | 495 | /* We set environment *before* vfork (because we want to use vfork), |
602 | * | 496 | * so we cannot use setenv() - repeated calls to setenv() may leak memory! |
603 | * Note: multiple entries for same user may exist if we were unable to | 497 | * Using putenv(), and freeing memory after unsetenv() won't leak */ |
604 | * completely delete a database due to running processes. | 498 | static void safe_setenv(char **pvar_val, const char *var, const char *val) |
605 | */ | ||
606 | static void DeleteFile(const char *userName) | ||
607 | { | ||
608 | CronFile **pfile = &FileBase; | ||
609 | CronFile *file; | ||
610 | |||
611 | while ((file = *pfile) != NULL) { | ||
612 | if (strcmp(userName, file->cf_User) == 0) { | ||
613 | CronLine **pline = &file->cf_LineBase; | ||
614 | CronLine *line; | ||
615 | |||
616 | file->cf_Running = 0; | ||
617 | file->cf_Deleted = 1; | ||
618 | |||
619 | while ((line = *pline) != NULL) { | ||
620 | if (line->cl_Pid > 0) { | ||
621 | file->cf_Running = 1; | ||
622 | pline = &line->cl_Next; | ||
623 | } else { | ||
624 | *pline = line->cl_Next; | ||
625 | free(line->cl_Shell); | ||
626 | free(line); | ||
627 | } | ||
628 | } | ||
629 | if (file->cf_Running == 0) { | ||
630 | *pfile = file->cf_Next; | ||
631 | free(file->cf_User); | ||
632 | free(file); | ||
633 | } else { | ||
634 | pfile = &file->cf_Next; | ||
635 | } | ||
636 | } else { | ||
637 | pfile = &file->cf_Next; | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * TestJobs() | ||
644 | * | ||
645 | * determine which jobs need to be run. Under normal conditions, the | ||
646 | * period is about a minute (one scan). Worst case it will be one | ||
647 | * hour (60 scans). | ||
648 | */ | ||
649 | static int TestJobs(time_t t1, time_t t2) | ||
650 | { | 499 | { |
651 | int nJobs = 0; | 500 | char *var_val = *pvar_val; |
652 | time_t t; | ||
653 | |||
654 | /* Find jobs > t1 and <= t2 */ | ||
655 | |||
656 | for (t = t1 - t1 % 60; t <= t2; t += 60) { | ||
657 | struct tm *ptm; | ||
658 | CronFile *file; | ||
659 | CronLine *line; | ||
660 | |||
661 | if (t <= t1) | ||
662 | continue; | ||
663 | 501 | ||
664 | ptm = localtime(&t); | 502 | if (var_val) { |
665 | for (file = FileBase; file; file = file->cf_Next) { | 503 | bb_unsetenv_and_free(var_val); |
666 | if (DebugOpt) | ||
667 | crondlog(LVL5 "file %s:", file->cf_User); | ||
668 | if (file->cf_Deleted) | ||
669 | continue; | ||
670 | for (line = file->cf_LineBase; line; line = line->cl_Next) { | ||
671 | if (DebugOpt) | ||
672 | crondlog(LVL5 " line %s", line->cl_Shell); | ||
673 | if (line->cl_Mins[ptm->tm_min] && line->cl_Hrs[ptm->tm_hour] | ||
674 | && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday]) | ||
675 | && line->cl_Mons[ptm->tm_mon] | ||
676 | ) { | ||
677 | if (DebugOpt) { | ||
678 | crondlog(LVL5 " job: %d %s", | ||
679 | (int)line->cl_Pid, line->cl_Shell); | ||
680 | } | ||
681 | if (line->cl_Pid > 0) { | ||
682 | crondlog(LVL8 "user %s: process already running: %s", | ||
683 | file->cf_User, line->cl_Shell); | ||
684 | } else if (line->cl_Pid == 0) { | ||
685 | line->cl_Pid = -1; | ||
686 | file->cf_Ready = 1; | ||
687 | ++nJobs; | ||
688 | } | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | } | 504 | } |
693 | return nJobs; | 505 | *pvar_val = xasprintf("%s=%s", var, val); |
506 | putenv(*pvar_val); | ||
694 | } | 507 | } |
508 | #endif | ||
695 | 509 | ||
696 | static void RunJobs(void) | 510 | static void set_env_vars(struct passwd *pas) |
697 | { | 511 | { |
698 | CronFile *file; | 512 | #if SETENV_LEAKS |
699 | CronLine *line; | 513 | safe_setenv(&G.env_var_user, "USER", pas->pw_name); |
700 | 514 | safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); | |
701 | for (file = FileBase; file; file = file->cf_Next) { | 515 | /* if we want to set user's shell instead: */ |
702 | if (!file->cf_Ready) | 516 | /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ |
703 | continue; | 517 | #else |
704 | 518 | xsetenv("USER", pas->pw_name); | |
705 | file->cf_Ready = 0; | 519 | xsetenv("HOME", pas->pw_dir); |
706 | for (line = file->cf_LineBase; line; line = line->cl_Next) { | 520 | #endif |
707 | if (line->cl_Pid >= 0) | 521 | /* currently, we use constant one: */ |
708 | continue; | 522 | /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ |
709 | |||
710 | RunJob(file->cf_User, line); | ||
711 | crondlog(LVL8 "USER %s pid %3d cmd %s", | ||
712 | file->cf_User, (int)line->cl_Pid, line->cl_Shell); | ||
713 | if (line->cl_Pid < 0) { | ||
714 | file->cf_Ready = 1; | ||
715 | } else if (line->cl_Pid > 0) { | ||
716 | file->cf_Running = 1; | ||
717 | } | ||
718 | } | ||
719 | } | ||
720 | } | 523 | } |
721 | 524 | ||
722 | /* | 525 | static void change_user(struct passwd *pas) |
723 | * CheckJobs() - check for job completion | ||
724 | * | ||
725 | * Check for job completion, return number of jobs still running after | ||
726 | * all done. | ||
727 | */ | ||
728 | static int CheckJobs(void) | ||
729 | { | 526 | { |
730 | CronFile *file; | 527 | /* careful: we're after vfork! */ |
731 | CronLine *line; | 528 | change_identity(pas); /* - initgroups, setgid, setuid */ |
732 | int nStillRunning = 0; | 529 | if (chdir(pas->pw_dir) < 0) { |
733 | 530 | crondlog(WARN9 "chdir(%s)", pas->pw_dir); | |
734 | for (file = FileBase; file; file = file->cf_Next) { | 531 | if (chdir(TMPDIR) < 0) { |
735 | if (file->cf_Running) { | 532 | crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ |
736 | file->cf_Running = 0; | ||
737 | |||
738 | for (line = file->cf_LineBase; line; line = line->cl_Next) { | ||
739 | int status, r; | ||
740 | if (line->cl_Pid <= 0) | ||
741 | continue; | ||
742 | |||
743 | r = waitpid(line->cl_Pid, &status, WNOHANG); | ||
744 | if (r < 0 || r == line->cl_Pid) { | ||
745 | EndJob(file->cf_User, line); | ||
746 | if (line->cl_Pid) { | ||
747 | file->cf_Running = 1; | ||
748 | } | ||
749 | } else if (r == 0) { | ||
750 | file->cf_Running = 1; | ||
751 | } | ||
752 | } | ||
753 | } | 533 | } |
754 | nStillRunning += file->cf_Running; | ||
755 | } | 534 | } |
756 | return nStillRunning; | ||
757 | } | 535 | } |
758 | 536 | ||
759 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | ||
760 | |||
761 | // TODO: sendmail should be _run-time_ option, not compile-time! | 537 | // TODO: sendmail should be _run-time_ option, not compile-time! |
538 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | ||
762 | 539 | ||
763 | static void | 540 | static pid_t |
764 | ForkJob(const char *user, CronLine *line, int mailFd, | 541 | fork_job(const char *user, int mailFd, |
765 | const char *prog, const char *cmd, const char *arg, | 542 | const char *prog, |
766 | const char *mail_filename) | 543 | const char *shell_cmd /* if NULL, we run sendmail */ |
767 | { | 544 | ) { |
768 | struct passwd *pas; | 545 | struct passwd *pas; |
769 | pid_t pid; | 546 | pid_t pid; |
770 | 547 | ||
@@ -774,48 +551,36 @@ ForkJob(const char *user, CronLine *line, int mailFd, | |||
774 | crondlog(WARN9 "can't get uid for %s", user); | 551 | crondlog(WARN9 "can't get uid for %s", user); |
775 | goto err; | 552 | goto err; |
776 | } | 553 | } |
777 | SetEnv(pas); | 554 | set_env_vars(pas); |
778 | 555 | ||
779 | pid = vfork(); | 556 | pid = vfork(); |
780 | if (pid == 0) { | 557 | if (pid == 0) { |
781 | /* CHILD */ | 558 | /* CHILD */ |
782 | /* change running state to the user in question */ | 559 | /* initgroups, setgid, setuid, and chdir to home or TMPDIR */ |
783 | ChangeUser(pas); | 560 | change_user(pas); |
784 | if (DebugOpt) { | 561 | if (DebugOpt) { |
785 | crondlog(LVL5 "child running %s", prog); | 562 | crondlog(LVL5 "child running %s", prog); |
786 | } | 563 | } |
787 | if (mailFd >= 0) { | 564 | if (mailFd >= 0) { |
788 | xmove_fd(mailFd, mail_filename ? 1 : 0); | 565 | xmove_fd(mailFd, shell_cmd ? 1 : 0); |
789 | dup2(1, 2); | 566 | dup2(1, 2); |
790 | } | 567 | } |
791 | /* crond 3.0pl1-100 puts tasks in separate process groups */ | 568 | /* crond 3.0pl1-100 puts tasks in separate process groups */ |
792 | bb_setpgrp(); | 569 | bb_setpgrp(); |
793 | execlp(prog, prog, cmd, arg, (char *) NULL); | 570 | execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL); |
794 | crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg); | 571 | crondlog(ERR20 "can't execute '%s' for user %s", prog, user); |
795 | if (mail_filename) { | 572 | if (shell_cmd) { |
796 | fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); | 573 | fdprintf(1, "Exec failed: %s -c %s\n", prog, shell_cmd); |
797 | } | 574 | } |
798 | _exit(EXIT_SUCCESS); | 575 | _exit(EXIT_SUCCESS); |
799 | } | 576 | } |
800 | 577 | ||
801 | line->cl_Pid = pid; | ||
802 | if (pid < 0) { | 578 | if (pid < 0) { |
803 | /* FORK FAILED */ | 579 | /* FORK FAILED */ |
804 | crondlog(ERR20 "can't vfork"); | 580 | crondlog(ERR20 "can't vfork"); |
805 | err: | 581 | err: |
806 | line->cl_Pid = 0; | 582 | pid = 0; |
807 | if (mail_filename) { | 583 | } /* else: PARENT, FORK SUCCESS */ |
808 | unlink(mail_filename); | ||
809 | } | ||
810 | } else if (mail_filename) { | ||
811 | /* PARENT, FORK SUCCESS | ||
812 | * rename mail-file based on pid of process | ||
813 | */ | ||
814 | char mailFile2[128]; | ||
815 | |||
816 | snprintf(mailFile2, sizeof(mailFile2), "%s/cron.%s.%d", TMPDIR, user, pid); | ||
817 | rename(mail_filename, mailFile2); // TODO: xrename? | ||
818 | } | ||
819 | 584 | ||
820 | /* | 585 | /* |
821 | * Close the mail file descriptor.. we can't just leave it open in | 586 | * Close the mail file descriptor.. we can't just leave it open in |
@@ -824,112 +589,120 @@ ForkJob(const char *user, CronLine *line, int mailFd, | |||
824 | if (mailFd >= 0) { | 589 | if (mailFd >= 0) { |
825 | close(mailFd); | 590 | close(mailFd); |
826 | } | 591 | } |
592 | return pid; | ||
827 | } | 593 | } |
828 | 594 | ||
829 | static void RunJob(const char *user, CronLine *line) | 595 | static void start_one_job(const char *user, CronLine *line) |
830 | { | 596 | { |
831 | char mailFile[128]; | 597 | char mailFile[128]; |
832 | int mailFd = -1; | 598 | int mailFd = -1; |
833 | 599 | ||
834 | line->cl_Pid = 0; | 600 | line->cl_pid = 0; |
835 | line->cl_MailFlag = 0; | 601 | line->cl_empty_mail_size = 0; |
836 | 602 | ||
837 | if (line->cl_MailTo) { | 603 | if (line->cl_mailto) { |
838 | /* open mail file - owner root so nobody can screw with it. */ | 604 | /* Open mail file (owner is root so nobody can screw with it) */ |
839 | snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid()); | 605 | snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid()); |
840 | mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); | 606 | mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); |
841 | 607 | ||
842 | if (mailFd >= 0) { | 608 | if (mailFd >= 0) { |
843 | line->cl_MailFlag = 1; | 609 | fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_mailto, |
844 | fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_MailTo, | 610 | line->cl_cmd); |
845 | line->cl_Shell); | 611 | line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR); |
846 | line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR); | ||
847 | } else { | 612 | } else { |
848 | crondlog(ERR20 "can't create mail file %s for user %s, " | 613 | crondlog(ERR20 "can't create mail file %s for user %s, " |
849 | "discarding output", mailFile, user); | 614 | "discarding output", mailFile, user); |
850 | } | 615 | } |
851 | } | 616 | } |
852 | 617 | ||
853 | ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); | 618 | line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd); |
619 | if (mailFd >= 0) { | ||
620 | if (line->cl_pid <= 0) { | ||
621 | unlink(mailFile); | ||
622 | } else { | ||
623 | /* rename mail-file based on pid of process */ | ||
624 | char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)line->cl_pid); | ||
625 | rename(mailFile, mailFile2); // TODO: xrename? | ||
626 | free(mailFile2); | ||
627 | } | ||
628 | } | ||
854 | } | 629 | } |
855 | 630 | ||
856 | /* | 631 | /* |
857 | * EndJob - called when job terminates and when mail terminates | 632 | * process_finished_job - called when job terminates and when mail terminates |
858 | */ | 633 | */ |
859 | static void EndJob(const char *user, CronLine *line) | 634 | static void process_finished_job(const char *user, CronLine *line) |
860 | { | 635 | { |
636 | pid_t pid; | ||
861 | int mailFd; | 637 | int mailFd; |
862 | char mailFile[128]; | 638 | char mailFile[128]; |
863 | struct stat sbuf; | 639 | struct stat sbuf; |
864 | 640 | ||
865 | /* No job */ | 641 | pid = line->cl_pid; |
866 | if (line->cl_Pid <= 0) { | 642 | line->cl_pid = 0; |
867 | line->cl_Pid = 0; | 643 | if (pid <= 0) { |
644 | /* No job */ | ||
868 | return; | 645 | return; |
869 | } | 646 | } |
870 | 647 | if (line->cl_empty_mail_size <= 0) { | |
871 | /* | 648 | /* End of job and no mail file, or end of sendmail job */ |
872 | * End of job and no mail file | ||
873 | * End of sendmail job | ||
874 | */ | ||
875 | snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); | ||
876 | line->cl_Pid = 0; | ||
877 | |||
878 | if (line->cl_MailFlag == 0) { | ||
879 | return; | 649 | return; |
880 | } | 650 | } |
881 | line->cl_MailFlag = 0; | ||
882 | 651 | ||
883 | /* | 652 | /* |
884 | * End of primary job - check for mail file. If size has increased and | 653 | * End of primary job - check for mail file. |
885 | * the file is still valid, we sendmail it. | 654 | * If size has changed and the file is still valid, we send it. |
886 | */ | 655 | */ |
656 | snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, (int)pid); | ||
887 | mailFd = open(mailFile, O_RDONLY); | 657 | mailFd = open(mailFile, O_RDONLY); |
888 | unlink(mailFile); | 658 | unlink(mailFile); |
889 | if (mailFd < 0) { | 659 | if (mailFd < 0) { |
890 | return; | 660 | return; |
891 | } | 661 | } |
892 | 662 | ||
893 | if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid | 663 | if (fstat(mailFd, &sbuf) < 0 |
894 | || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos | 664 | || sbuf.st_uid != DAEMON_UID |
665 | || sbuf.st_nlink != 0 | ||
666 | || sbuf.st_size == line->cl_empty_mail_size | ||
895 | || !S_ISREG(sbuf.st_mode) | 667 | || !S_ISREG(sbuf.st_mode) |
896 | ) { | 668 | ) { |
897 | close(mailFd); | 669 | close(mailFd); |
898 | return; | 670 | return; |
899 | } | 671 | } |
900 | if (line->cl_MailTo) | 672 | line->cl_empty_mail_size = 0; |
901 | ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); | 673 | /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ |
674 | line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL); | ||
902 | } | 675 | } |
903 | 676 | ||
904 | #else /* crond without sendmail */ | 677 | #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ |
905 | 678 | ||
906 | static void RunJob(const char *user, CronLine *line) | 679 | static void start_one_job(const char *user, CronLine *line) |
907 | { | 680 | { |
908 | struct passwd *pas; | 681 | struct passwd *pas; |
909 | pid_t pid; | 682 | pid_t pid; |
910 | 683 | ||
911 | /* prepare things before vfork */ | ||
912 | pas = getpwnam(user); | 684 | pas = getpwnam(user); |
913 | if (!pas) { | 685 | if (!pas) { |
914 | crondlog(WARN9 "can't get uid for %s", user); | 686 | crondlog(WARN9 "can't get uid for %s", user); |
915 | goto err; | 687 | goto err; |
916 | } | 688 | } |
917 | SetEnv(pas); | ||
918 | 689 | ||
919 | /* fork as the user in question and run program */ | 690 | /* Prepare things before vfork */ |
691 | set_env_vars(pas); | ||
692 | |||
693 | /* Fork as the user in question and run program */ | ||
920 | pid = vfork(); | 694 | pid = vfork(); |
921 | if (pid == 0) { | 695 | if (pid == 0) { |
922 | /* CHILD */ | 696 | /* CHILD */ |
923 | /* change running state to the user in question */ | 697 | /* initgroups, setgid, setuid, and chdir to home or TMPDIR */ |
924 | ChangeUser(pas); | 698 | change_user(pas); |
925 | if (DebugOpt) { | 699 | if (DebugOpt) { |
926 | crondlog(LVL5 "child running %s", DEFAULT_SHELL); | 700 | crondlog(LVL5 "child running %s", DEFAULT_SHELL); |
927 | } | 701 | } |
928 | /* crond 3.0pl1-100 puts tasks in separate process groups */ | 702 | /* crond 3.0pl1-100 puts tasks in separate process groups */ |
929 | bb_setpgrp(); | 703 | bb_setpgrp(); |
930 | execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, (char *) NULL); | 704 | execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_cmd, (char *) NULL); |
931 | crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, | 705 | crondlog(ERR20 "can't execute '%s' for user %s", DEFAULT_SHELL, user); |
932 | DEFAULT_SHELL, "-c", line->cl_Shell); | ||
933 | _exit(EXIT_SUCCESS); | 706 | _exit(EXIT_SUCCESS); |
934 | } | 707 | } |
935 | if (pid < 0) { | 708 | if (pid < 0) { |
@@ -938,7 +711,231 @@ static void RunJob(const char *user, CronLine *line) | |||
938 | err: | 711 | err: |
939 | pid = 0; | 712 | pid = 0; |
940 | } | 713 | } |
941 | line->cl_Pid = pid; | 714 | line->cl_pid = pid; |
942 | } | 715 | } |
943 | 716 | ||
944 | #endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */ | 717 | #define process_finished_job(user, line) ((line)->cl_pid = 0) |
718 | |||
719 | #endif /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ | ||
720 | |||
721 | /* | ||
722 | * Determine which jobs need to be run. Under normal conditions, the | ||
723 | * period is about a minute (one scan). Worst case it will be one | ||
724 | * hour (60 scans). | ||
725 | */ | ||
726 | static void flag_starting_jobs(time_t t1, time_t t2) | ||
727 | { | ||
728 | time_t t; | ||
729 | |||
730 | /* Find jobs > t1 and <= t2 */ | ||
731 | |||
732 | for (t = t1 - t1 % 60; t <= t2; t += 60) { | ||
733 | struct tm *ptm; | ||
734 | CronFile *file; | ||
735 | CronLine *line; | ||
736 | |||
737 | if (t <= t1) | ||
738 | continue; | ||
739 | |||
740 | ptm = localtime(&t); | ||
741 | for (file = G.cron_files; file; file = file->cf_next) { | ||
742 | if (DebugOpt) | ||
743 | crondlog(LVL5 "file %s:", file->cf_username); | ||
744 | if (file->cf_deleted) | ||
745 | continue; | ||
746 | for (line = file->cf_lines; line; line = line->cl_next) { | ||
747 | if (DebugOpt) | ||
748 | crondlog(LVL5 " line %s", line->cl_cmd); | ||
749 | if (line->cl_Mins[ptm->tm_min] | ||
750 | && line->cl_Hrs[ptm->tm_hour] | ||
751 | && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday]) | ||
752 | && line->cl_Mons[ptm->tm_mon] | ||
753 | ) { | ||
754 | if (DebugOpt) { | ||
755 | crondlog(LVL5 " job: %d %s", | ||
756 | (int)line->cl_pid, line->cl_cmd); | ||
757 | } | ||
758 | if (line->cl_pid > 0) { | ||
759 | crondlog(LVL8 "user %s: process already running: %s", | ||
760 | file->cf_username, line->cl_cmd); | ||
761 | } else if (line->cl_pid == 0) { | ||
762 | line->cl_pid = -1; | ||
763 | file->cf_wants_starting = 1; | ||
764 | } | ||
765 | } | ||
766 | } | ||
767 | } | ||
768 | } | ||
769 | } | ||
770 | |||
771 | static void start_jobs(void) | ||
772 | { | ||
773 | CronFile *file; | ||
774 | CronLine *line; | ||
775 | |||
776 | for (file = G.cron_files; file; file = file->cf_next) { | ||
777 | if (!file->cf_wants_starting) | ||
778 | continue; | ||
779 | |||
780 | file->cf_wants_starting = 0; | ||
781 | for (line = file->cf_lines; line; line = line->cl_next) { | ||
782 | pid_t pid; | ||
783 | if (line->cl_pid >= 0) | ||
784 | continue; | ||
785 | |||
786 | start_one_job(file->cf_username, line); | ||
787 | pid = line->cl_pid; | ||
788 | crondlog(LVL8 "USER %s pid %3d cmd %s", | ||
789 | file->cf_username, (int)pid, line->cl_cmd); | ||
790 | if (pid < 0) { | ||
791 | file->cf_wants_starting = 1; | ||
792 | } | ||
793 | if (pid > 0) { | ||
794 | file->cf_has_running = 1; | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | } | ||
799 | |||
800 | /* | ||
801 | * Check for job completion, return number of jobs still running after | ||
802 | * all done. | ||
803 | */ | ||
804 | static int check_completions(void) | ||
805 | { | ||
806 | CronFile *file; | ||
807 | CronLine *line; | ||
808 | int num_still_running = 0; | ||
809 | |||
810 | for (file = G.cron_files; file; file = file->cf_next) { | ||
811 | if (!file->cf_has_running) | ||
812 | continue; | ||
813 | |||
814 | file->cf_has_running = 0; | ||
815 | for (line = file->cf_lines; line; line = line->cl_next) { | ||
816 | int r; | ||
817 | |||
818 | if (line->cl_pid <= 0) | ||
819 | continue; | ||
820 | |||
821 | r = waitpid(line->cl_pid, NULL, WNOHANG); | ||
822 | if (r < 0 || r == line->cl_pid) { | ||
823 | process_finished_job(file->cf_username, line); | ||
824 | if (line->cl_pid == 0) { | ||
825 | /* sendmail was not started for it */ | ||
826 | continue; | ||
827 | } | ||
828 | /* else: sendmail was started, job is still running, fall thru */ | ||
829 | } | ||
830 | /* else: r == 0: "process is still running" */ | ||
831 | file->cf_has_running = 1; | ||
832 | } | ||
833 | //FIXME: if !file->cf_has_running && file->deleted: delete it! | ||
834 | //otherwise deleted entries will stay forever, right? | ||
835 | num_still_running += file->cf_has_running; | ||
836 | } | ||
837 | return num_still_running; | ||
838 | } | ||
839 | |||
840 | int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
841 | int crond_main(int argc UNUSED_PARAM, char **argv) | ||
842 | { | ||
843 | time_t t2; | ||
844 | int rescan; | ||
845 | int sleep_time; | ||
846 | unsigned opts; | ||
847 | |||
848 | INIT_G(); | ||
849 | |||
850 | /* "-b after -f is ignored", and so on for every pair a-b */ | ||
851 | opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") | ||
852 | ":l+:d+"; /* -l and -d have numeric param */ | ||
853 | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), | ||
854 | &G.log_level, &G.log_filename, &G.crontab_dir_name | ||
855 | IF_FEATURE_CROND_D(,&G.log_level)); | ||
856 | /* both -d N and -l N set the same variable: G.log_level */ | ||
857 | |||
858 | if (!(opts & OPT_f)) { | ||
859 | /* close stdin, stdout, stderr. | ||
860 | * close unused descriptors - don't need them. */ | ||
861 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); | ||
862 | } | ||
863 | |||
864 | if (!(opts & OPT_d) && G.log_filename == NULL) { | ||
865 | /* logging to syslog */ | ||
866 | openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); | ||
867 | logmode = LOGMODE_SYSLOG; | ||
868 | } | ||
869 | |||
870 | xchdir(G.crontab_dir_name); | ||
871 | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ | ||
872 | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ | ||
873 | crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.log_level); | ||
874 | rescan_crontab_dir(); | ||
875 | write_pidfile("/var/run/crond.pid"); | ||
876 | |||
877 | /* Main loop */ | ||
878 | t2 = time(NULL); | ||
879 | rescan = 60; | ||
880 | sleep_time = 60; | ||
881 | for (;;) { | ||
882 | struct stat sbuf; | ||
883 | time_t t1; | ||
884 | long dt; | ||
885 | |||
886 | t1 = t2; | ||
887 | |||
888 | /* Synchronize to 1 minute, minimum 1 second */ | ||
889 | sleep(sleep_time - (time(NULL) % sleep_time) + 1); | ||
890 | |||
891 | t2 = time(NULL); | ||
892 | dt = (long)t2 - (long)t1; | ||
893 | |||
894 | /* | ||
895 | * The file 'cron.update' is checked to determine new cron | ||
896 | * jobs. The directory is rescanned once an hour to deal | ||
897 | * with any screwups. | ||
898 | * | ||
899 | * Check for time jump. Disparities over an hour either way | ||
900 | * result in resynchronization. A negative disparity | ||
901 | * less than an hour causes us to effectively sleep until we | ||
902 | * match the original time (i.e. no re-execution of jobs that | ||
903 | * have just been run). A positive disparity less than | ||
904 | * an hour causes intermediate jobs to be run, but only once | ||
905 | * in the worst case. | ||
906 | * | ||
907 | * When running jobs, the inequality used is greater but not | ||
908 | * equal to t1, and less then or equal to t2. | ||
909 | */ | ||
910 | if (stat(G.crontab_dir_name, &sbuf) != 0) | ||
911 | sbuf.st_mtime = 0; /* force update (once) if dir was deleted */ | ||
912 | if (G.crontab_dir_mtime != sbuf.st_mtime) { | ||
913 | G.crontab_dir_mtime = sbuf.st_mtime; | ||
914 | rescan = 1; | ||
915 | } | ||
916 | if (--rescan == 0) { | ||
917 | rescan = 60; | ||
918 | rescan_crontab_dir(); | ||
919 | } | ||
920 | process_cron_update_file(); | ||
921 | if (DebugOpt) | ||
922 | crondlog(LVL5 "wakeup dt=%ld", dt); | ||
923 | if (dt < -60 * 60 || dt > 60 * 60) { | ||
924 | crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); | ||
925 | /* and we do not run any jobs in this case */ | ||
926 | } else if (dt > 0) { | ||
927 | /* Usual case: time advances forward, as expected */ | ||
928 | flag_starting_jobs(t1, t2); | ||
929 | start_jobs(); | ||
930 | if (check_completions() > 0) { | ||
931 | /* some jobs are still running */ | ||
932 | sleep_time = 10; | ||
933 | } else { | ||
934 | sleep_time = 60; | ||
935 | } | ||
936 | } | ||
937 | /* else: time jumped back, do not run any jobs */ | ||
938 | } /* for (;;) */ | ||
939 | |||
940 | return 0; /* not reached */ | ||
941 | } | ||
diff --git a/miscutils/crontab.c b/miscutils/crontab.c index 5557bc491..b8a5abc64 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c | |||
@@ -20,10 +20,8 @@ | |||
20 | static void edit_file(const struct passwd *pas, const char *file) | 20 | static void edit_file(const struct passwd *pas, const char *file) |
21 | { | 21 | { |
22 | const char *ptr; | 22 | const char *ptr; |
23 | int pid = vfork(); | 23 | int pid = xvfork(); |
24 | 24 | ||
25 | if (pid < 0) /* failure */ | ||
26 | bb_perror_msg_and_die("vfork"); | ||
27 | if (pid) { /* parent */ | 25 | if (pid) { /* parent */ |
28 | wait4pid(pid); | 26 | wait4pid(pid); |
29 | return; | 27 | return; |
@@ -51,9 +49,7 @@ static int open_as_user(const struct passwd *pas, const char *file) | |||
51 | pid_t pid; | 49 | pid_t pid; |
52 | char c; | 50 | char c; |
53 | 51 | ||
54 | pid = vfork(); | 52 | pid = xvfork(); |
55 | if (pid < 0) /* ERROR */ | ||
56 | bb_perror_msg_and_die("vfork"); | ||
57 | if (pid) { /* PARENT */ | 53 | if (pid) { /* PARENT */ |
58 | if (wait4pid(pid) == 0) { | 54 | if (wait4pid(pid) == 0) { |
59 | /* exitcode 0: child says it can read */ | 55 | /* exitcode 0: child says it can read */ |
diff --git a/miscutils/ionice.c b/miscutils/ionice.c index 361c141b8..52e51b908 100644 --- a/miscutils/ionice.c +++ b/miscutils/ionice.c | |||
@@ -89,9 +89,8 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) | |||
89 | pri |= (ioclass << IOPRIO_CLASS_SHIFT); | 89 | pri |= (ioclass << IOPRIO_CLASS_SHIFT); |
90 | if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) | 90 | if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) |
91 | bb_perror_msg_and_die("ioprio_%cet", 's'); | 91 | bb_perror_msg_and_die("ioprio_%cet", 's'); |
92 | if (*argv) { | 92 | if (argv[0]) { |
93 | BB_EXECVP(*argv, argv); | 93 | BB_EXECVP_or_die(argv); |
94 | bb_simple_perror_msg_and_die(*argv); | ||
95 | } | 94 | } |
96 | } | 95 | } |
97 | 96 | ||
diff --git a/miscutils/setsid.c b/miscutils/setsid.c index fd3283e30..c573fae34 100644 --- a/miscutils/setsid.c +++ b/miscutils/setsid.c | |||
@@ -44,6 +44,6 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) | |||
44 | setsid(); | 44 | setsid(); |
45 | } | 45 | } |
46 | 46 | ||
47 | BB_EXECVP(argv[1], argv + 1); | 47 | argv++; |
48 | bb_simple_perror_msg_and_die(argv[1]); | 48 | BB_EXECVP_or_die(argv); |
49 | } | 49 | } |
diff --git a/miscutils/taskset.c b/miscutils/taskset.c index a0bbf0aa1..08198d5d4 100644 --- a/miscutils/taskset.c +++ b/miscutils/taskset.c | |||
@@ -129,9 +129,8 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) | |||
129 | if (sched_setaffinity(pid, sizeof(mask), &mask)) | 129 | if (sched_setaffinity(pid, sizeof(mask), &mask)) |
130 | bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid); | 130 | bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid); |
131 | 131 | ||
132 | if (!*argv) /* "-p <aff> <pid> [...ignored...]" */ | 132 | if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */ |
133 | goto print_aff; /* print new affinity and exit */ | 133 | goto print_aff; /* print new affinity and exit */ |
134 | 134 | ||
135 | BB_EXECVP(*argv, argv); | 135 | BB_EXECVP_or_die(argv); |
136 | bb_simple_perror_msg_and_die(*argv); | ||
137 | } | 136 | } |
diff --git a/miscutils/time.c b/miscutils/time.c index 6946c863f..9facc3657 100644 --- a/miscutils/time.c +++ b/miscutils/time.c | |||
@@ -367,20 +367,15 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
367 | Put the statistics in *RESP. */ | 367 | Put the statistics in *RESP. */ |
368 | static void run_command(char *const *cmd, resource_t *resp) | 368 | static void run_command(char *const *cmd, resource_t *resp) |
369 | { | 369 | { |
370 | pid_t pid; /* Pid of child. */ | 370 | pid_t pid; |
371 | void (*interrupt_signal)(int); | 371 | void (*interrupt_signal)(int); |
372 | void (*quit_signal)(int); | 372 | void (*quit_signal)(int); |
373 | 373 | ||
374 | resp->elapsed_ms = monotonic_ms(); | 374 | resp->elapsed_ms = monotonic_ms(); |
375 | pid = vfork(); /* Run CMD as child process. */ | 375 | pid = xvfork(); |
376 | if (pid < 0) | 376 | if (pid == 0) { |
377 | bb_perror_msg_and_die("fork"); | 377 | /* Child */ |
378 | if (pid == 0) { /* If child. */ | 378 | BB_EXECVP_or_die((char**)cmd); |
379 | /* Don't cast execvp arguments; that causes errors on some systems, | ||
380 | versus merely warnings if the cast is left off. */ | ||
381 | BB_EXECVP(cmd[0], cmd); | ||
382 | xfunc_error_retval = (errno == ENOENT ? 127 : 126); | ||
383 | bb_error_msg_and_die("can't run '%s'", cmd[0]); | ||
384 | } | 379 | } |
385 | 380 | ||
386 | /* Have signals kill the child but not self (if possible). */ | 381 | /* Have signals kill the child but not self (if possible). */ |
diff --git a/miscutils/timeout.c b/miscutils/timeout.c index 83ae56e69..48b8d8fc0 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c | |||
@@ -71,9 +71,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
71 | sv1 = argv[optind]; | 71 | sv1 = argv[optind]; |
72 | sv2 = argv[optind + 1]; | 72 | sv2 = argv[optind + 1]; |
73 | #endif | 73 | #endif |
74 | pid = vfork(); | 74 | pid = xvfork(); |
75 | if (pid < 0) | ||
76 | bb_perror_msg_and_die("vfork"); | ||
77 | if (pid == 0) { | 75 | if (pid == 0) { |
78 | /* Child: spawn grandchild and exit */ | 76 | /* Child: spawn grandchild and exit */ |
79 | parent = getppid(); | 77 | parent = getppid(); |
@@ -110,6 +108,5 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
110 | argv[0] = sv1; | 108 | argv[0] = sv1; |
111 | argv[1] = sv2; | 109 | argv[1] = sv2; |
112 | #endif | 110 | #endif |
113 | BB_EXECVP(argv[0], argv); | 111 | BB_EXECVP_or_die(argv); |
114 | bb_perror_msg_and_die("exec '%s'", argv[0]); | ||
115 | } | 112 | } |
diff --git a/modutils/Config.src b/modutils/Config.src index 2ced9b308..a7dcb3ab3 100644 --- a/modutils/Config.src +++ b/modutils/Config.src | |||
@@ -228,7 +228,7 @@ config FEATURE_MODUTILS_SYMBOLS | |||
228 | config DEFAULT_MODULES_DIR | 228 | config DEFAULT_MODULES_DIR |
229 | string "Default directory containing modules" | 229 | string "Default directory containing modules" |
230 | default "/lib/modules" | 230 | default "/lib/modules" |
231 | depends on DEPMOD || MODPROBE || MODPROBE_SMALL | 231 | depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO |
232 | help | 232 | help |
233 | Directory that contains kernel modules. | 233 | Directory that contains kernel modules. |
234 | Defaults to "/lib/modules" | 234 | Defaults to "/lib/modules" |
@@ -236,7 +236,7 @@ config DEFAULT_MODULES_DIR | |||
236 | config DEFAULT_DEPMOD_FILE | 236 | config DEFAULT_DEPMOD_FILE |
237 | string "Default name of modules.dep" | 237 | string "Default name of modules.dep" |
238 | default "modules.dep" | 238 | default "modules.dep" |
239 | depends on DEPMOD || MODPROBE || MODPROBE_SMALL | 239 | depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO |
240 | help | 240 | help |
241 | Filename that contains kernel modules dependencies. | 241 | Filename that contains kernel modules dependencies. |
242 | Defaults to "modules.dep" | 242 | Defaults to "modules.dep" |
diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 321ad78f4..454a1b366 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c | |||
@@ -43,7 +43,8 @@ static int display(const char *data, const char *pattern, int flag) | |||
43 | return printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n'); | 43 | return printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n'); |
44 | } | 44 | } |
45 | 45 | ||
46 | static void modinfo(const char *path, struct modinfo_env *env) | 46 | static void modinfo(const char *path, const char *version, |
47 | struct modinfo_env *env) | ||
47 | { | 48 | { |
48 | static const char *const shortcuts[] = { | 49 | static const char *const shortcuts[] = { |
49 | "filename", | 50 | "filename", |
@@ -62,10 +63,20 @@ static void modinfo(const char *path, struct modinfo_env *env) | |||
62 | if (tags & 1) { /* filename */ | 63 | if (tags & 1) { /* filename */ |
63 | display(path, shortcuts[0], 1 != tags); | 64 | display(path, shortcuts[0], 1 != tags); |
64 | } | 65 | } |
66 | |||
65 | len = MAXINT(ssize_t); | 67 | len = MAXINT(ssize_t); |
66 | the_module = xmalloc_open_zipped_read_close(path, &len); | 68 | the_module = xmalloc_open_zipped_read_close(path, &len); |
67 | if (!the_module) | 69 | if (!the_module) { |
68 | return; | 70 | if (path[0] == '/') |
71 | return; | ||
72 | /* Newer depmod puts relative paths in modules.dep */ | ||
73 | path = xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, version, path); | ||
74 | the_module = xmalloc_open_zipped_read_close(path, &len); | ||
75 | free((char*)path); | ||
76 | if (!the_module) | ||
77 | return; | ||
78 | } | ||
79 | |||
69 | if (field) | 80 | if (field) |
70 | tags |= OPT_F; | 81 | tags |= OPT_F; |
71 | for (j = 1; (1<<j) & (OPT_TAGS + OPT_F); j++) { | 82 | for (j = 1; (1<<j) & (OPT_TAGS + OPT_F); j++) { |
@@ -109,7 +120,7 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv) | |||
109 | struct modinfo_env env; | 120 | struct modinfo_env env; |
110 | char name[MODULE_NAME_LEN]; | 121 | char name[MODULE_NAME_LEN]; |
111 | struct utsname uts; | 122 | struct utsname uts; |
112 | parser_t *p; | 123 | parser_t *parser; |
113 | char *colon, *tokens[2]; | 124 | char *colon, *tokens[2]; |
114 | unsigned opts; | 125 | unsigned opts; |
115 | unsigned i; | 126 | unsigned i; |
@@ -121,14 +132,12 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv) | |||
121 | argv += optind; | 132 | argv += optind; |
122 | 133 | ||
123 | uname(&uts); | 134 | uname(&uts); |
124 | p = config_open2( | 135 | parser = config_open2( |
125 | concat_path_file( | 136 | xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, uts.release, CONFIG_DEFAULT_DEPMOD_FILE), |
126 | concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release), | ||
127 | CONFIG_DEFAULT_DEPMOD_FILE), | ||
128 | xfopen_for_read | 137 | xfopen_for_read |
129 | ); | 138 | ); |
130 | 139 | ||
131 | while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { | 140 | while (config_read(parser, tokens, 2, 1, "# \t", PARSE_NORMAL)) { |
132 | colon = last_char_is(tokens[0], ':'); | 141 | colon = last_char_is(tokens[0], ':'); |
133 | if (colon == NULL) | 142 | if (colon == NULL) |
134 | continue; | 143 | continue; |
@@ -136,15 +145,19 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv) | |||
136 | filename2modname(tokens[0], name); | 145 | filename2modname(tokens[0], name); |
137 | for (i = 0; argv[i]; i++) { | 146 | for (i = 0; argv[i]; i++) { |
138 | if (fnmatch(argv[i], name, 0) == 0) { | 147 | if (fnmatch(argv[i], name, 0) == 0) { |
139 | modinfo(tokens[0], &env); | 148 | modinfo(tokens[0], uts.release, &env); |
140 | argv[i] = (char *) ""; | 149 | argv[i] = (char *) ""; |
141 | } | 150 | } |
142 | } | 151 | } |
143 | } | 152 | } |
153 | if (ENABLE_FEATURE_CLEAN_UP) | ||
154 | config_close(parser); | ||
155 | |||
144 | for (i = 0; argv[i]; i++) { | 156 | for (i = 0; argv[i]; i++) { |
145 | if (argv[i][0]) { | 157 | if (argv[i][0]) { |
146 | modinfo(argv[i], &env); | 158 | modinfo(argv[i], uts.release, &env); |
147 | } | 159 | } |
148 | } | 160 | } |
161 | |||
149 | return 0; | 162 | return 0; |
150 | } | 163 | } |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index b4de65b1f..0a9424293 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -483,6 +483,11 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
483 | opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); | 483 | opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); |
484 | argv += optind; | 484 | argv += optind; |
485 | 485 | ||
486 | /* Goto modules location */ | ||
487 | xchdir(CONFIG_DEFAULT_MODULES_DIR); | ||
488 | uname(&uts); | ||
489 | xchdir(uts.release); | ||
490 | |||
486 | if (opt & MODPROBE_OPT_LIST_ONLY) { | 491 | if (opt & MODPROBE_OPT_LIST_ONLY) { |
487 | char name[MODULE_NAME_LEN]; | 492 | char name[MODULE_NAME_LEN]; |
488 | char *colon, *tokens[2]; | 493 | char *colon, *tokens[2]; |
@@ -524,11 +529,6 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
524 | return EXIT_SUCCESS; | 529 | return EXIT_SUCCESS; |
525 | } | 530 | } |
526 | 531 | ||
527 | /* Goto modules location */ | ||
528 | xchdir(CONFIG_DEFAULT_MODULES_DIR); | ||
529 | uname(&uts); | ||
530 | xchdir(uts.release); | ||
531 | |||
532 | /* Retrieve module names of already loaded modules */ | 532 | /* Retrieve module names of already loaded modules */ |
533 | { | 533 | { |
534 | char *s; | 534 | char *s; |
diff --git a/networking/Config.src b/networking/Config.src index ebad9e598..449436247 100644 --- a/networking/Config.src +++ b/networking/Config.src | |||
@@ -623,29 +623,6 @@ config FEATURE_NAMEIF_EXTENDED | |||
623 | new_interface_name mac=00:80:C8:38:91:B5 | 623 | new_interface_name mac=00:80:C8:38:91:B5 |
624 | new_interface_name 00:80:C8:38:91:B5 | 624 | new_interface_name 00:80:C8:38:91:B5 |
625 | 625 | ||
626 | config NC | ||
627 | bool "nc" | ||
628 | default y | ||
629 | help | ||
630 | A simple Unix utility which reads and writes data across network | ||
631 | connections. | ||
632 | |||
633 | config NC_SERVER | ||
634 | bool "Netcat server options (-l)" | ||
635 | default y | ||
636 | depends on NC | ||
637 | help | ||
638 | Allow netcat to act as a server. | ||
639 | |||
640 | config NC_EXTRA | ||
641 | bool "Netcat extensions (-eiw and filename)" | ||
642 | default y | ||
643 | depends on NC | ||
644 | help | ||
645 | Add -e (support for executing the rest of the command line after | ||
646 | making or receiving a successful connection), -i (delay interval for | ||
647 | lines sent), -w (timeout for initial connection). | ||
648 | |||
649 | config NETSTAT | 626 | config NETSTAT |
650 | bool "netstat" | 627 | bool "netstat" |
651 | default y | 628 | default y |
diff --git a/networking/ftpd.c b/networking/ftpd.c index c63b9319e..e8cae0a36 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -632,10 +632,7 @@ popen_ls(const char *opt) | |||
632 | xpiped_pair(outfd); | 632 | xpiped_pair(outfd); |
633 | 633 | ||
634 | /*fflush_all(); - so far we dont use stdio on output */ | 634 | /*fflush_all(); - so far we dont use stdio on output */ |
635 | pid = BB_MMU ? fork() : vfork(); | 635 | pid = BB_MMU ? xfork() : xvfork(); |
636 | if (pid < 0) | ||
637 | bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); | ||
638 | |||
639 | if (pid == 0) { | 636 | if (pid == 0) { |
640 | /* child */ | 637 | /* child */ |
641 | #if !BB_MMU | 638 | #if !BB_MMU |
diff --git a/networking/httpd.c b/networking/httpd.c index 6dbc219e7..8ad7e88b1 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -1474,7 +1474,7 @@ static void send_cgi_and_exit( | |||
1474 | * in the current directory */ | 1474 | * in the current directory */ |
1475 | execv(argv[0], argv); | 1475 | execv(argv[0], argv); |
1476 | if (verbose) | 1476 | if (verbose) |
1477 | bb_perror_msg("exec %s", argv[0]); | 1477 | bb_perror_msg("can't execute '%s'", argv[0]); |
1478 | error_execing_cgi: | 1478 | error_execing_cgi: |
1479 | /* send to stdout | 1479 | /* send to stdout |
1480 | * (we are CGI here, our stdout is pumped to the net) */ | 1480 | * (we are CGI here, our stdout is pumped to the net) */ |
diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 8cb07db5d..eb7442881 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c | |||
@@ -79,6 +79,7 @@ enum { // api mode | |||
79 | API_WLAN = 'w', | 79 | API_WLAN = 'w', |
80 | API_IFF = 'i', | 80 | API_IFF = 'i', |
81 | }; | 81 | }; |
82 | static const char api_modes[] ALIGN1 = "aempwi"; | ||
82 | 83 | ||
83 | enum { // interface status | 84 | enum { // interface status |
84 | IFSTATUS_ERR = -1, | 85 | IFSTATUS_ERR = -1, |
@@ -95,6 +96,7 @@ struct globals { | |||
95 | smallint iface_last_status; | 96 | smallint iface_last_status; |
96 | smallint iface_prev_status; | 97 | smallint iface_prev_status; |
97 | smallint iface_exists; | 98 | smallint iface_exists; |
99 | smallint api_method_num; | ||
98 | 100 | ||
99 | /* Used in getopt32, must have sizeof == sizeof(int) */ | 101 | /* Used in getopt32, must have sizeof == sizeof(int) */ |
100 | unsigned poll_time; | 102 | unsigned poll_time; |
@@ -107,7 +109,6 @@ struct globals { | |||
107 | const char *extra_arg; | 109 | const char *extra_arg; |
108 | 110 | ||
109 | smallint (*detect_link_func)(void); | 111 | smallint (*detect_link_func)(void); |
110 | smallint (*cached_detect_link_func)(void); | ||
111 | }; | 112 | }; |
112 | #define G (*ptr_to_globals) | 113 | #define G (*ptr_to_globals) |
113 | #define INIT_G() do { \ | 114 | #define INIT_G() do { \ |
@@ -239,8 +240,8 @@ static void maybe_up_new_iface(void) | |||
239 | G.iface, buf, driver_info.driver, driver_info.version); | 240 | G.iface, buf, driver_info.driver, driver_info.version); |
240 | } | 241 | } |
241 | #endif | 242 | #endif |
242 | 243 | if (G.api_method_num == 0) | |
243 | G.cached_detect_link_func = NULL; | 244 | G.detect_link_func = NULL; |
244 | } | 245 | } |
245 | 246 | ||
246 | static smallint detect_link_mii(void) | 247 | static smallint detect_link_mii(void) |
@@ -348,7 +349,7 @@ static smallint detect_link_wlan(void) | |||
348 | return IFSTATUS_UP; | 349 | return IFSTATUS_UP; |
349 | } | 350 | } |
350 | 351 | ||
351 | static smallint detect_link_auto(void) | 352 | static smallint detect_link(void) |
352 | { | 353 | { |
353 | static const struct { | 354 | static const struct { |
354 | const char *name; | 355 | const char *name; |
@@ -360,32 +361,6 @@ static smallint detect_link_auto(void) | |||
360 | { "wireless extension", &detect_link_wlan }, | 361 | { "wireless extension", &detect_link_wlan }, |
361 | { "IFF_RUNNING" , &detect_link_iff }, | 362 | { "IFF_RUNNING" , &detect_link_iff }, |
362 | }; | 363 | }; |
363 | int i; | ||
364 | smallint iface_status; | ||
365 | smallint sv_logmode; | ||
366 | |||
367 | if (G.cached_detect_link_func) { | ||
368 | iface_status = G.cached_detect_link_func(); | ||
369 | if (iface_status != IFSTATUS_ERR) | ||
370 | return iface_status; | ||
371 | } | ||
372 | |||
373 | sv_logmode = logmode; | ||
374 | for (i = 0; i < ARRAY_SIZE(method); i++) { | ||
375 | logmode = LOGMODE_NONE; | ||
376 | iface_status = method[i].func(); | ||
377 | logmode = sv_logmode; | ||
378 | if (iface_status != IFSTATUS_ERR) { | ||
379 | G.cached_detect_link_func = method[i].func; | ||
380 | bb_error_msg("using %s detection mode", method[i].name); | ||
381 | break; | ||
382 | } | ||
383 | } | ||
384 | return iface_status; | ||
385 | } | ||
386 | |||
387 | static smallint detect_link(void) | ||
388 | { | ||
389 | smallint status; | 364 | smallint status; |
390 | 365 | ||
391 | if (!G.iface_exists) | 366 | if (!G.iface_exists) |
@@ -398,20 +373,38 @@ static smallint detect_link(void) | |||
398 | if (!(option_mask32 & FLAG_NO_AUTO)) | 373 | if (!(option_mask32 & FLAG_NO_AUTO)) |
399 | up_iface(); | 374 | up_iface(); |
400 | 375 | ||
376 | if (!G.detect_link_func) { | ||
377 | if (G.api_method_num == 0) { | ||
378 | int i; | ||
379 | smallint sv_logmode; | ||
380 | |||
381 | sv_logmode = logmode; | ||
382 | for (i = 0; i < ARRAY_SIZE(method); i++) { | ||
383 | logmode = LOGMODE_NONE; | ||
384 | status = method[i].func(); | ||
385 | logmode = sv_logmode; | ||
386 | if (status != IFSTATUS_ERR) { | ||
387 | G.detect_link_func = method[i].func; | ||
388 | bb_error_msg("using %s detection mode", method[i].name); | ||
389 | goto _2; | ||
390 | } | ||
391 | } | ||
392 | goto _1; | ||
393 | } | ||
394 | G.detect_link_func = method[G.api_method_num - 1].func; | ||
395 | } | ||
396 | |||
401 | status = G.detect_link_func(); | 397 | status = G.detect_link_func(); |
398 | _1: | ||
402 | if (status == IFSTATUS_ERR) { | 399 | if (status == IFSTATUS_ERR) { |
403 | if (option_mask32 & FLAG_IGNORE_FAIL) | 400 | if (option_mask32 & FLAG_IGNORE_FAIL) |
404 | status = IFSTATUS_DOWN; | 401 | status = IFSTATUS_DOWN; |
405 | if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE) | 402 | else if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE) |
406 | status = IFSTATUS_UP; | 403 | status = IFSTATUS_UP; |
404 | else if (G.api_method_num == 0) | ||
405 | bb_error_msg("can't detect link status"); | ||
407 | } | 406 | } |
408 | 407 | _2: | |
409 | if (status == IFSTATUS_ERR | ||
410 | && G.detect_link_func == detect_link_auto | ||
411 | ) { | ||
412 | bb_error_msg("can't detect link status"); | ||
413 | } | ||
414 | |||
415 | if (status != G.iface_last_status) { | 408 | if (status != G.iface_last_status) { |
416 | G.iface_prev_status = G.iface_last_status; | 409 | G.iface_prev_status = G.iface_last_status; |
417 | G.iface_last_status = status; | 410 | G.iface_last_status = status; |
@@ -523,6 +516,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) | |||
523 | const char *iface_status_str; | 516 | const char *iface_status_str; |
524 | struct pollfd netlink_pollfd[1]; | 517 | struct pollfd netlink_pollfd[1]; |
525 | unsigned opts; | 518 | unsigned opts; |
519 | const char *api_mode_found; | ||
526 | #if ENABLE_FEATURE_PIDFILE | 520 | #if ENABLE_FEATURE_PIDFILE |
527 | char *pidfile_name; | 521 | char *pidfile_name; |
528 | pid_t pid_from_pidfile; | 522 | pid_t pid_from_pidfile; |
@@ -551,29 +545,10 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) | |||
551 | if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0) | 545 | if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0) |
552 | bb_error_msg_and_die("daemon already running"); | 546 | bb_error_msg_and_die("daemon already running"); |
553 | #endif | 547 | #endif |
554 | 548 | api_mode_found = strchr(api_modes, G.api_mode[0]); | |
555 | switch (G.api_mode[0]) { | 549 | if (!api_mode_found) |
556 | case API_AUTO: | ||
557 | G.detect_link_func = detect_link_auto; | ||
558 | break; | ||
559 | case API_ETHTOOL: | ||
560 | G.detect_link_func = detect_link_ethtool; | ||
561 | break; | ||
562 | case API_MII: | ||
563 | G.detect_link_func = detect_link_mii; | ||
564 | break; | ||
565 | case API_PRIVATE: | ||
566 | G.detect_link_func = detect_link_priv; | ||
567 | break; | ||
568 | case API_WLAN: | ||
569 | G.detect_link_func = detect_link_wlan; | ||
570 | break; | ||
571 | case API_IFF: | ||
572 | G.detect_link_func = detect_link_iff; | ||
573 | break; | ||
574 | default: | ||
575 | bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); | 550 | bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); |
576 | } | 551 | G.api_method_num = api_mode_found - api_modes; |
577 | 552 | ||
578 | if (!(opts & FLAG_NO_DAEMON)) | 553 | if (!(opts & FLAG_NO_DAEMON)) |
579 | bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); | 554 | bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); |
diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 2f3dd1d7b..69c56e879 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c | |||
@@ -1041,19 +1041,16 @@ static int popen2(FILE **in, FILE **out, char *command, char *param) | |||
1041 | xpiped_pair(outfd); | 1041 | xpiped_pair(outfd); |
1042 | 1042 | ||
1043 | fflush_all(); | 1043 | fflush_all(); |
1044 | pid = vfork(); | 1044 | pid = xvfork(); |
1045 | 1045 | ||
1046 | switch (pid) { | 1046 | if (pid == 0) { |
1047 | case -1: /* failure */ | 1047 | /* Child */ |
1048 | bb_perror_msg_and_die("vfork"); | ||
1049 | case 0: /* child */ | ||
1050 | /* NB: close _first_, then move fds! */ | 1048 | /* NB: close _first_, then move fds! */ |
1051 | close(infd.wr); | 1049 | close(infd.wr); |
1052 | close(outfd.rd); | 1050 | close(outfd.rd); |
1053 | xmove_fd(infd.rd, 0); | 1051 | xmove_fd(infd.rd, 0); |
1054 | xmove_fd(outfd.wr, 1); | 1052 | xmove_fd(outfd.wr, 1); |
1055 | BB_EXECVP(command, argv); | 1053 | BB_EXECVP_or_die(argv); |
1056 | _exit(127); | ||
1057 | } | 1054 | } |
1058 | /* parent */ | 1055 | /* parent */ |
1059 | close(infd.rd); | 1056 | close(infd.rd); |
diff --git a/networking/inetd.c b/networking/inetd.c index 7aa6b7b19..7030062b6 100644 --- a/networking/inetd.c +++ b/networking/inetd.c | |||
@@ -1271,7 +1271,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1271 | pid = vfork(); | 1271 | pid = vfork(); |
1272 | 1272 | ||
1273 | if (pid < 0) { /* fork error */ | 1273 | if (pid < 0) { /* fork error */ |
1274 | bb_perror_msg("fork"); | 1274 | bb_perror_msg("vfork"+1); |
1275 | sleep(1); | 1275 | sleep(1); |
1276 | restore_sigmask(&omask); | 1276 | restore_sigmask(&omask); |
1277 | maybe_close(accepted_fd); | 1277 | maybe_close(accepted_fd); |
@@ -1380,7 +1380,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1380 | sigaction_set(SIGPIPE, &saved_pipe_handler); | 1380 | sigaction_set(SIGPIPE, &saved_pipe_handler); |
1381 | restore_sigmask(&omask); | 1381 | restore_sigmask(&omask); |
1382 | BB_EXECVP(sep->se_program, sep->se_argv); | 1382 | BB_EXECVP(sep->se_program, sep->se_argv); |
1383 | bb_perror_msg("exec %s", sep->se_program); | 1383 | bb_perror_msg("can't execute '%s'", sep->se_program); |
1384 | do_exit1: | 1384 | do_exit1: |
1385 | /* eat packet in udp case */ | 1385 | /* eat packet in udp case */ |
1386 | if (sep->se_socktype != SOCK_STREAM) | 1386 | if (sep->se_socktype != SOCK_STREAM) |
diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 17b216354..265009ad8 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c | |||
@@ -11,11 +11,9 @@ | |||
11 | * | 11 | * |
12 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 12 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
13 | */ | 13 | */ |
14 | |||
15 | #include <sys/socket.h> | ||
16 | #include <arpa/inet.h> | ||
17 | |||
18 | #include "libbb.h" | 14 | #include "libbb.h" |
15 | /* After libbb.h, because on some systems it needs other includes */ | ||
16 | #include <arpa/inet.h> | ||
19 | 17 | ||
20 | #define CLASS_A_NETMASK ntohl(0xFF000000) | 18 | #define CLASS_A_NETMASK ntohl(0xFF000000) |
21 | #define CLASS_B_NETMASK ntohl(0xFFFF0000) | 19 | #define CLASS_B_NETMASK ntohl(0xFFFF0000) |
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index a603053e1..381293412 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c | |||
@@ -444,28 +444,28 @@ int ipaddr_list_or_flush(char **argv, int flush) | |||
444 | while (*argv) { | 444 | while (*argv) { |
445 | const smalluint key = index_in_strings(option, *argv); | 445 | const smalluint key = index_in_strings(option, *argv); |
446 | if (key == 0) { /* to */ | 446 | if (key == 0) { /* to */ |
447 | NEXT_ARG(); | 447 | NEXT_ARG(); |
448 | get_prefix(&G_filter.pfx, *argv, G_filter.family); | 448 | get_prefix(&G_filter.pfx, *argv, G_filter.family); |
449 | if (G_filter.family == AF_UNSPEC) { | 449 | if (G_filter.family == AF_UNSPEC) { |
450 | G_filter.family = G_filter.pfx.family; | 450 | G_filter.family = G_filter.pfx.family; |
451 | } | 451 | } |
452 | } else if (key == 1) { /* scope */ | 452 | } else if (key == 1) { /* scope */ |
453 | uint32_t scope = 0; | 453 | uint32_t scope = 0; |
454 | NEXT_ARG(); | 454 | NEXT_ARG(); |
455 | G_filter.scopemask = -1; | 455 | G_filter.scopemask = -1; |
456 | if (rtnl_rtscope_a2n(&scope, *argv)) { | 456 | if (rtnl_rtscope_a2n(&scope, *argv)) { |
457 | if (strcmp(*argv, "all") != 0) { | 457 | if (strcmp(*argv, "all") != 0) { |
458 | invarg(*argv, "scope"); | 458 | invarg(*argv, "scope"); |
459 | } | ||
460 | scope = RT_SCOPE_NOWHERE; | ||
461 | G_filter.scopemask = 0; | ||
462 | } | 459 | } |
463 | G_filter.scope = scope; | 460 | scope = RT_SCOPE_NOWHERE; |
461 | G_filter.scopemask = 0; | ||
462 | } | ||
463 | G_filter.scope = scope; | ||
464 | } else if (key == 2) { /* up */ | 464 | } else if (key == 2) { /* up */ |
465 | G_filter.up = 1; | 465 | G_filter.up = 1; |
466 | } else if (key == 3) { /* label */ | 466 | } else if (key == 3) { /* label */ |
467 | NEXT_ARG(); | 467 | NEXT_ARG(); |
468 | G_filter.label = *argv; | 468 | G_filter.label = *argv; |
469 | } else { | 469 | } else { |
470 | if (key == 4) /* dev */ | 470 | if (key == 4) /* dev */ |
471 | NEXT_ARG(); | 471 | NEXT_ARG(); |
@@ -681,7 +681,7 @@ static int ipaddr_modify(int cmd, char **argv) | |||
681 | } else if (arg == 7) { /* label */ | 681 | } else if (arg == 7) { /* label */ |
682 | NEXT_ARG(); | 682 | NEXT_ARG(); |
683 | l = *argv; | 683 | l = *argv; |
684 | addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); | 684 | addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1); |
685 | } else { | 685 | } else { |
686 | if (arg == 8) /* local */ | 686 | if (arg == 8) /* local */ |
687 | NEXT_ARG(); | 687 | NEXT_ARG(); |
@@ -698,11 +698,10 @@ static int ipaddr_modify(int cmd, char **argv) | |||
698 | argv++; | 698 | argv++; |
699 | } | 699 | } |
700 | 700 | ||
701 | // d cannot be null here, NEXT_ARG() of "dev" ensures that | 701 | if (!d) { |
702 | //if (d == NULL) { | 702 | /* There was no "dev IFACE", but we need that */ |
703 | // bb_error_msg(bb_msg_requires_arg, "\"dev\""); | 703 | bb_error_msg_and_die("need \"dev IFACE\""); |
704 | // return -1; | 704 | } |
705 | //} | ||
706 | if (l && strncmp(d, l, strlen(d)) != 0) { | 705 | if (l && strncmp(d, l, strlen(d)) != 0) { |
707 | bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); | 706 | bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); |
708 | } | 707 | } |
diff --git a/networking/nc.c b/networking/nc.c index 243c47976..0dacaf117 100644 --- a/networking/nc.c +++ b/networking/nc.c | |||
@@ -9,10 +9,89 @@ | |||
9 | 9 | ||
10 | #include "libbb.h" | 10 | #include "libbb.h" |
11 | 11 | ||
12 | #if ENABLE_DESKTOP | 12 | //config:config NC |
13 | #include "nc_bloaty.c" | 13 | //config: bool "nc" |
14 | //config: default y | ||
15 | //config: help | ||
16 | //config: A simple Unix utility which reads and writes data across network | ||
17 | //config: connections. | ||
18 | //config: | ||
19 | //config:config NC_SERVER | ||
20 | //config: bool "Netcat server options (-l)" | ||
21 | //config: default y | ||
22 | //config: depends on NC | ||
23 | //config: help | ||
24 | //config: Allow netcat to act as a server. | ||
25 | //config: | ||
26 | //config:config NC_EXTRA | ||
27 | //config: bool "Netcat extensions (-eiw and filename)" | ||
28 | //config: default y | ||
29 | //config: depends on NC | ||
30 | //config: help | ||
31 | //config: Add -e (support for executing the rest of the command line after | ||
32 | //config: making or receiving a successful connection), -i (delay interval for | ||
33 | //config: lines sent), -w (timeout for initial connection). | ||
34 | //config: | ||
35 | //config:config NC_110_COMPAT | ||
36 | //config: bool "Netcat 1.10 compatibility (+2.5k)" | ||
37 | //config: default y | ||
38 | //config: depends on NC | ||
39 | //config: help | ||
40 | //config: This option makes nc closely follow original nc-1.10. | ||
41 | //config: The code is about 2.5k bigger. It enables | ||
42 | //config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses | ||
43 | //config: busybox-specific extensions: -f FILE and -ll. | ||
44 | |||
45 | #if ENABLE_NC_110_COMPAT | ||
46 | # include "nc_bloaty.c" | ||
14 | #else | 47 | #else |
15 | 48 | ||
49 | //usage:#if !ENABLE_NC_110_COMPAT | ||
50 | //usage: | ||
51 | //usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA | ||
52 | //usage:#define NC_OPTIONS_STR "\n\nOptions:" | ||
53 | //usage:#else | ||
54 | //usage:#define NC_OPTIONS_STR | ||
55 | //usage:#endif | ||
56 | //usage: | ||
57 | //usage:#define nc_trivial_usage | ||
58 | //usage: IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ") | ||
59 | //usage: "["IF_NC_EXTRA("-f FILE|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]") | ||
60 | //usage:#define nc_full_usage "\n\n" | ||
61 | //usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") | ||
62 | //usage: NC_OPTIONS_STR | ||
63 | //usage: IF_NC_EXTRA( | ||
64 | //usage: "\n -e PROG Run PROG after connect" | ||
65 | //usage: IF_NC_SERVER( | ||
66 | //usage: "\n -l Listen mode, for inbound connects" | ||
67 | //usage: IF_NC_EXTRA( | ||
68 | //usage: "\n (use -l twice with -e for persistent server)") | ||
69 | //usage: "\n -p PORT Local port" | ||
70 | //usage: ) | ||
71 | //usage: "\n -w SEC Timeout for connect" | ||
72 | //usage: "\n -i SEC Delay interval for lines sent" | ||
73 | //usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" | ||
74 | //usage: ) | ||
75 | //usage: | ||
76 | //usage:#define nc_notes_usage "" | ||
77 | //usage: IF_NC_EXTRA( | ||
78 | //usage: "To use netcat as a terminal emulator on a serial port:\n\n" | ||
79 | //usage: "$ stty 115200 -F /dev/ttyS0\n" | ||
80 | //usage: "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" | ||
81 | //usage: ) | ||
82 | //usage: | ||
83 | //usage:#define nc_example_usage | ||
84 | //usage: "$ nc foobar.somedomain.com 25\n" | ||
85 | //usage: "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" | ||
86 | //usage: "help\n" | ||
87 | //usage: "214-Commands supported:\n" | ||
88 | //usage: "214- HELO EHLO MAIL RCPT DATA AUTH\n" | ||
89 | //usage: "214 NOOP QUIT RSET HELP\n" | ||
90 | //usage: "quit\n" | ||
91 | //usage: "221 foobar closing connection\n" | ||
92 | //usage: | ||
93 | //usage:#endif | ||
94 | |||
16 | /* Lots of small differences in features | 95 | /* Lots of small differences in features |
17 | * when compared to "standard" nc | 96 | * when compared to "standard" nc |
18 | */ | 97 | */ |
@@ -39,7 +118,7 @@ int nc_main(int argc, char **argv) | |||
39 | 118 | ||
40 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { | 119 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { |
41 | /* getopt32 is _almost_ usable: | 120 | /* getopt32 is _almost_ usable: |
42 | ** it cannot handle "... -e prog -prog-opt" */ | 121 | ** it cannot handle "... -e PROG -prog-opt" */ |
43 | while ((opt = getopt(argc, argv, | 122 | while ((opt = getopt(argc, argv, |
44 | "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 | 123 | "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 |
45 | ) { | 124 | ) { |
@@ -57,7 +136,7 @@ int nc_main(int argc, char **argv) | |||
57 | /* We cannot just 'break'. We should let getopt finish. | 136 | /* We cannot just 'break'. We should let getopt finish. |
58 | ** Or else we won't be able to find where | 137 | ** Or else we won't be able to find where |
59 | ** 'host' and 'port' params are | 138 | ** 'host' and 'port' params are |
60 | ** (think "nc -w 60 host port -e prog"). */ | 139 | ** (think "nc -w 60 host port -e PROG"). */ |
61 | IF_NC_EXTRA( | 140 | IF_NC_EXTRA( |
62 | char **p; | 141 | char **p; |
63 | // +2: one for progname (optarg) and one for NULL | 142 | // +2: one for progname (optarg) and one for NULL |
@@ -70,7 +149,7 @@ int nc_main(int argc, char **argv) | |||
70 | ) | 149 | ) |
71 | /* optind points to argv[arvc] (NULL) now. | 150 | /* optind points to argv[arvc] (NULL) now. |
72 | ** FIXME: we assume that getopt will not count options | 151 | ** FIXME: we assume that getopt will not count options |
73 | ** possibly present on "-e prog args" and will not | 152 | ** possibly present on "-e PROG ARGS" and will not |
74 | ** include them into final value of optind | 153 | ** include them into final value of optind |
75 | ** which is to be used ... */ | 154 | ** which is to be used ... */ |
76 | } else bb_show_usage(); | 155 | } else bb_show_usage(); |
@@ -137,10 +216,8 @@ int nc_main(int argc, char **argv) | |||
137 | if (execparam) { | 216 | if (execparam) { |
138 | pid_t pid; | 217 | pid_t pid; |
139 | /* With more than one -l, repeatedly act as server */ | 218 | /* With more than one -l, repeatedly act as server */ |
140 | if (do_listen > 1 && (pid = vfork()) != 0) { | 219 | if (do_listen > 1 && (pid = xvfork()) != 0) { |
141 | /* parent or error */ | 220 | /* parent */ |
142 | if (pid < 0) | ||
143 | bb_perror_msg_and_die("vfork"); | ||
144 | /* prevent zombies */ | 221 | /* prevent zombies */ |
145 | signal(SIGCHLD, SIG_IGN); | 222 | signal(SIGCHLD, SIG_IGN); |
146 | close(cfd); | 223 | close(cfd); |
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index e14d512ed..aebb9cb8c 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -36,20 +36,58 @@ | |||
36 | * - source routing | 36 | * - source routing |
37 | * - multiple DNS checks | 37 | * - multiple DNS checks |
38 | * Functionalty which is different from nc 1.10: | 38 | * Functionalty which is different from nc 1.10: |
39 | * - Prog in '-e prog' can have prog's parameters and options. | 39 | * - PROG in '-e PROG' can have ARGS (and options). |
40 | * Because of this -e option must be last. | 40 | * Because of this -e option must be last. |
41 | * - nc doesn't redirect stderr to the network socket for the -e prog. | 41 | //TODO: remove -e incompatibility? |
42 | * - we don't redirect stderr to the network socket for the -e PROG. | ||
43 | * (PROG can do it itself if needed, but sometimes it is NOT wanted!) | ||
42 | * - numeric addresses are printed in (), not [] (IPv6 looks better), | 44 | * - numeric addresses are printed in (), not [] (IPv6 looks better), |
43 | * port numbers are inside (): (1.2.3.4:5678) | 45 | * port numbers are inside (): (1.2.3.4:5678) |
44 | * - network read errors are reported on verbose levels > 1 | 46 | * - network read errors are reported on verbose levels > 1 |
45 | * (nc 1.10 treats them as EOF) | 47 | * (nc 1.10 treats them as EOF) |
46 | * - TCP connects from wrong ip/ports (if peer ip:port is specified | 48 | * - TCP connects from wrong ip/ports (if peer ip:port is specified |
47 | * on the command line, but accept() says that it came from different addr) | 49 | * on the command line, but accept() says that it came from different addr) |
48 | * are closed, but nc doesn't exit - continues to listen/accept. | 50 | * are closed, but we don't exit - we continue to listen/accept. |
49 | */ | 51 | */ |
50 | 52 | ||
51 | /* done in nc.c: #include "libbb.h" */ | 53 | /* done in nc.c: #include "libbb.h" */ |
52 | 54 | ||
55 | //usage:#if ENABLE_NC_110_COMPAT | ||
56 | //usage: | ||
57 | //usage:#define nc_trivial_usage | ||
58 | //usage: "[OPTIONS] HOST PORT - connect" | ||
59 | //usage: IF_NC_SERVER("\n" | ||
60 | //usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") | ||
61 | //usage:#define nc_full_usage "\n\n" | ||
62 | //usage: "Options:" | ||
63 | //usage: "\n -e PROG Run PROG after connect (must be last)" | ||
64 | //usage: IF_NC_SERVER( | ||
65 | //usage: "\n -l Listen mode, for inbound connects" | ||
66 | //usage: ) | ||
67 | //usage: "\n -p PORT Local port" | ||
68 | //usage: "\n -s ADDR Local address" | ||
69 | //usage: "\n -w SEC Timeout for connects and final net reads" | ||
70 | //usage: IF_NC_EXTRA( | ||
71 | //usage: "\n -i SEC Delay interval for lines sent" /* ", ports scanned" */ | ||
72 | //usage: ) | ||
73 | //usage: "\n -n Don't do DNS resolution" | ||
74 | //usage: "\n -u UDP mode" | ||
75 | //usage: "\n -v Verbose" | ||
76 | //usage: IF_NC_EXTRA( | ||
77 | //usage: "\n -o FILE Hex dump traffic" | ||
78 | //usage: "\n -z Zero-I/O mode (scanning)" | ||
79 | //usage: ) | ||
80 | //usage:#endif | ||
81 | |||
82 | /* "\n -r Randomize local and remote ports" */ | ||
83 | /* "\n -g gateway Source-routing hop point[s], up to 8" */ | ||
84 | /* "\n -G num Source-routing pointer: 4, 8, 12, ..." */ | ||
85 | /* "\nport numbers can be individual or ranges: lo-hi [inclusive]" */ | ||
86 | |||
87 | /* -e PROG can take ARGS too: "nc ... -e ls -l", but we don't document it | ||
88 | * in help text: nc 1.10 does not allow that. We don't want to entice | ||
89 | * users to use this incompatibility */ | ||
90 | |||
53 | enum { | 91 | enum { |
54 | SLEAZE_PORT = 31337, /* for UDP-scan RTT trick, change if ya want */ | 92 | SLEAZE_PORT = 31337, /* for UDP-scan RTT trick, change if ya want */ |
55 | BIGSIZ = 8192, /* big buffers */ | 93 | BIGSIZ = 8192, /* big buffers */ |
@@ -230,7 +268,7 @@ static int doexec(char **proggie) | |||
230 | /* dup2(0, 2); - do we *really* want this? NO! | 268 | /* dup2(0, 2); - do we *really* want this? NO! |
231 | * exec'ed prog can do it yourself, if needed */ | 269 | * exec'ed prog can do it yourself, if needed */ |
232 | execvp(proggie[0], proggie); | 270 | execvp(proggie[0], proggie); |
233 | bb_perror_msg_and_die("exec"); | 271 | bb_perror_msg_and_die("can't execute '%s'", proggie[0]); |
234 | } | 272 | } |
235 | 273 | ||
236 | /* connect_w_timeout: | 274 | /* connect_w_timeout: |
diff --git a/networking/ntpd.c b/networking/ntpd.c index 6d9183a4b..14c3a5fbb 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -603,9 +603,9 @@ reset_peer_stats(peer_t *p, double offset) | |||
603 | 603 | ||
604 | for (i = 0; i < NUM_DATAPOINTS; i++) { | 604 | for (i = 0; i < NUM_DATAPOINTS; i++) { |
605 | if (small_ofs) { | 605 | if (small_ofs) { |
606 | p->filter_datapoint[i].d_recv_time -= offset; | 606 | p->filter_datapoint[i].d_recv_time += offset; |
607 | if (p->filter_datapoint[i].d_offset != 0) { | 607 | if (p->filter_datapoint[i].d_offset != 0) { |
608 | p->filter_datapoint[i].d_offset -= offset; | 608 | p->filter_datapoint[i].d_offset += offset; |
609 | } | 609 | } |
610 | } else { | 610 | } else { |
611 | p->filter_datapoint[i].d_recv_time = G.cur_time; | 611 | p->filter_datapoint[i].d_recv_time = G.cur_time; |
@@ -614,13 +614,12 @@ reset_peer_stats(peer_t *p, double offset) | |||
614 | } | 614 | } |
615 | } | 615 | } |
616 | if (small_ofs) { | 616 | if (small_ofs) { |
617 | p->lastpkt_recv_time -= offset; | 617 | p->lastpkt_recv_time += offset; |
618 | } else { | 618 | } else { |
619 | p->reachable_bits = 0; | 619 | p->reachable_bits = 0; |
620 | p->lastpkt_recv_time = G.cur_time; | 620 | p->lastpkt_recv_time = G.cur_time; |
621 | } | 621 | } |
622 | filter_datapoints(p); /* recalc p->filter_xxx */ | 622 | filter_datapoints(p); /* recalc p->filter_xxx */ |
623 | p->next_action_time -= offset; | ||
624 | VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); | 623 | VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); |
625 | } | 624 | } |
626 | 625 | ||
@@ -815,11 +814,14 @@ step_time(double offset) | |||
815 | for (item = G.ntp_peers; item != NULL; item = item->link) { | 814 | for (item = G.ntp_peers; item != NULL; item = item->link) { |
816 | peer_t *pp = (peer_t *) item->data; | 815 | peer_t *pp = (peer_t *) item->data; |
817 | reset_peer_stats(pp, offset); | 816 | reset_peer_stats(pp, offset); |
817 | //bb_error_msg("offset:%f pp->next_action_time:%f -> %f", | ||
818 | // offset, pp->next_action_time, pp->next_action_time + offset); | ||
819 | pp->next_action_time += offset; | ||
818 | } | 820 | } |
819 | /* Globals: */ | 821 | /* Globals: */ |
820 | G.cur_time -= offset; | 822 | G.cur_time += offset; |
821 | G.last_update_recv_time -= offset; | 823 | G.last_update_recv_time += offset; |
822 | G.last_script_run -= offset; | 824 | G.last_script_run += offset; |
823 | } | 825 | } |
824 | 826 | ||
825 | 827 | ||
diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 42845df0e..53e622b56 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c | |||
@@ -85,8 +85,7 @@ static void undo_xsetenv(void) | |||
85 | char **pp = env_cur = &env_var[0]; | 85 | char **pp = env_cur = &env_var[0]; |
86 | while (*pp) { | 86 | while (*pp) { |
87 | char *var = *pp; | 87 | char *var = *pp; |
88 | bb_unsetenv(var); | 88 | bb_unsetenv_and_free(var); |
89 | free(var); | ||
90 | *pp++ = NULL; | 89 | *pp++ = NULL; |
91 | } | 90 | } |
92 | } | 91 | } |
@@ -502,10 +501,10 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
502 | #ifdef SSLSVD | 501 | #ifdef SSLSVD |
503 | strcpy(id, utoa(pid)); | 502 | strcpy(id, utoa(pid)); |
504 | ssl_io(0, argv); | 503 | ssl_io(0, argv); |
504 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | ||
505 | #else | 505 | #else |
506 | BB_EXECVP(argv[0], argv); | 506 | BB_EXECVP_or_die(argv); |
507 | #endif | 507 | #endif |
508 | bb_perror_msg_and_die("exec '%s'", argv[0]); | ||
509 | } | 508 | } |
510 | 509 | ||
511 | /* | 510 | /* |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index c2b21c695..de1b79844 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -327,8 +327,7 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name) | |||
327 | 327 | ||
328 | for (curr = envp; *curr; curr++) { | 328 | for (curr = envp; *curr; curr++) { |
329 | log2(" %s", *curr); | 329 | log2(" %s", *curr); |
330 | bb_unsetenv(*curr); | 330 | bb_unsetenv_and_free(*curr); |
331 | free(*curr); | ||
332 | } | 331 | } |
333 | free(envp); | 332 | free(envp); |
334 | } | 333 | } |
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c index e14325dca..d194a989b 100644 --- a/networking/udhcp/dhcprelay.c +++ b/networking/udhcp/dhcprelay.c | |||
@@ -175,7 +175,6 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in | |||
175 | struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) | 175 | struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) |
176 | { | 176 | { |
177 | int res, type; | 177 | int res, type; |
178 | struct xid_item *item; | ||
179 | 178 | ||
180 | /* check packet_type */ | 179 | /* check packet_type */ |
181 | type = get_dhcp_packet_type(p); | 180 | type = get_dhcp_packet_type(p); |
@@ -187,7 +186,7 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in | |||
187 | } | 186 | } |
188 | 187 | ||
189 | /* create new xid entry */ | 188 | /* create new xid entry */ |
190 | item = xid_add(p->xid, client_addr, client); | 189 | xid_add(p->xid, client_addr, client); |
191 | 190 | ||
192 | /* forward request to LAN (server) */ | 191 | /* forward request to LAN (server) */ |
193 | errno = 0; | 192 | errno = 0; |
diff --git a/networking/wget.c b/networking/wget.c index f55b68a38..1f35f8b03 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -50,7 +50,7 @@ static void progress_meter(int flag) | |||
50 | } | 50 | } |
51 | 51 | ||
52 | bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, | 52 | bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, |
53 | G.chunked ? 0 : G.content_len + G.beg_range); | 53 | G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); |
54 | 54 | ||
55 | if (flag == 0) { | 55 | if (flag == 0) { |
56 | /* last call to progress_meter */ | 56 | /* last call to progress_meter */ |
diff --git a/printutils/lpd.c b/printutils/lpd.c index 43c22948f..d91491f1b 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c | |||
@@ -181,8 +181,7 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) | |||
181 | // this call reopens stdio fds to "/dev/null" | 181 | // this call reopens stdio fds to "/dev/null" |
182 | // (no daemonization is done) | 182 | // (no daemonization is done) |
183 | bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); | 183 | bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); |
184 | BB_EXECVP(*argv, argv); | 184 | BB_EXECVP_or_die(argv); |
185 | exit(127); | ||
186 | } | 185 | } |
187 | 186 | ||
188 | // validate input. | 187 | // validate input. |
diff --git a/procps/smemcap.c b/procps/smemcap.c new file mode 100644 index 000000000..06cf93c85 --- /dev/null +++ b/procps/smemcap.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | smemcap - a tool for meaningful memory reporting | ||
3 | |||
4 | Copyright 2008-2009 Matt Mackall <mpm@selenic.com> | ||
5 | |||
6 | This software may be used and distributed according to the terms of | ||
7 | the GNU General Public License version 2 or later, incorporated | ||
8 | herein by reference. | ||
9 | */ | ||
10 | |||
11 | //applet:IF_SMEMCAP(APPLET(smemcap, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | ||
12 | |||
13 | //kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o | ||
14 | |||
15 | //config:config SMEMCAP | ||
16 | //config: bool "smemcap" | ||
17 | //config: default y | ||
18 | //config: help | ||
19 | //config: smemcap is a tool for capturing process data for smem, | ||
20 | //config: a memory usage statistic tool. | ||
21 | |||
22 | #include "libbb.h" | ||
23 | #include "unarchive.h" | ||
24 | |||
25 | struct fileblock { | ||
26 | struct fileblock *next; | ||
27 | char data[TAR_BLOCK_SIZE]; | ||
28 | }; | ||
29 | |||
30 | static void writeheader(const char *path, struct stat *sb, int type) | ||
31 | { | ||
32 | struct tar_header_t header; | ||
33 | int i, sum; | ||
34 | |||
35 | memset(&header, 0, TAR_BLOCK_SIZE); | ||
36 | strcpy(header.name, path); | ||
37 | sprintf(header.mode, "%o", sb->st_mode & 0777); | ||
38 | /* careful to not overflow fields! */ | ||
39 | sprintf(header.uid, "%o", sb->st_uid & 07777777); | ||
40 | sprintf(header.gid, "%o", sb->st_gid & 07777777); | ||
41 | sprintf(header.size, "%o", (unsigned)sb->st_size); | ||
42 | sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL); | ||
43 | header.typeflag = type; | ||
44 | //strcpy(header.magic, "ustar "); - do we want to be standard-compliant? | ||
45 | |||
46 | /* Calculate and store the checksum (the sum of all of the bytes of | ||
47 | * the header). The checksum field must be filled with blanks for the | ||
48 | * calculation. The checksum field is formatted differently from the | ||
49 | * other fields: it has 6 digits, a NUL, then a space -- rather than | ||
50 | * digits, followed by a NUL like the other fields... */ | ||
51 | header.chksum[7] = ' '; | ||
52 | sum = ' ' * 7; | ||
53 | for (i = 0; i < TAR_BLOCK_SIZE; i++) | ||
54 | sum += ((unsigned char*)&header)[i]; | ||
55 | sprintf(header.chksum, "%06o", sum); | ||
56 | |||
57 | xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE); | ||
58 | } | ||
59 | |||
60 | static void archivefile(const char *path) | ||
61 | { | ||
62 | struct fileblock *start, *cur; | ||
63 | struct fileblock **prev = &start; | ||
64 | int fd, r; | ||
65 | unsigned size = 0; | ||
66 | struct stat s; | ||
67 | |||
68 | /* buffer the file */ | ||
69 | fd = xopen(path, O_RDONLY); | ||
70 | do { | ||
71 | cur = xzalloc(sizeof(*cur)); | ||
72 | *prev = cur; | ||
73 | prev = &cur->next; | ||
74 | r = full_read(fd, cur->data, TAR_BLOCK_SIZE); | ||
75 | if (r > 0) | ||
76 | size += r; | ||
77 | } while (r == TAR_BLOCK_SIZE); | ||
78 | |||
79 | /* write archive header */ | ||
80 | fstat(fd, &s); | ||
81 | close(fd); | ||
82 | s.st_size = size; | ||
83 | writeheader(path, &s, '0'); | ||
84 | |||
85 | /* dump file contents */ | ||
86 | for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) { | ||
87 | xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE); | ||
88 | start = cur; | ||
89 | cur = cur->next; | ||
90 | free(start); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static void archivejoin(const char *sub, const char *name) | ||
95 | { | ||
96 | char path[sizeof(long long)*3 + sizeof("/cmdline")]; | ||
97 | sprintf(path, "%s/%s", sub, name); | ||
98 | archivefile(path); | ||
99 | } | ||
100 | |||
101 | //usage:#define smemcap_trivial_usage ">SMEMDATA.TAR" | ||
102 | //usage:#define smemcap_full_usage "\n\n" | ||
103 | //usage: "Collect memory usage data in /proc and write it to stdout" | ||
104 | |||
105 | int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
106 | int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
107 | { | ||
108 | DIR *d; | ||
109 | struct dirent *de; | ||
110 | |||
111 | xchdir("/proc"); | ||
112 | d = xopendir("."); | ||
113 | |||
114 | archivefile("meminfo"); | ||
115 | archivefile("version"); | ||
116 | while ((de = readdir(d)) != NULL) { | ||
117 | if (isdigit(de->d_name[0])) { | ||
118 | struct stat s; | ||
119 | memset(&s, 0, sizeof(s)); | ||
120 | s.st_mode = 0555; | ||
121 | writeheader(de->d_name, &s, '5'); | ||
122 | archivejoin(de->d_name, "smaps"); | ||
123 | archivejoin(de->d_name, "cmdline"); | ||
124 | archivejoin(de->d_name, "stat"); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | return EXIT_SUCCESS; | ||
129 | } | ||
diff --git a/procps/sysctl.c b/procps/sysctl.c index 7a5bf1435..fc601d637 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c | |||
@@ -212,6 +212,7 @@ static int sysctl_handle_preload_file(const char *filename) | |||
212 | //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value | 212 | //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value |
213 | // (but _whitespace_ from ends should be trimmed first (and we do it right)) | 213 | // (but _whitespace_ from ends should be trimmed first (and we do it right)) |
214 | //TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") | 214 | //TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") |
215 | // can it be fixed by removing PARSE_COLLAPSE bit? | ||
215 | while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { | 216 | while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { |
216 | char *tp; | 217 | char *tp; |
217 | sysctl_dots_to_slashes(token[0]); | 218 | sysctl_dots_to_slashes(token[0]); |
diff --git a/procps/top.c b/procps/top.c index 04dd82633..ec8437442 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -686,10 +686,10 @@ static int topmem_sort(char *a, char *b) | |||
686 | n = offsetof(topmem_status_t, vsz) + (sort_field * sizeof(mem_t)); | 686 | n = offsetof(topmem_status_t, vsz) + (sort_field * sizeof(mem_t)); |
687 | l = *(mem_t*)(a + n); | 687 | l = *(mem_t*)(a + n); |
688 | r = *(mem_t*)(b + n); | 688 | r = *(mem_t*)(b + n); |
689 | // if (l == r) { | 689 | if (l == r) { |
690 | // l = a->mapped_rw; | 690 | l = ((topmem_status_t*)a)->dirty; |
691 | // r = b->mapped_rw; | 691 | r = ((topmem_status_t*)b)->dirty; |
692 | // } | 692 | } |
693 | /* We want to avoid unsigned->signed and truncation errors */ | 693 | /* We want to avoid unsigned->signed and truncation errors */ |
694 | /* l>r: -1, l=r: 0, l<r: 1 */ | 694 | /* l>r: -1, l=r: 0, l<r: 1 */ |
695 | n = (l > r) ? -1 : (l != r); | 695 | n = (l > r) ? -1 : (l != r); |
diff --git a/runit/chpst.c b/runit/chpst.c index 1a68eb755..ad0811294 100644 --- a/runit/chpst.c +++ b/runit/chpst.c | |||
@@ -382,6 +382,5 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) | |||
382 | if (opt & OPT_2) | 382 | if (opt & OPT_2) |
383 | close(STDERR_FILENO); | 383 | close(STDERR_FILENO); |
384 | 384 | ||
385 | BB_EXECVP(argv[0], argv); | 385 | BB_EXECVP_or_die(argv); |
386 | bb_perror_msg_and_die("exec %s", argv[0]); | ||
387 | } | 386 | } |
diff --git a/runit/svlogd.c b/runit/svlogd.c index fc8b4abb9..9fe81b900 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c | |||
@@ -354,7 +354,7 @@ static void processorstart(struct logdir *ld) | |||
354 | xmove_fd(fd, 5); | 354 | xmove_fd(fd, 5); |
355 | 355 | ||
356 | // getenv("SHELL")? | 356 | // getenv("SHELL")? |
357 | execl("/bin/sh", "/bin/sh" + 5, "-c", ld->processor, (char*) NULL); | 357 | execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", ld->processor, (char*) NULL); |
358 | bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name); | 358 | bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name); |
359 | } | 359 | } |
360 | ld->fnsave[26] = sv_ch; /* ...restore */ | 360 | ld->fnsave[26] = sv_ch; /* ...restore */ |
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index f343818b1..5685b5bcc 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
@@ -13,8 +13,13 @@ __build: | |||
13 | include scripts/Kbuild.include | 13 | include scripts/Kbuild.include |
14 | 14 | ||
15 | # The filename Kbuild has precedence over Makefile | 15 | # The filename Kbuild has precedence over Makefile |
16 | # bbox: we also try to include Kbuild file in obj tree first | ||
16 | kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) | 17 | kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) |
17 | include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile) | 18 | include $(if $(wildcard $(src)/Kbuild), $(src)/Kbuild, \ |
19 | $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, \ | ||
20 | $(kbuild-dir)/Makefile \ | ||
21 | ) \ | ||
22 | ) | ||
18 | 23 | ||
19 | include scripts/Makefile.lib | 24 | include scripts/Makefile.lib |
20 | 25 | ||
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index ef5181226..50ef37157 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c | |||
@@ -86,7 +86,7 @@ void exec_kernel_doc(char **svec) | |||
86 | fflush(stdout); | 86 | fflush(stdout); |
87 | switch(pid=fork()) { | 87 | switch(pid=fork()) { |
88 | case -1: | 88 | case -1: |
89 | perror("fork"); | 89 | perror("vfork"+1); |
90 | exit(1); | 90 | exit(1); |
91 | case 0: | 91 | case 0: |
92 | rflen = strlen(getenv("SRCTREE")); | 92 | rflen = strlen(getenv("SRCTREE")); |
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 647c7daf7..968158758 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh | |||
@@ -4,6 +4,8 @@ test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } | |||
4 | 4 | ||
5 | # cd to objtree | 5 | # cd to objtree |
6 | cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } | 6 | cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } |
7 | # In separate objtree build, include/ might not exist yet | ||
8 | mkdir include 2>/dev/null | ||
7 | 9 | ||
8 | srctree="$1" | 10 | srctree="$1" |
9 | 11 | ||
@@ -11,20 +13,19 @@ srctree="$1" | |||
11 | src="$srctree/include/applets.src.h" | 13 | src="$srctree/include/applets.src.h" |
12 | dst="include/applets.h" | 14 | dst="include/applets.h" |
13 | s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` | 15 | s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` |
14 | echo "/* DO NOT EDIT. This file is generated from applets.src.h */" >"$dst.$$.tmp" | 16 | old=`cat "$dst" 2>/dev/null` |
15 | # Why "IFS='' read -r REPLY"?? | 17 | # Why "IFS='' read -r REPLY"?? |
16 | # This atrocity is needed to read lines without mangling. | 18 | # This atrocity is needed to read lines without mangling. |
17 | # IFS='' prevents whitespace trimming, | 19 | # IFS='' prevents whitespace trimming, |
18 | # -r suppresses backslash handling. | 20 | # -r suppresses backslash handling. |
21 | new=`echo "/* DO NOT EDIT. This file is generated from applets.src.h */" | ||
19 | while IFS='' read -r REPLY; do | 22 | while IFS='' read -r REPLY; do |
20 | test x"$REPLY" = x"INSERT" && REPLY="$s" | 23 | test x"$REPLY" = x"INSERT" && REPLY="$s" |
21 | printf "%s\n" "$REPLY" | 24 | printf "%s\n" "$REPLY" |
22 | done <"$src" >>"$dst.$$.tmp" | 25 | done <"$src"` |
23 | if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then | 26 | if test x"$new" != x"$old"; then |
24 | rm -- "$dst.$$.tmp" | ||
25 | else | ||
26 | echo " GEN $dst" | 27 | echo " GEN $dst" |
27 | mv -- "$dst.$$.tmp" "$dst" | 28 | printf "%s\n" "$new" >"$dst" |
28 | fi | 29 | fi |
29 | 30 | ||
30 | # (Re)generate include/usage.h | 31 | # (Re)generate include/usage.h |
@@ -35,62 +36,58 @@ dst="include/usage.h" | |||
35 | # with space or tab | 36 | # with space or tab |
36 | # (note: we need to use \\\\ because of ``) | 37 | # (note: we need to use \\\\ because of ``) |
37 | s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` | 38 | s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` |
38 | echo "/* DO NOT EDIT. This file is generated from usage.src.h */" >"$dst.$$.tmp" | 39 | old=`cat "$dst" 2>/dev/null` |
39 | # Why "IFS='' read -r REPLY"?? | 40 | new=`echo "/* DO NOT EDIT. This file is generated from usage.src.h */" |
40 | # This atrocity is needed to read lines without mangling. | ||
41 | # IFS='' prevents whitespace trimming, | ||
42 | # -r suppresses backslash handling. | ||
43 | while IFS='' read -r REPLY; do | 41 | while IFS='' read -r REPLY; do |
44 | test x"$REPLY" = x"INSERT" && REPLY="$s" | 42 | test x"$REPLY" = x"INSERT" && REPLY="$s" |
45 | printf "%s\n" "$REPLY" | 43 | printf "%s\n" "$REPLY" |
46 | done <"$src" >>"$dst.$$.tmp" | 44 | done <"$src"` |
47 | if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then | 45 | if test x"$new" != x"$old"; then |
48 | rm -- "$dst.$$.tmp" | ||
49 | else | ||
50 | echo " GEN $dst" | 46 | echo " GEN $dst" |
51 | mv -- "$dst.$$.tmp" "$dst" | 47 | printf "%s\n" "$new" >"$dst" |
52 | fi | 48 | fi |
53 | 49 | ||
54 | # (Re)generate */Kbuild and */Config.in | 50 | # (Re)generate */Kbuild and */Config.in |
55 | find -type d | while read -r d; do | 51 | { cd -- "$srctree" && find -type d; } | while read -r d; do |
56 | d="${d#./}" | 52 | d="${d#./}" |
53 | |||
57 | src="$srctree/$d/Kbuild.src" | 54 | src="$srctree/$d/Kbuild.src" |
58 | dst="$d/Kbuild" | 55 | dst="$d/Kbuild" |
56 | mkdir -p -- "$d" 2>/dev/null | ||
59 | if test -f "$src"; then | 57 | if test -f "$src"; then |
60 | #echo " CHK $dst" | 58 | #echo " CHK $dst" |
61 | 59 | ||
62 | s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` | 60 | s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` |
63 | 61 | ||
64 | echo "# DO NOT EDIT. This file is generated from Kbuild.src" >"$dst.$$.tmp" | 62 | old=`cat "$dst" 2>/dev/null` |
63 | new=`echo "# DO NOT EDIT. This file is generated from Kbuild.src" | ||
65 | while IFS='' read -r REPLY; do | 64 | while IFS='' read -r REPLY; do |
66 | test x"$REPLY" = x"INSERT" && REPLY="$s" | 65 | test x"$REPLY" = x"INSERT" && REPLY="$s" |
67 | printf "%s\n" "$REPLY" | 66 | printf "%s\n" "$REPLY" |
68 | done <"$src" >>"$dst.$$.tmp" | 67 | done <"$src"` |
69 | if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then | 68 | if test x"$new" != x"$old"; then |
70 | rm -- "$dst.$$.tmp" | ||
71 | else | ||
72 | echo " GEN $dst" | 69 | echo " GEN $dst" |
73 | mv -- "$dst.$$.tmp" "$dst" | 70 | printf "%s\n" "$new" >"$dst" |
74 | fi | 71 | fi |
75 | fi | 72 | fi |
76 | 73 | ||
77 | src="$srctree/$d/Config.src" | 74 | src="$srctree/$d/Config.src" |
78 | dst="$d/Config.in" | 75 | dst="$d/Config.in" |
76 | mkdir -p -- "$d" 2>/dev/null | ||
79 | if test -f "$src"; then | 77 | if test -f "$src"; then |
80 | #echo " CHK $dst" | 78 | #echo " CHK $dst" |
81 | 79 | ||
82 | s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` | 80 | s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` |
83 | 81 | ||
84 | echo "# DO NOT EDIT. This file is generated from Config.src" >"$dst.$$.tmp" | 82 | old=`cat "$dst" 2>/dev/null` |
83 | new=`echo "# DO NOT EDIT. This file is generated from Config.src" | ||
85 | while IFS='' read -r REPLY; do | 84 | while IFS='' read -r REPLY; do |
86 | test x"$REPLY" = x"INSERT" && REPLY="$s" | 85 | test x"$REPLY" = x"INSERT" && REPLY="$s" |
87 | printf "%s\n" "$REPLY" | 86 | printf "%s\n" "$REPLY" |
88 | done <"$src" >>"$dst.$$.tmp" | 87 | done <"$src"` |
89 | if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then | 88 | if test x"$new" != x"$old"; then |
90 | rm -- "$dst.$$.tmp" | ||
91 | else | ||
92 | echo " GEN $dst" | 89 | echo " GEN $dst" |
93 | mv -- "$dst.$$.tmp" "$dst" | 90 | printf "%s\n" "$new" >"$dst" |
94 | fi | 91 | fi |
95 | fi | 92 | fi |
96 | done | 93 | done |
diff --git a/scripts/randomtest b/scripts/randomtest index 8d0d79e64..a102593d3 100755 --- a/scripts/randomtest +++ b/scripts/randomtest | |||
@@ -43,6 +43,10 @@ mv .config.new .config | |||
43 | echo '# CONFIG_DEBUG_PESSIMIZE is not set' >>.config | 43 | echo '# CONFIG_DEBUG_PESSIMIZE is not set' >>.config |
44 | echo '# CONFIG_WERROR is not set' >>.config | 44 | echo '# CONFIG_WERROR is not set' >>.config |
45 | echo "CONFIG_CROSS_COMPILER_PREFIX=\"${CROSS_COMPILER_PREFIX}\"" >>.config | 45 | echo "CONFIG_CROSS_COMPILER_PREFIX=\"${CROSS_COMPILER_PREFIX}\"" >>.config |
46 | echo '# CONFIG_SELINUX is not set' >>.config | ||
47 | echo '# CONFIG_EFENCE is not set' >>.config | ||
48 | echo '# CONFIG_DMALLOC is not set' >>.config | ||
49 | echo '# CONFIG_RFKILL is not set' >>.config | ||
46 | 50 | ||
47 | # If glibc, don't build static | 51 | # If glibc, don't build static |
48 | if test x"$LIBC" = x"glibc"; then | 52 | if test x"$LIBC" = x"glibc"; then |
@@ -53,18 +57,21 @@ if test x"$LIBC" = x"glibc"; then | |||
53 | echo '# CONFIG_STATIC is not set' >>.config | 57 | echo '# CONFIG_STATIC is not set' >>.config |
54 | fi | 58 | fi |
55 | 59 | ||
56 | # If glibc, build static, and remove some things | 60 | # If uclibc, build static, and remove some things |
57 | # likely to not work on uclibc. | 61 | # likely to not work on uclibc. |
58 | if test x"$LIBC" = x"uclibc"; then | 62 | if test x"$LIBC" = x"uclibc"; then |
59 | cat .config \ | 63 | cat .config \ |
60 | | grep -v CONFIG_STATIC \ | 64 | | grep -v CONFIG_STATIC \ |
61 | | grep -v CONFIG_BUILD_LIBBUSYBOX \ | 65 | | grep -v CONFIG_BUILD_LIBBUSYBOX \ |
62 | | grep -v CONFIG_TASKSET \ | ||
63 | | grep -v CONFIG_UNICODE_SUPPORT \ | ||
64 | | grep -v CONFIG_PIE \ | 66 | | grep -v CONFIG_PIE \ |
67 | \ | ||
68 | | grep -v CONFIG_FEATURE_2_4_MODULES \ | ||
65 | >.config.new | 69 | >.config.new |
66 | mv .config.new .config | 70 | mv .config.new .config |
67 | echo 'CONFIG_STATIC=y' >>.config | 71 | echo 'CONFIG_STATIC=y' >>.config |
72 | echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config | ||
73 | echo '# CONFIG_PIE is not set' >>.config | ||
74 | echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config | ||
68 | fi | 75 | fi |
69 | 76 | ||
70 | # If STATIC, remove some things. | 77 | # If STATIC, remove some things. |
@@ -75,6 +82,7 @@ if grep -q "^CONFIG_STATIC=y" .config; then | |||
75 | | grep -v CONFIG_PAM \ | 82 | | grep -v CONFIG_PAM \ |
76 | >.config.new | 83 | >.config.new |
77 | mv .config.new .config | 84 | mv .config.new .config |
85 | echo '# CONFIG_PAM is not set' >>.config | ||
78 | fi | 86 | fi |
79 | 87 | ||
80 | # Regenerate .config with default answers for yanked-off options | 88 | # Regenerate .config with default answers for yanked-off options |
diff --git a/scripts/test_make_O b/scripts/test_make_O new file mode 100755 index 000000000..a0ee6a868 --- /dev/null +++ b/scripts/test_make_O | |||
@@ -0,0 +1,11 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | b=`basename $PWD` | ||
4 | test "${b#busybox}" != "$b" || { echo "Must be run in busybox tree"; exit 1; } | ||
5 | |||
6 | rm -rf ../testdir_make_O.$$ | ||
7 | mkdir ../testdir_make_O.$$ | ||
8 | odir=`cd ../testdir_make_O.$$ && pwd` | ||
9 | test -d "$odir" || exit 1 | ||
10 | |||
11 | make O="$odir" $MAKEOPTS "$@" defconfig busybox 2>&1 | tee test_make_O.log | ||
diff --git a/scripts/trylink b/scripts/trylink index 164f5274c..5994a757b 100755 --- a/scripts/trylink +++ b/scripts/trylink | |||
@@ -85,6 +85,10 @@ LDLIBS="$7" | |||
85 | # The --sort-section option is not supported by older versions of ld | 85 | # The --sort-section option is not supported by older versions of ld |
86 | SORT_SECTION=`check_cc "-Wl,--sort-section,alignment" ""` | 86 | SORT_SECTION=`check_cc "-Wl,--sort-section,alignment" ""` |
87 | 87 | ||
88 | START_GROUP="-Wl,--start-group" | ||
89 | END_GROUP="-Wl,--end-group" | ||
90 | INFO_OPTS="-Wl,--warn-common -Wl,-Map,$EXE.map -Wl,--verbose" | ||
91 | |||
88 | # gold may not support --sort-common (yet) | 92 | # gold may not support --sort-common (yet) |
89 | SORT_COMMON=`check_cc "-Wl,--sort-common" ""` | 93 | SORT_COMMON=`check_cc "-Wl,--sort-common" ""` |
90 | 94 | ||
@@ -114,13 +118,13 @@ LDLIBS=`echo "$LDLIBS" | xargs -n1 | sort | uniq | xargs` | |||
114 | echo "Trying libraries: $LDLIBS" | 118 | echo "Trying libraries: $LDLIBS" |
115 | # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" | 119 | # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" |
116 | l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` | 120 | l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` |
117 | test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" | 121 | test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" |
118 | try $CC $CFLAGS $LDFLAGS \ | 122 | try $CC $CFLAGS $LDFLAGS \ |
119 | -o $EXE \ | 123 | -o $EXE \ |
120 | $SORT_COMMON \ | 124 | $SORT_COMMON \ |
121 | $SORT_SECTION \ | 125 | $SORT_SECTION \ |
122 | $GC_SECTIONS \ | 126 | $GC_SECTIONS \ |
123 | -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ | 127 | $START_GROUP $O_FILES $A_FILES $END_GROUP \ |
124 | $l_list \ | 128 | $l_list \ |
125 | || { | 129 | || { |
126 | echo "Failed: $l_list" | 130 | echo "Failed: $l_list" |
@@ -138,14 +142,14 @@ while test "$LDLIBS"; do | |||
138 | without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` | 142 | without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` |
139 | # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" | 143 | # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" |
140 | l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` | 144 | l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` |
141 | test x"$l_list" != x"" && l_list="-Wl,--start-group $l_list -Wl,--end-group" | 145 | test x"$l_list" != x"" && l_list="$START_GROUP $l_list $END_GROUP" |
142 | $debug && echo "Trying -l options: '$l_list'" | 146 | $debug && echo "Trying -l options: '$l_list'" |
143 | try $CC $CFLAGS $LDFLAGS \ | 147 | try $CC $CFLAGS $LDFLAGS \ |
144 | -o $EXE \ | 148 | -o $EXE \ |
145 | $SORT_COMMON \ | 149 | $SORT_COMMON \ |
146 | $SORT_SECTION \ | 150 | $SORT_SECTION \ |
147 | $GC_SECTIONS \ | 151 | $GC_SECTIONS \ |
148 | -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ | 152 | $START_GROUP $O_FILES $A_FILES $END_GROUP \ |
149 | $l_list | 153 | $l_list |
150 | if test $? = 0; then | 154 | if test $? = 0; then |
151 | echo " Library $one is not needed, excluding it" | 155 | echo " Library $one is not needed, excluding it" |
@@ -169,7 +173,7 @@ done | |||
169 | # Make the binary with final, minimal list of libs | 173 | # Make the binary with final, minimal list of libs |
170 | echo "Final link with: ${LDLIBS:-<none>}" | 174 | echo "Final link with: ${LDLIBS:-<none>}" |
171 | l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` | 175 | l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` |
172 | test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" | 176 | test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" |
173 | # --verbose gives us gobs of info to stdout (e.g. linker script used) | 177 | # --verbose gives us gobs of info to stdout (e.g. linker script used) |
174 | if ! test -f busybox_ldscript; then | 178 | if ! test -f busybox_ldscript; then |
175 | try $CC $CFLAGS $LDFLAGS \ | 179 | try $CC $CFLAGS $LDFLAGS \ |
@@ -177,11 +181,9 @@ if ! test -f busybox_ldscript; then | |||
177 | $SORT_COMMON \ | 181 | $SORT_COMMON \ |
178 | $SORT_SECTION \ | 182 | $SORT_SECTION \ |
179 | $GC_SECTIONS \ | 183 | $GC_SECTIONS \ |
180 | -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ | 184 | $START_GROUP $O_FILES $A_FILES $END_GROUP \ |
181 | $l_list \ | 185 | $l_list \ |
182 | -Wl,--warn-common \ | 186 | $INFO_OPTS \ |
183 | -Wl,-Map,$EXE.map \ | ||
184 | -Wl,--verbose \ | ||
185 | || { | 187 | || { |
186 | cat $EXE.out | 188 | cat $EXE.out |
187 | exit 1 | 189 | exit 1 |
@@ -200,11 +202,9 @@ else | |||
200 | $SORT_SECTION \ | 202 | $SORT_SECTION \ |
201 | $GC_SECTIONS \ | 203 | $GC_SECTIONS \ |
202 | -Wl,-T,busybox_ldscript \ | 204 | -Wl,-T,busybox_ldscript \ |
203 | -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ | 205 | $START_GROUP $O_FILES $A_FILES $END_GROUP \ |
204 | $l_list \ | 206 | $l_list \ |
205 | -Wl,--warn-common \ | 207 | $INFO_OPTS \ |
206 | -Wl,-Map,$EXE.map \ | ||
207 | -Wl,--verbose \ | ||
208 | || { | 208 | || { |
209 | cat $EXE.out | 209 | cat $EXE.out |
210 | exit 1 | 210 | exit 1 |
@@ -233,11 +233,9 @@ if test "$CONFIG_BUILD_LIBBUSYBOX" = y; then | |||
233 | -Wl,--undefined=lbb_main \ | 233 | -Wl,--undefined=lbb_main \ |
234 | $SORT_COMMON \ | 234 | $SORT_COMMON \ |
235 | $SORT_SECTION \ | 235 | $SORT_SECTION \ |
236 | -Wl,--start-group $A_FILES -Wl,--end-group \ | 236 | $START_GROUP $A_FILES $END_GROUP \ |
237 | $l_list \ | 237 | $l_list \ |
238 | -Wl,--warn-common \ | 238 | $INFO_OPTS \ |
239 | -Wl,-Map,$EXE.map \ | ||
240 | -Wl,--verbose \ | ||
241 | || { | 239 | || { |
242 | echo "Linking $EXE failed" | 240 | echo "Linking $EXE failed" |
243 | cat $EXE.out | 241 | cat $EXE.out |
@@ -255,11 +253,9 @@ if test "$CONFIG_FEATURE_SHARED_BUSYBOX" = y; then | |||
255 | $SORT_COMMON \ | 253 | $SORT_COMMON \ |
256 | $SORT_SECTION \ | 254 | $SORT_SECTION \ |
257 | $GC_SECTIONS \ | 255 | $GC_SECTIONS \ |
258 | -Wl,--start-group $O_FILES -Wl,--end-group \ | 256 | $START_GROUP $O_FILES $END_GROUP \ |
259 | -L"$sharedlib_dir" -lbusybox \ | 257 | -L"$sharedlib_dir" -lbusybox \ |
260 | -Wl,--warn-common \ | 258 | $INFO_OPTS \ |
261 | -Wl,-Map,$EXE.map \ | ||
262 | -Wl,--verbose \ | ||
263 | || { | 259 | || { |
264 | echo "Linking $EXE failed" | 260 | echo "Linking $EXE failed" |
265 | cat $EXE.out | 261 | cat $EXE.out |
diff --git a/selinux/runcon.c b/selinux/runcon.c index 4afd1116e..f8ca9a6aa 100644 --- a/selinux/runcon.c +++ b/selinux/runcon.c | |||
@@ -133,6 +133,5 @@ int runcon_main(int argc UNUSED_PARAM, char **argv) | |||
133 | context_str(con)); | 133 | context_str(con)); |
134 | 134 | ||
135 | execvp(argv[0], argv); | 135 | execvp(argv[0], argv); |
136 | |||
137 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | 136 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); |
138 | } | 137 | } |
diff --git a/shell/Config.src b/shell/Config.src index 800911966..f415a5fa6 100644 --- a/shell/Config.src +++ b/shell/Config.src | |||
@@ -110,112 +110,6 @@ config ASH_EXPAND_PRMT | |||
110 | This option recreates the prompt string from the environment | 110 | This option recreates the prompt string from the environment |
111 | variable each time it is displayed. | 111 | variable each time it is displayed. |
112 | 112 | ||
113 | config HUSH | ||
114 | bool "hush" | ||
115 | default y | ||
116 | help | ||
117 | hush is a small shell (22k). It handles the normal flow control | ||
118 | constructs such as if/then/elif/else/fi, for/in/do/done, while loops, | ||
119 | case/esac. Redirections, here documents, $((arithmetic)) | ||
120 | and functions are supported. | ||
121 | |||
122 | It will compile and work on no-mmu systems. | ||
123 | |||
124 | It does not handle select, aliases, brace expansion, | ||
125 | tilde expansion, &>file and >&file redirection of stdout+stderr. | ||
126 | |||
127 | config HUSH_BASH_COMPAT | ||
128 | bool "bash-compatible extensions" | ||
129 | default y | ||
130 | depends on HUSH | ||
131 | help | ||
132 | Enable bash-compatible extensions. | ||
133 | |||
134 | config HUSH_HELP | ||
135 | bool "help builtin" | ||
136 | default y | ||
137 | depends on HUSH | ||
138 | help | ||
139 | Enable help builtin in hush. Code size + ~1 kbyte. | ||
140 | |||
141 | config HUSH_INTERACTIVE | ||
142 | bool "Interactive mode" | ||
143 | default y | ||
144 | depends on HUSH | ||
145 | help | ||
146 | Enable interactive mode (prompt and command editing). | ||
147 | Without this, hush simply reads and executes commands | ||
148 | from stdin just like a shell script from a file. | ||
149 | No prompt, no PS1/PS2 magic shell variables. | ||
150 | |||
151 | config HUSH_JOB | ||
152 | bool "Job control" | ||
153 | default y | ||
154 | depends on HUSH_INTERACTIVE | ||
155 | help | ||
156 | Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current | ||
157 | command (not entire shell), fg/bg builtins work. Without this option, | ||
158 | "cmd &" still works by simply spawning a process and immediately | ||
159 | prompting for next command (or executing next command in a script), | ||
160 | but no separate process group is formed. | ||
161 | |||
162 | config HUSH_TICK | ||
163 | bool "Process substitution" | ||
164 | default y | ||
165 | depends on HUSH | ||
166 | help | ||
167 | Enable process substitution `command` and $(command) in hush. | ||
168 | |||
169 | config HUSH_IF | ||
170 | bool "Support if/then/elif/else/fi" | ||
171 | default y | ||
172 | depends on HUSH | ||
173 | help | ||
174 | Enable if/then/elif/else/fi in hush. | ||
175 | |||
176 | config HUSH_LOOPS | ||
177 | bool "Support for, while and until loops" | ||
178 | default y | ||
179 | depends on HUSH | ||
180 | help | ||
181 | Enable for, while and until loops in hush. | ||
182 | |||
183 | config HUSH_CASE | ||
184 | bool "Support case ... esac statement" | ||
185 | default y | ||
186 | depends on HUSH | ||
187 | help | ||
188 | Enable case ... esac statement in hush. +400 bytes. | ||
189 | |||
190 | config HUSH_FUNCTIONS | ||
191 | bool "Support funcname() { commands; } syntax" | ||
192 | default y | ||
193 | depends on HUSH | ||
194 | help | ||
195 | Enable support for shell functions in hush. +800 bytes. | ||
196 | |||
197 | config HUSH_LOCAL | ||
198 | bool "Support local builtin" | ||
199 | default y | ||
200 | depends on HUSH_FUNCTIONS | ||
201 | help | ||
202 | Enable support for local variables in functions. | ||
203 | |||
204 | config HUSH_EXPORT_N | ||
205 | bool "Support export '-n' option" | ||
206 | default y | ||
207 | depends on HUSH | ||
208 | help | ||
209 | Enable support for export '-n' option in hush. It is a bash extension. | ||
210 | |||
211 | config HUSH_RANDOM_SUPPORT | ||
212 | bool "Pseudorandom generator and $RANDOM variable" | ||
213 | default y | ||
214 | depends on HUSH | ||
215 | help | ||
216 | Enable pseudorandom generator and dynamic variable "$RANDOM". | ||
217 | Each read of "$RANDOM" will generate a new pseudorandom value. | ||
218 | |||
219 | 113 | ||
220 | choice | 114 | choice |
221 | prompt "Choose which shell is aliased to 'sh' name" | 115 | prompt "Choose which shell is aliased to 'sh' name" |
diff --git a/shell/Kbuild.src b/shell/Kbuild.src index d76b35386..c7eb5b61a 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src | |||
@@ -9,9 +9,7 @@ lib-y:= | |||
9 | INSERT | 9 | INSERT |
10 | 10 | ||
11 | lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | 11 | lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
12 | lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o | ||
13 | lib-$(CONFIG_CTTYHACK) += cttyhack.o | 12 | lib-$(CONFIG_CTTYHACK) += cttyhack.o |
14 | 13 | ||
15 | lib-$(CONFIG_SH_MATH_SUPPORT) += math.o | 14 | lib-$(CONFIG_SH_MATH_SUPPORT) += math.o |
16 | lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | 15 | lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
17 | lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o | ||
diff --git a/shell/ash.c b/shell/ash.c index 5ac2a1922..e0b15e343 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -64,9 +64,7 @@ | |||
64 | # define CLEAR_RANDOM_T(rnd) ((void)0) | 64 | # define CLEAR_RANDOM_T(rnd) ((void)0) |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | #define SKIP_definitions 1 | 67 | #include "NUM_APPLETS.h" |
68 | #include "applet_tables.h" | ||
69 | #undef SKIP_definitions | ||
70 | #if NUM_APPLETS == 1 | 68 | #if NUM_APPLETS == 1 |
71 | /* STANDALONE does not make sense, and won't compile */ | 69 | /* STANDALONE does not make sense, and won't compile */ |
72 | # undef CONFIG_FEATURE_SH_STANDALONE | 70 | # undef CONFIG_FEATURE_SH_STANDALONE |
@@ -5216,7 +5214,7 @@ openredirect(union node *redir) | |||
5216 | break; | 5214 | break; |
5217 | case NFROMTO: | 5215 | case NFROMTO: |
5218 | fname = redir->nfile.expfname; | 5216 | fname = redir->nfile.expfname; |
5219 | f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); | 5217 | f = open(fname, O_RDWR|O_CREAT, 0666); |
5220 | if (f < 0) | 5218 | if (f < 0) |
5221 | goto ecreate; | 5219 | goto ecreate; |
5222 | break; | 5220 | break; |
@@ -6507,8 +6505,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6507 | char *startp; | 6505 | char *startp; |
6508 | char *loc; | 6506 | char *loc; |
6509 | char *rmesc, *rmescend; | 6507 | char *rmesc, *rmescend; |
6510 | IF_ASH_BASH_COMPAT(char *repl = NULL;) | 6508 | IF_ASH_BASH_COMPAT(const char *repl = NULL;) |
6511 | IF_ASH_BASH_COMPAT(char null = '\0';) | ||
6512 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) | 6509 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) |
6513 | int saveherefd = herefd; | 6510 | int saveherefd = herefd; |
6514 | int amount, workloc, resetloc; | 6511 | int amount, workloc, resetloc; |
@@ -6629,7 +6626,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6629 | if (!repl) { | 6626 | if (!repl) { |
6630 | repl = parse_sub_pattern(str, varflags & VSQUOTE); | 6627 | repl = parse_sub_pattern(str, varflags & VSQUOTE); |
6631 | if (!repl) | 6628 | if (!repl) |
6632 | repl = &null; | 6629 | repl = nullstr; |
6633 | } | 6630 | } |
6634 | 6631 | ||
6635 | /* If there's no pattern to match, return the expansion unmolested */ | 6632 | /* If there's no pattern to match, return the expansion unmolested */ |
@@ -6680,8 +6677,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6680 | idx = loc; | 6677 | idx = loc; |
6681 | } | 6678 | } |
6682 | 6679 | ||
6683 | for (loc = repl; *loc; loc++) { | 6680 | for (loc = (char*)repl; *loc; loc++) { |
6684 | char *restart_detect = stackblock(); | 6681 | char *restart_detect = stackblock(); |
6682 | if (quotes && *loc == '\\') { | ||
6683 | STPUTC(CTLESC, expdest); | ||
6684 | len++; | ||
6685 | } | ||
6685 | STPUTC(*loc, expdest); | 6686 | STPUTC(*loc, expdest); |
6686 | if (stackblock() != restart_detect) | 6687 | if (stackblock() != restart_detect) |
6687 | goto restart; | 6688 | goto restart; |
@@ -6691,6 +6692,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6691 | if (subtype == VSREPLACE) { | 6692 | if (subtype == VSREPLACE) { |
6692 | while (*idx) { | 6693 | while (*idx) { |
6693 | char *restart_detect = stackblock(); | 6694 | char *restart_detect = stackblock(); |
6695 | if (quotes && *idx == '\\') { | ||
6696 | STPUTC(CTLESC, expdest); | ||
6697 | len++; | ||
6698 | } | ||
6694 | STPUTC(*idx, expdest); | 6699 | STPUTC(*idx, expdest); |
6695 | if (stackblock() != restart_detect) | 6700 | if (stackblock() != restart_detect) |
6696 | goto restart; | 6701 | goto restart; |
@@ -6704,11 +6709,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6704 | /* We've put the replaced text into a buffer at workloc, now | 6709 | /* We've put the replaced text into a buffer at workloc, now |
6705 | * move it to the right place and adjust the stack. | 6710 | * move it to the right place and adjust the stack. |
6706 | */ | 6711 | */ |
6707 | startp = stackblock() + startloc; | ||
6708 | STPUTC('\0', expdest); | 6712 | STPUTC('\0', expdest); |
6709 | memmove(startp, stackblock() + workloc, len); | 6713 | startp = (char *)stackblock() + startloc; |
6710 | startp[len++] = '\0'; | 6714 | memmove(startp, (char *)stackblock() + workloc, len + 1); |
6711 | amount = expdest - ((char *)stackblock() + startloc + len - 1); | 6715 | amount = expdest - (startp + len); |
6712 | STADJUST(-amount, expdest); | 6716 | STADJUST(-amount, expdest); |
6713 | return startp; | 6717 | return startp; |
6714 | } | 6718 | } |
@@ -7008,7 +7012,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7008 | */ | 7012 | */ |
7009 | STPUTC('\0', expdest); | 7013 | STPUTC('\0', expdest); |
7010 | patloc = expdest - (char *)stackblock(); | 7014 | patloc = expdest - (char *)stackblock(); |
7011 | if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, | 7015 | if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, |
7012 | startloc, varflags, | 7016 | startloc, varflags, |
7013 | //TODO: | EXP_REDIR too? All other such places do it too | 7017 | //TODO: | EXP_REDIR too? All other such places do it too |
7014 | /* quotes: */ flags & (EXP_FULL | EXP_CASE), | 7018 | /* quotes: */ flags & (EXP_FULL | EXP_CASE), |
@@ -7171,13 +7175,11 @@ addfname(const char *name) | |||
7171 | exparg.lastp = &sp->next; | 7175 | exparg.lastp = &sp->next; |
7172 | } | 7176 | } |
7173 | 7177 | ||
7174 | static char *expdir; | ||
7175 | |||
7176 | /* | 7178 | /* |
7177 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 7179 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
7178 | */ | 7180 | */ |
7179 | static void | 7181 | static void |
7180 | expmeta(char *enddir, char *name) | 7182 | expmeta(char *expdir, char *enddir, char *name) |
7181 | { | 7183 | { |
7182 | char *p; | 7184 | char *p; |
7183 | const char *cp; | 7185 | const char *cp; |
@@ -7276,7 +7278,7 @@ expmeta(char *enddir, char *name) | |||
7276 | for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) | 7278 | for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) |
7277 | continue; | 7279 | continue; |
7278 | p[-1] = '/'; | 7280 | p[-1] = '/'; |
7279 | expmeta(p, endname); | 7281 | expmeta(expdir, p, endname); |
7280 | } | 7282 | } |
7281 | } | 7283 | } |
7282 | } | 7284 | } |
@@ -7358,6 +7360,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7358 | /* TODO - EXP_REDIR */ | 7360 | /* TODO - EXP_REDIR */ |
7359 | 7361 | ||
7360 | while (str) { | 7362 | while (str) { |
7363 | char *expdir; | ||
7361 | struct strlist **savelastp; | 7364 | struct strlist **savelastp; |
7362 | struct strlist *sp; | 7365 | struct strlist *sp; |
7363 | char *p; | 7366 | char *p; |
@@ -7374,8 +7377,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7374 | int i = strlen(str->text); | 7377 | int i = strlen(str->text); |
7375 | expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ | 7378 | expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ |
7376 | } | 7379 | } |
7377 | 7380 | expmeta(expdir, expdir, p); | |
7378 | expmeta(expdir, p); | ||
7379 | free(expdir); | 7381 | free(expdir); |
7380 | if (p != str->text) | 7382 | if (p != str->text) |
7381 | free(p); | 7383 | free(p); |
@@ -9547,19 +9549,15 @@ evalcommand(union node *cmd, int flags) | |||
9547 | /* Print the command if xflag is set. */ | 9549 | /* Print the command if xflag is set. */ |
9548 | if (xflag) { | 9550 | if (xflag) { |
9549 | int n; | 9551 | int n; |
9550 | const char *p = " %s"; | 9552 | const char *p = " %s" + 1; |
9551 | 9553 | ||
9552 | p++; | ||
9553 | fdprintf(preverrout_fd, p, expandstr(ps4val())); | 9554 | fdprintf(preverrout_fd, p, expandstr(ps4val())); |
9554 | |||
9555 | sp = varlist.list; | 9555 | sp = varlist.list; |
9556 | for (n = 0; n < 2; n++) { | 9556 | for (n = 0; n < 2; n++) { |
9557 | while (sp) { | 9557 | while (sp) { |
9558 | fdprintf(preverrout_fd, p, sp->text); | 9558 | fdprintf(preverrout_fd, p, sp->text); |
9559 | sp = sp->next; | 9559 | sp = sp->next; |
9560 | if (*p == '%') { | 9560 | p = " %s"; |
9561 | p--; | ||
9562 | } | ||
9563 | } | 9561 | } |
9564 | sp = arglist.list; | 9562 | sp = arglist.list; |
9565 | } | 9563 | } |
diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right new file mode 100644 index 000000000..b212c246c --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right | |||
@@ -0,0 +1,10 @@ | |||
1 | 192\.168\.0\.1 | ||
2 | 192\.168\.0\.1[ | ||
3 | 192\.168\.0\.1[ | ||
4 | 192\\.168\\.0\\.1[ | ||
5 | 192\.168\.0\.1[ | ||
6 | 192\.168\.0\.1 | ||
7 | 192\.168\.0\.1[ | ||
8 | 192\.168\.0\.1[ | ||
9 | 192\\.168\\.0\\.1[ | ||
10 | 192\.168\.0\.1[ | ||
diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests new file mode 100755 index 000000000..3fa2f186d --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests | |||
@@ -0,0 +1,21 @@ | |||
1 | # The bug here was triggered by: | ||
2 | # * performin pathname expansion because we see [ | ||
3 | # * replace operator did not escape \ in replace string | ||
4 | |||
5 | IP=192.168.0.1 | ||
6 | |||
7 | rm -f '192.168.0.1[' | ||
8 | echo "${IP//./\\.}" | ||
9 | echo "${IP//./\\.}"'[' # bug was here | ||
10 | echo "${IP//./\\.}[" # bug was here | ||
11 | echo "${IP//./\\\\.}[" # bug was here | ||
12 | echo "192\.168\.0\.1[" | ||
13 | |||
14 | echo >'192.168.0.1[' | ||
15 | echo "${IP//./\\.}" | ||
16 | echo "${IP//./\\.}"'[' # bug was here | ||
17 | echo "${IP//./\\.}[" # bug was here | ||
18 | echo "${IP//./\\\\.}[" # bug was here | ||
19 | echo "192\.168\.0\.1[" | ||
20 | |||
21 | rm -f '192.168.0.1[' | ||
diff --git a/shell/ash_test/ash-redir/redir9.right b/shell/ash_test/ash-redir/redir9.right new file mode 100644 index 000000000..34c2512e4 --- /dev/null +++ b/shell/ash_test/ash-redir/redir9.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Ok | ||
2 | Done:0 | ||
diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests new file mode 100644 index 000000000..8befa611c --- /dev/null +++ b/shell/ash_test/ash-redir/redir9.tests | |||
@@ -0,0 +1,4 @@ | |||
1 | echo Ok >file.tmp | ||
2 | cat 0<>file.tmp | ||
3 | echo Done:$? | ||
4 | rm file.tmp | ||
diff --git a/shell/cttyhack.c b/shell/cttyhack.c index bde2acdc9..67736ad62 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c | |||
@@ -81,6 +81,5 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) | |||
81 | } | 81 | } |
82 | } | 82 | } |
83 | 83 | ||
84 | BB_EXECVP(argv[0], argv); | 84 | BB_EXECVP_or_die(argv); |
85 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | ||
86 | } | 85 | } |
diff --git a/shell/hush.c b/shell/hush.c index 4832e2c48..c5a8ea617 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -101,6 +101,137 @@ | |||
101 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 101 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
102 | #endif | 102 | #endif |
103 | 103 | ||
104 | //applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
105 | //applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
106 | //applet:IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
107 | //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) | ||
108 | //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) | ||
109 | |||
110 | //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o | ||
111 | //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o | ||
112 | |||
113 | //config:config HUSH | ||
114 | //config: bool "hush" | ||
115 | //config: default y | ||
116 | //config: help | ||
117 | //config: hush is a small shell (22k). It handles the normal flow control | ||
118 | //config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops, | ||
119 | //config: case/esac. Redirections, here documents, $((arithmetic)) | ||
120 | //config: and functions are supported. | ||
121 | //config: | ||
122 | //config: It will compile and work on no-mmu systems. | ||
123 | //config: | ||
124 | //config: It does not handle select, aliases, brace expansion, | ||
125 | //config: tilde expansion, &>file and >&file redirection of stdout+stderr. | ||
126 | //config: | ||
127 | //config:config HUSH_BASH_COMPAT | ||
128 | //config: bool "bash-compatible extensions" | ||
129 | //config: default y | ||
130 | //config: depends on HUSH | ||
131 | //config: help | ||
132 | //config: Enable bash-compatible extensions. | ||
133 | //config: | ||
134 | //config:config HUSH_HELP | ||
135 | //config: bool "help builtin" | ||
136 | //config: default y | ||
137 | //config: depends on HUSH | ||
138 | //config: help | ||
139 | //config: Enable help builtin in hush. Code size + ~1 kbyte. | ||
140 | //config: | ||
141 | //config:config HUSH_INTERACTIVE | ||
142 | //config: bool "Interactive mode" | ||
143 | //config: default y | ||
144 | //config: depends on HUSH | ||
145 | //config: help | ||
146 | //config: Enable interactive mode (prompt and command editing). | ||
147 | //config: Without this, hush simply reads and executes commands | ||
148 | //config: from stdin just like a shell script from a file. | ||
149 | //config: No prompt, no PS1/PS2 magic shell variables. | ||
150 | //config: | ||
151 | //config:config HUSH_JOB | ||
152 | //config: bool "Job control" | ||
153 | //config: default y | ||
154 | //config: depends on HUSH_INTERACTIVE | ||
155 | //config: help | ||
156 | //config: Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current | ||
157 | //config: command (not entire shell), fg/bg builtins work. Without this option, | ||
158 | //config: "cmd &" still works by simply spawning a process and immediately | ||
159 | //config: prompting for next command (or executing next command in a script), | ||
160 | //config: but no separate process group is formed. | ||
161 | //config: | ||
162 | //config:config HUSH_TICK | ||
163 | //config: bool "Process substitution" | ||
164 | //config: default y | ||
165 | //config: depends on HUSH | ||
166 | //config: help | ||
167 | //config: Enable process substitution `command` and $(command) in hush. | ||
168 | //config: | ||
169 | //config:config HUSH_IF | ||
170 | //config: bool "Support if/then/elif/else/fi" | ||
171 | //config: default y | ||
172 | //config: depends on HUSH | ||
173 | //config: help | ||
174 | //config: Enable if/then/elif/else/fi in hush. | ||
175 | //config: | ||
176 | //config:config HUSH_LOOPS | ||
177 | //config: bool "Support for, while and until loops" | ||
178 | //config: default y | ||
179 | //config: depends on HUSH | ||
180 | //config: help | ||
181 | //config: Enable for, while and until loops in hush. | ||
182 | //config: | ||
183 | //config:config HUSH_CASE | ||
184 | //config: bool "Support case ... esac statement" | ||
185 | //config: default y | ||
186 | //config: depends on HUSH | ||
187 | //config: help | ||
188 | //config: Enable case ... esac statement in hush. +400 bytes. | ||
189 | //config: | ||
190 | //config:config HUSH_FUNCTIONS | ||
191 | //config: bool "Support funcname() { commands; } syntax" | ||
192 | //config: default y | ||
193 | //config: depends on HUSH | ||
194 | //config: help | ||
195 | //config: Enable support for shell functions in hush. +800 bytes. | ||
196 | //config: | ||
197 | //config:config HUSH_LOCAL | ||
198 | //config: bool "Support local builtin" | ||
199 | //config: default y | ||
200 | //config: depends on HUSH_FUNCTIONS | ||
201 | //config: help | ||
202 | //config: Enable support for local variables in functions. | ||
203 | //config: | ||
204 | //config:config HUSH_RANDOM_SUPPORT | ||
205 | //config: bool "Pseudorandom generator and $RANDOM variable" | ||
206 | //config: default y | ||
207 | //config: depends on HUSH | ||
208 | //config: help | ||
209 | //config: Enable pseudorandom generator and dynamic variable "$RANDOM". | ||
210 | //config: Each read of "$RANDOM" will generate a new pseudorandom value. | ||
211 | //config: | ||
212 | //config:config HUSH_EXPORT_N | ||
213 | //config: bool "Support 'export -n' option" | ||
214 | //config: default y | ||
215 | //config: depends on HUSH | ||
216 | //config: help | ||
217 | //config: export -n unexports variables. It is a bash extension. | ||
218 | //config: | ||
219 | //config:config HUSH_MODE_X | ||
220 | //config: bool "Support 'hush -x' option and 'set -x' command" | ||
221 | //config: default y | ||
222 | //config: depends on HUSH | ||
223 | //config: help | ||
224 | //config: This instructs hush to print commands before execution. | ||
225 | //config: Adds ~300 bytes. | ||
226 | //config: | ||
227 | |||
228 | //usage:#define hush_trivial_usage NOUSAGE_STR | ||
229 | //usage:#define hush_full_usage "" | ||
230 | //usage:#define lash_trivial_usage NOUSAGE_STR | ||
231 | //usage:#define lash_full_usage "" | ||
232 | //usage:#define msh_trivial_usage NOUSAGE_STR | ||
233 | //usage:#define msh_full_usage "" | ||
234 | |||
104 | 235 | ||
105 | /* Build knobs */ | 236 | /* Build knobs */ |
106 | #define LEAK_HUNTING 0 | 237 | #define LEAK_HUNTING 0 |
@@ -117,6 +248,10 @@ | |||
117 | * and therefore waitpid will return the same result as last time) | 248 | * and therefore waitpid will return the same result as last time) |
118 | */ | 249 | */ |
119 | #define ENABLE_HUSH_FAST 0 | 250 | #define ENABLE_HUSH_FAST 0 |
251 | /* TODO: implement simplified code for users which do not need ${var%...} ops | ||
252 | * So far ${var%...} ops are always enabled: | ||
253 | */ | ||
254 | #define ENABLE_HUSH_DOLLAR_OPS 1 | ||
120 | 255 | ||
121 | 256 | ||
122 | #if BUILD_AS_NOMMU | 257 | #if BUILD_AS_NOMMU |
@@ -128,9 +263,7 @@ | |||
128 | # define USE_FOR_MMU(...) | 263 | # define USE_FOR_MMU(...) |
129 | #endif | 264 | #endif |
130 | 265 | ||
131 | #define SKIP_definitions 1 | 266 | #include "NUM_APPLETS.h" |
132 | #include "applet_tables.h" | ||
133 | #undef SKIP_definitions | ||
134 | #if NUM_APPLETS == 1 | 267 | #if NUM_APPLETS == 1 |
135 | /* STANDALONE does not make sense, and won't compile */ | 268 | /* STANDALONE does not make sense, and won't compile */ |
136 | # undef CONFIG_FEATURE_SH_STANDALONE | 269 | # undef CONFIG_FEATURE_SH_STANDALONE |
@@ -529,7 +662,13 @@ struct globals { | |||
529 | */ | 662 | */ |
530 | smallint flag_return_in_progress; | 663 | smallint flag_return_in_progress; |
531 | #endif | 664 | #endif |
532 | smallint fake_mode; | 665 | smallint n_mode; |
666 | #if ENABLE_HUSH_MODE_X | ||
667 | smallint x_mode; | ||
668 | # define G_x_mode (G.x_mode) | ||
669 | #else | ||
670 | # define G_x_mode 0 | ||
671 | #endif | ||
533 | smallint exiting; /* used to prevent EXIT trap recursion */ | 672 | smallint exiting; /* used to prevent EXIT trap recursion */ |
534 | /* These four support $?, $#, and $1 */ | 673 | /* These four support $?, $#, and $1 */ |
535 | smalluint last_exitcode; | 674 | smalluint last_exitcode; |
@@ -550,6 +689,7 @@ struct globals { | |||
550 | const char *cwd; | 689 | const char *cwd; |
551 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ | 690 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ |
552 | struct variable shell_ver; | 691 | struct variable shell_ver; |
692 | char **expanded_assignments; | ||
553 | #if ENABLE_HUSH_FUNCTIONS | 693 | #if ENABLE_HUSH_FUNCTIONS |
554 | struct function *top_func; | 694 | struct function *top_func; |
555 | # if ENABLE_HUSH_LOCAL | 695 | # if ENABLE_HUSH_LOCAL |
@@ -1217,7 +1357,7 @@ static void hush_exit(int exitcode) | |||
1217 | 1357 | ||
1218 | static int check_and_run_traps(int sig) | 1358 | static int check_and_run_traps(int sig) |
1219 | { | 1359 | { |
1220 | static const struct timespec zero_timespec = { 0, 0 }; | 1360 | static const struct timespec zero_timespec; |
1221 | smalluint save_rcode; | 1361 | smalluint save_rcode; |
1222 | int last_sig = 0; | 1362 | int last_sig = 0; |
1223 | 1363 | ||
@@ -1321,9 +1461,23 @@ static struct variable *get_local_var(const char *name) | |||
1321 | 1461 | ||
1322 | static const char* FAST_FUNC get_local_var_value(const char *name) | 1462 | static const char* FAST_FUNC get_local_var_value(const char *name) |
1323 | { | 1463 | { |
1324 | struct variable **pp = get_ptr_to_local_var(name); | 1464 | struct variable **vpp; |
1325 | if (pp) | 1465 | |
1326 | return strchr((*pp)->varstr, '=') + 1; | 1466 | if (G.expanded_assignments) { |
1467 | char **cpp = G.expanded_assignments; | ||
1468 | int len = strlen(name); | ||
1469 | while (*cpp) { | ||
1470 | char *cp = *cpp; | ||
1471 | if (strncmp(cp, name, len) == 0 && cp[len] == '=') | ||
1472 | return cp + len + 1; | ||
1473 | cpp++; | ||
1474 | } | ||
1475 | } | ||
1476 | |||
1477 | vpp = get_ptr_to_local_var(name); | ||
1478 | if (vpp) | ||
1479 | return strchr((*vpp)->varstr, '=') + 1; | ||
1480 | |||
1327 | if (strcmp(name, "PPID") == 0) | 1481 | if (strcmp(name, "PPID") == 0) |
1328 | return utoa(G.root_ppid); | 1482 | return utoa(G.root_ppid); |
1329 | // bash compat: UID? EUID? | 1483 | // bash compat: UID? EUID? |
@@ -2683,7 +2837,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2683 | } | 2837 | } |
2684 | } | 2838 | } |
2685 | } else if (exp_op == ':') { | 2839 | } else if (exp_op == ':') { |
2686 | #if ENABLE_HUSH_BASH_COMPAT | 2840 | #if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT |
2687 | /* It's ${var:N[:M]} bashism. | 2841 | /* It's ${var:N[:M]} bashism. |
2688 | * Note that in encoded form it has TWO parts: | 2842 | * Note that in encoded form it has TWO parts: |
2689 | * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> | 2843 | * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> |
@@ -2952,11 +3106,14 @@ static char* expand_strvec_to_string(char **argv) | |||
2952 | static char **expand_assignments(char **argv, int count) | 3106 | static char **expand_assignments(char **argv, int count) |
2953 | { | 3107 | { |
2954 | int i; | 3108 | int i; |
2955 | char **p = NULL; | 3109 | char **p; |
3110 | |||
3111 | G.expanded_assignments = p = NULL; | ||
2956 | /* Expand assignments into one string each */ | 3112 | /* Expand assignments into one string each */ |
2957 | for (i = 0; i < count; i++) { | 3113 | for (i = 0; i < count; i++) { |
2958 | p = add_string_to_strings(p, expand_string_to_string(argv[i])); | 3114 | G.expanded_assignments = p = add_string_to_strings(p, expand_string_to_string(argv[i])); |
2959 | } | 3115 | } |
3116 | G.expanded_assignments = NULL; | ||
2960 | return p; | 3117 | return p; |
2961 | } | 3118 | } |
2962 | 3119 | ||
@@ -3210,15 +3367,11 @@ static void setup_heredoc(struct redir_struct *redir) | |||
3210 | #if !BB_MMU | 3367 | #if !BB_MMU |
3211 | to_free = NULL; | 3368 | to_free = NULL; |
3212 | #endif | 3369 | #endif |
3213 | pid = vfork(); | 3370 | pid = xvfork(); |
3214 | if (pid < 0) | ||
3215 | bb_perror_msg_and_die("vfork"); | ||
3216 | if (pid == 0) { | 3371 | if (pid == 0) { |
3217 | /* child */ | 3372 | /* child */ |
3218 | disable_restore_tty_pgrp_on_exit(); | 3373 | disable_restore_tty_pgrp_on_exit(); |
3219 | pid = BB_MMU ? fork() : vfork(); | 3374 | pid = BB_MMU ? xfork() : xvfork(); |
3220 | if (pid < 0) | ||
3221 | bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); | ||
3222 | if (pid != 0) | 3375 | if (pid != 0) |
3223 | _exit(0); | 3376 | _exit(0); |
3224 | /* grandchild */ | 3377 | /* grandchild */ |
@@ -3694,6 +3847,35 @@ static void execvp_or_die(char **argv) | |||
3694 | _exit(127); /* bash compat */ | 3847 | _exit(127); /* bash compat */ |
3695 | } | 3848 | } |
3696 | 3849 | ||
3850 | #if ENABLE_HUSH_MODE_X | ||
3851 | static void dump_cmd_in_x_mode(char **argv) | ||
3852 | { | ||
3853 | if (G_x_mode && argv) { | ||
3854 | /* We want to output the line in one write op */ | ||
3855 | char *buf, *p; | ||
3856 | int len; | ||
3857 | int n; | ||
3858 | |||
3859 | len = 3; | ||
3860 | n = 0; | ||
3861 | while (argv[n]) | ||
3862 | len += strlen(argv[n++]) + 1; | ||
3863 | buf = xmalloc(len); | ||
3864 | buf[0] = '+'; | ||
3865 | p = buf + 1; | ||
3866 | n = 0; | ||
3867 | while (argv[n]) | ||
3868 | p += sprintf(p, " %s", argv[n++]); | ||
3869 | *p++ = '\n'; | ||
3870 | *p = '\0'; | ||
3871 | fputs(buf, stderr); | ||
3872 | free(buf); | ||
3873 | } | ||
3874 | } | ||
3875 | #else | ||
3876 | # define dump_cmd_in_x_mode(argv) ((void)0) | ||
3877 | #endif | ||
3878 | |||
3697 | #if BB_MMU | 3879 | #if BB_MMU |
3698 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ | 3880 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ |
3699 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) | 3881 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) |
@@ -3715,11 +3897,18 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
3715 | { | 3897 | { |
3716 | char **new_env; | 3898 | char **new_env; |
3717 | 3899 | ||
3718 | /* Case when we are here: ... | var=val | ... */ | 3900 | new_env = expand_assignments(argv, assignment_cnt); |
3719 | if (!argv[assignment_cnt]) | 3901 | dump_cmd_in_x_mode(new_env); |
3902 | |||
3903 | if (!argv[assignment_cnt]) { | ||
3904 | /* Case when we are here: ... | var=val | ... | ||
3905 | * (note that we do not exit early, i.e., do not optimize out | ||
3906 | * expand_assignments(): think about ... | var=`sleep 1` | ... | ||
3907 | */ | ||
3908 | free_strings(new_env); | ||
3720 | _exit(EXIT_SUCCESS); | 3909 | _exit(EXIT_SUCCESS); |
3910 | } | ||
3721 | 3911 | ||
3722 | new_env = expand_assignments(argv, assignment_cnt); | ||
3723 | #if BB_MMU | 3912 | #if BB_MMU |
3724 | set_vars_and_save_old(new_env); | 3913 | set_vars_and_save_old(new_env); |
3725 | free(new_env); /* optional */ | 3914 | free(new_env); /* optional */ |
@@ -3729,6 +3918,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
3729 | nommu_save->new_env = new_env; | 3918 | nommu_save->new_env = new_env; |
3730 | nommu_save->old_vars = set_vars_and_save_old(new_env); | 3919 | nommu_save->old_vars = set_vars_and_save_old(new_env); |
3731 | #endif | 3920 | #endif |
3921 | |||
3732 | if (argv_expanded) { | 3922 | if (argv_expanded) { |
3733 | argv = argv_expanded; | 3923 | argv = argv_expanded; |
3734 | } else { | 3924 | } else { |
@@ -3737,6 +3927,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
3737 | nommu_save->argv = argv; | 3927 | nommu_save->argv = argv; |
3738 | #endif | 3928 | #endif |
3739 | } | 3929 | } |
3930 | dump_cmd_in_x_mode(argv); | ||
3740 | 3931 | ||
3741 | #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU | 3932 | #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU |
3742 | if (strchr(argv[0], '/') != NULL) | 3933 | if (strchr(argv[0], '/') != NULL) |
@@ -4144,15 +4335,36 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | |||
4144 | * backgrounded: cmd & { list } & | 4335 | * backgrounded: cmd & { list } & |
4145 | * subshell: ( list ) [&] | 4336 | * subshell: ( list ) [&] |
4146 | */ | 4337 | */ |
4338 | #if !ENABLE_HUSH_MODE_X | ||
4339 | #define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, char argv_expanded) \ | ||
4340 | redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) | ||
4341 | #endif | ||
4342 | static int redirect_and_varexp_helper(char ***new_env_p, struct variable **old_vars_p, struct command *command, int squirrel[3], char **argv_expanded) | ||
4343 | { | ||
4344 | /* setup_redirects acts on file descriptors, not FILEs. | ||
4345 | * This is perfect for work that comes after exec(). | ||
4346 | * Is it really safe for inline use? Experimentally, | ||
4347 | * things seem to work. */ | ||
4348 | int rcode = setup_redirects(command, squirrel); | ||
4349 | if (rcode == 0) { | ||
4350 | char **new_env = expand_assignments(command->argv, command->assignment_cnt); | ||
4351 | *new_env_p = new_env; | ||
4352 | dump_cmd_in_x_mode(new_env); | ||
4353 | dump_cmd_in_x_mode(argv_expanded); | ||
4354 | if (old_vars_p) | ||
4355 | *old_vars_p = set_vars_and_save_old(new_env); | ||
4356 | } | ||
4357 | return rcode; | ||
4358 | } | ||
4147 | static NOINLINE int run_pipe(struct pipe *pi) | 4359 | static NOINLINE int run_pipe(struct pipe *pi) |
4148 | { | 4360 | { |
4149 | static const char *const null_ptr = NULL; | 4361 | static const char *const null_ptr = NULL; |
4150 | int i; | 4362 | |
4151 | int nextin; | 4363 | int cmd_no; |
4364 | int next_infd; | ||
4152 | struct command *command; | 4365 | struct command *command; |
4153 | char **argv_expanded; | 4366 | char **argv_expanded; |
4154 | char **argv; | 4367 | char **argv; |
4155 | char *p; | ||
4156 | /* it is not always needed, but we aim to smaller code */ | 4368 | /* it is not always needed, but we aim to smaller code */ |
4157 | int squirrel[] = { -1, -1, -1 }; | 4369 | int squirrel[] = { -1, -1, -1 }; |
4158 | int rcode; | 4370 | int rcode; |
@@ -4162,7 +4374,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4162 | 4374 | ||
4163 | IF_HUSH_JOB(pi->pgrp = -1;) | 4375 | IF_HUSH_JOB(pi->pgrp = -1;) |
4164 | pi->stopped_cmds = 0; | 4376 | pi->stopped_cmds = 0; |
4165 | command = &(pi->cmds[0]); | 4377 | command = &pi->cmds[0]; |
4166 | argv_expanded = NULL; | 4378 | argv_expanded = NULL; |
4167 | 4379 | ||
4168 | if (pi->num_cmds != 1 | 4380 | if (pi->num_cmds != 1 |
@@ -4229,29 +4441,59 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4229 | if (argv[command->assignment_cnt] == NULL) { | 4441 | if (argv[command->assignment_cnt] == NULL) { |
4230 | /* Assignments, but no command */ | 4442 | /* Assignments, but no command */ |
4231 | /* Ensure redirects take effect (that is, create files). | 4443 | /* Ensure redirects take effect (that is, create files). |
4232 | * Try "a=t >file": */ | 4444 | * Try "a=t >file" */ |
4445 | #if 0 /* A few cases in testsuite fail with this code. FIXME */ | ||
4446 | rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, squirrel, /*argv_expanded:*/ NULL); | ||
4447 | /* Set shell variables */ | ||
4448 | if (new_env) { | ||
4449 | argv = new_env; | ||
4450 | while (*argv) { | ||
4451 | set_local_var(*argv, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | ||
4452 | /* Do we need to flag set_local_var() errors? | ||
4453 | * "assignment to readonly var" and "putenv error" | ||
4454 | */ | ||
4455 | argv++; | ||
4456 | } | ||
4457 | } | ||
4458 | /* Redirect error sets $? to 1. Otherwise, | ||
4459 | * if evaluating assignment value set $?, retain it. | ||
4460 | * Try "false; q=`exit 2`; echo $?" - should print 2: */ | ||
4461 | if (rcode == 0) | ||
4462 | rcode = G.last_exitcode; | ||
4463 | /* Exit, _skipping_ variable restoring code: */ | ||
4464 | goto clean_up_and_ret0; | ||
4465 | |||
4466 | #else /* Older, bigger, but more correct code */ | ||
4467 | |||
4233 | rcode = setup_redirects(command, squirrel); | 4468 | rcode = setup_redirects(command, squirrel); |
4234 | restore_redirects(squirrel); | 4469 | restore_redirects(squirrel); |
4235 | /* Set shell variables */ | 4470 | /* Set shell variables */ |
4471 | if (G_x_mode) | ||
4472 | bb_putchar_stderr('+'); | ||
4236 | while (*argv) { | 4473 | while (*argv) { |
4237 | p = expand_string_to_string(*argv); | 4474 | char *p = expand_string_to_string(*argv); |
4475 | if (G_x_mode) | ||
4476 | fprintf(stderr, " %s", p); | ||
4238 | debug_printf_exec("set shell var:'%s'->'%s'\n", | 4477 | debug_printf_exec("set shell var:'%s'->'%s'\n", |
4239 | *argv, p); | 4478 | *argv, p); |
4240 | set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | 4479 | set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); |
4480 | /* Do we need to flag set_local_var() errors? | ||
4481 | * "assignment to readonly var" and "putenv error" | ||
4482 | */ | ||
4241 | argv++; | 4483 | argv++; |
4242 | } | 4484 | } |
4243 | /* Redirect error sets $? to 1. Othervise, | 4485 | if (G_x_mode) |
4486 | bb_putchar_stderr('\n'); | ||
4487 | /* Redirect error sets $? to 1. Otherwise, | ||
4244 | * if evaluating assignment value set $?, retain it. | 4488 | * if evaluating assignment value set $?, retain it. |
4245 | * Try "false; q=`exit 2`; echo $?" - should print 2: */ | 4489 | * Try "false; q=`exit 2`; echo $?" - should print 2: */ |
4246 | if (rcode == 0) | 4490 | if (rcode == 0) |
4247 | rcode = G.last_exitcode; | 4491 | rcode = G.last_exitcode; |
4248 | /* Do we need to flag set_local_var() errors? | ||
4249 | * "assignment to readonly var" and "putenv error" | ||
4250 | */ | ||
4251 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 4492 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
4252 | debug_leave(); | 4493 | debug_leave(); |
4253 | debug_printf_exec("run_pipe: return %d\n", rcode); | 4494 | debug_printf_exec("run_pipe: return %d\n", rcode); |
4254 | return rcode; | 4495 | return rcode; |
4496 | #endif | ||
4255 | } | 4497 | } |
4256 | 4498 | ||
4257 | /* Expand the rest into (possibly) many strings each */ | 4499 | /* Expand the rest into (possibly) many strings each */ |
@@ -4292,14 +4534,8 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4292 | goto clean_up_and_ret1; | 4534 | goto clean_up_and_ret1; |
4293 | } | 4535 | } |
4294 | } | 4536 | } |
4295 | /* setup_redirects acts on file descriptors, not FILEs. | 4537 | rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); |
4296 | * This is perfect for work that comes after exec(). | ||
4297 | * Is it really safe for inline use? Experimentally, | ||
4298 | * things seem to work. */ | ||
4299 | rcode = setup_redirects(command, squirrel); | ||
4300 | if (rcode == 0) { | 4538 | if (rcode == 0) { |
4301 | new_env = expand_assignments(argv, command->assignment_cnt); | ||
4302 | old_vars = set_vars_and_save_old(new_env); | ||
4303 | if (!funcp) { | 4539 | if (!funcp) { |
4304 | debug_printf_exec(": builtin '%s' '%s'...\n", | 4540 | debug_printf_exec(": builtin '%s' '%s'...\n", |
4305 | x->b_cmd, argv_expanded[1]); | 4541 | x->b_cmd, argv_expanded[1]); |
@@ -4322,12 +4558,11 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4322 | } | 4558 | } |
4323 | #endif | 4559 | #endif |
4324 | } | 4560 | } |
4325 | #if ENABLE_FEATURE_SH_STANDALONE | ||
4326 | clean_up_and_ret: | 4561 | clean_up_and_ret: |
4327 | #endif | ||
4328 | restore_redirects(squirrel); | ||
4329 | unset_vars(new_env); | 4562 | unset_vars(new_env); |
4330 | add_vars(old_vars); | 4563 | add_vars(old_vars); |
4564 | /* clean_up_and_ret0: */ | ||
4565 | restore_redirects(squirrel); | ||
4331 | clean_up_and_ret1: | 4566 | clean_up_and_ret1: |
4332 | free(argv_expanded); | 4567 | free(argv_expanded); |
4333 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 4568 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
@@ -4336,20 +4571,18 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4336 | return rcode; | 4571 | return rcode; |
4337 | } | 4572 | } |
4338 | 4573 | ||
4339 | #if ENABLE_FEATURE_SH_STANDALONE | 4574 | if (ENABLE_FEATURE_SH_STANDALONE) { |
4340 | i = find_applet_by_name(argv_expanded[0]); | 4575 | int n = find_applet_by_name(argv_expanded[0]); |
4341 | if (i >= 0 && APPLET_IS_NOFORK(i)) { | 4576 | if (n >= 0 && APPLET_IS_NOFORK(n)) { |
4342 | rcode = setup_redirects(command, squirrel); | 4577 | rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); |
4343 | if (rcode == 0) { | 4578 | if (rcode == 0) { |
4344 | new_env = expand_assignments(argv, command->assignment_cnt); | 4579 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", |
4345 | old_vars = set_vars_and_save_old(new_env); | 4580 | argv_expanded[0], argv_expanded[1]); |
4346 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", | 4581 | rcode = run_nofork_applet(n, argv_expanded); |
4347 | argv_expanded[0], argv_expanded[1]); | 4582 | } |
4348 | rcode = run_nofork_applet(i, argv_expanded); | 4583 | goto clean_up_and_ret; |
4349 | } | 4584 | } |
4350 | goto clean_up_and_ret; | ||
4351 | } | 4585 | } |
4352 | #endif | ||
4353 | /* It is neither builtin nor applet. We must fork. */ | 4586 | /* It is neither builtin nor applet. We must fork. */ |
4354 | } | 4587 | } |
4355 | 4588 | ||
@@ -4360,9 +4593,10 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4360 | 4593 | ||
4361 | /* Going to fork a child per each pipe member */ | 4594 | /* Going to fork a child per each pipe member */ |
4362 | pi->alive_cmds = 0; | 4595 | pi->alive_cmds = 0; |
4363 | nextin = 0; | 4596 | next_infd = 0; |
4364 | 4597 | ||
4365 | for (i = 0; i < pi->num_cmds; i++) { | 4598 | cmd_no = 0; |
4599 | while (cmd_no < pi->num_cmds) { | ||
4366 | struct fd_pair pipefds; | 4600 | struct fd_pair pipefds; |
4367 | #if !BB_MMU | 4601 | #if !BB_MMU |
4368 | volatile nommu_save_t nommu_save; | 4602 | volatile nommu_save_t nommu_save; |
@@ -4371,7 +4605,8 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4371 | nommu_save.argv = NULL; | 4605 | nommu_save.argv = NULL; |
4372 | nommu_save.argv_from_re_execing = NULL; | 4606 | nommu_save.argv_from_re_execing = NULL; |
4373 | #endif | 4607 | #endif |
4374 | command = &(pi->cmds[i]); | 4608 | command = &pi->cmds[cmd_no]; |
4609 | cmd_no++; | ||
4375 | if (command->argv) { | 4610 | if (command->argv) { |
4376 | debug_printf_exec(": pipe member '%s' '%s'...\n", | 4611 | debug_printf_exec(": pipe member '%s' '%s'...\n", |
4377 | command->argv[0], command->argv[1]); | 4612 | command->argv[0], command->argv[1]); |
@@ -4382,7 +4617,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4382 | /* pipes are inserted between pairs of commands */ | 4617 | /* pipes are inserted between pairs of commands */ |
4383 | pipefds.rd = 0; | 4618 | pipefds.rd = 0; |
4384 | pipefds.wr = 1; | 4619 | pipefds.wr = 1; |
4385 | if ((i + 1) < pi->num_cmds) | 4620 | if (cmd_no < pi->num_cmds) |
4386 | xpiped_pair(pipefds); | 4621 | xpiped_pair(pipefds); |
4387 | 4622 | ||
4388 | command->pid = BB_MMU ? fork() : vfork(); | 4623 | command->pid = BB_MMU ? fork() : vfork(); |
@@ -4415,7 +4650,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4415 | if (open(bb_dev_null, O_RDONLY)) | 4650 | if (open(bb_dev_null, O_RDONLY)) |
4416 | xopen("/", O_RDONLY); | 4651 | xopen("/", O_RDONLY); |
4417 | } else { | 4652 | } else { |
4418 | xmove_fd(nextin, 0); | 4653 | xmove_fd(next_infd, 0); |
4419 | } | 4654 | } |
4420 | xmove_fd(pipefds.wr, 1); | 4655 | xmove_fd(pipefds.wr, 1); |
4421 | if (pipefds.rd > 1) | 4656 | if (pipefds.rd > 1) |
@@ -4452,7 +4687,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4452 | argv_expanded = NULL; | 4687 | argv_expanded = NULL; |
4453 | if (command->pid < 0) { /* [v]fork failed */ | 4688 | if (command->pid < 0) { /* [v]fork failed */ |
4454 | /* Clearly indicate, was it fork or vfork */ | 4689 | /* Clearly indicate, was it fork or vfork */ |
4455 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); | 4690 | bb_perror_msg(BB_MMU ? "vfork"+1 : "vfork"); |
4456 | } else { | 4691 | } else { |
4457 | pi->alive_cmds++; | 4692 | pi->alive_cmds++; |
4458 | #if ENABLE_HUSH_JOB | 4693 | #if ENABLE_HUSH_JOB |
@@ -4462,12 +4697,12 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4462 | #endif | 4697 | #endif |
4463 | } | 4698 | } |
4464 | 4699 | ||
4465 | if (i) | 4700 | if (cmd_no > 1) |
4466 | close(nextin); | 4701 | close(next_infd); |
4467 | if ((i + 1) < pi->num_cmds) | 4702 | if (cmd_no < pi->num_cmds) |
4468 | close(pipefds.wr); | 4703 | close(pipefds.wr); |
4469 | /* Pass read (output) pipe end to next iteration */ | 4704 | /* Pass read (output) pipe end to next iteration */ |
4470 | nextin = pipefds.rd; | 4705 | next_infd = pipefds.rd; |
4471 | } | 4706 | } |
4472 | 4707 | ||
4473 | if (!pi->alive_cmds) { | 4708 | if (!pi->alive_cmds) { |
@@ -4899,7 +5134,7 @@ static int run_and_free_list(struct pipe *pi) | |||
4899 | { | 5134 | { |
4900 | int rcode = 0; | 5135 | int rcode = 0; |
4901 | debug_printf_exec("run_and_free_list entered\n"); | 5136 | debug_printf_exec("run_and_free_list entered\n"); |
4902 | if (!G.fake_mode) { | 5137 | if (!G.n_mode) { |
4903 | debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); | 5138 | debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); |
4904 | rcode = run_list(pi); | 5139 | rcode = run_list(pi); |
4905 | } | 5140 | } |
@@ -5588,10 +5823,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) | |||
5588 | # endif | 5823 | # endif |
5589 | 5824 | ||
5590 | xpipe(channel); | 5825 | xpipe(channel); |
5591 | pid = BB_MMU ? fork() : vfork(); | 5826 | pid = BB_MMU ? xfork() : xvfork(); |
5592 | if (pid < 0) | ||
5593 | bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); | ||
5594 | |||
5595 | if (pid == 0) { /* child */ | 5827 | if (pid == 0) { /* child */ |
5596 | disable_restore_tty_pgrp_on_exit(); | 5828 | disable_restore_tty_pgrp_on_exit(); |
5597 | /* Process substitution is not considered to be usual | 5829 | /* Process substitution is not considered to be usual |
@@ -5829,7 +6061,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
5829 | /* command remains "open", available for possible redirects */ | 6061 | /* command remains "open", available for possible redirects */ |
5830 | } | 6062 | } |
5831 | 6063 | ||
5832 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT | 6064 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS |
5833 | /* Subroutines for copying $(...) and `...` things */ | 6065 | /* Subroutines for copying $(...) and `...` things */ |
5834 | static void add_till_backquote(o_string *dest, struct in_str *input); | 6066 | static void add_till_backquote(o_string *dest, struct in_str *input); |
5835 | /* '...' */ | 6067 | /* '...' */ |
@@ -5930,9 +6162,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
5930 | { | 6162 | { |
5931 | int ch; | 6163 | int ch; |
5932 | char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; | 6164 | char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; |
5933 | #if ENABLE_HUSH_BASH_COMPAT | 6165 | # if ENABLE_HUSH_BASH_COMPAT |
5934 | char end_char2 = end_ch >> 8; | 6166 | char end_char2 = end_ch >> 8; |
5935 | #endif | 6167 | # endif |
5936 | end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); | 6168 | end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); |
5937 | 6169 | ||
5938 | while (1) { | 6170 | while (1) { |
@@ -5985,7 +6217,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
5985 | } | 6217 | } |
5986 | return ch; | 6218 | return ch; |
5987 | } | 6219 | } |
5988 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ | 6220 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS */ |
5989 | 6221 | ||
5990 | /* Return code: 0 for OK, 1 for syntax error */ | 6222 | /* Return code: 0 for OK, 1 for syntax error */ |
5991 | #if BB_MMU | 6223 | #if BB_MMU |
@@ -6091,7 +6323,11 @@ static int parse_dollar(o_string *as_string, | |||
6091 | again: | 6323 | again: |
6092 | if (!BB_MMU) | 6324 | if (!BB_MMU) |
6093 | pos = dest->length; | 6325 | pos = dest->length; |
6326 | #if ENABLE_HUSH_DOLLAR_OPS | ||
6094 | last_ch = add_till_closing_bracket(dest, input, end_ch); | 6327 | last_ch = add_till_closing_bracket(dest, input, end_ch); |
6328 | #else | ||
6329 | #error Simple code to only allow ${var} is not implemented | ||
6330 | #endif | ||
6095 | if (as_string) { | 6331 | if (as_string) { |
6096 | o_addstr(as_string, dest->data + pos); | 6332 | o_addstr(as_string, dest->data + pos); |
6097 | o_addchr(as_string, last_ch); | 6333 | o_addchr(as_string, last_ch); |
@@ -6924,8 +7160,8 @@ static int set_mode(const char cstate, const char mode) | |||
6924 | { | 7160 | { |
6925 | int state = (cstate == '-' ? 1 : 0); | 7161 | int state = (cstate == '-' ? 1 : 0); |
6926 | switch (mode) { | 7162 | switch (mode) { |
6927 | case 'n': G.fake_mode = state; break; | 7163 | case 'n': G.n_mode = state; break; |
6928 | case 'x': /*G.debug_mode = state;*/ break; | 7164 | case 'x': IF_HUSH_MODE_X(G_x_mode = state;) break; |
6929 | default: return EXIT_FAILURE; | 7165 | default: return EXIT_FAILURE; |
6930 | } | 7166 | } |
6931 | return EXIT_SUCCESS; | 7167 | return EXIT_SUCCESS; |
@@ -7154,7 +7390,7 @@ int hush_main(int argc, char **argv) | |||
7154 | #endif | 7390 | #endif |
7155 | case 'n': | 7391 | case 'n': |
7156 | case 'x': | 7392 | case 'x': |
7157 | if (!set_mode('-', opt)) | 7393 | if (set_mode('-', opt) == 0) /* no error */ |
7158 | break; | 7394 | break; |
7159 | default: | 7395 | default: |
7160 | #ifndef BB_VER | 7396 | #ifndef BB_VER |
diff --git a/shell/hush_test/hush-vars/var_serial.right b/shell/hush_test/hush-vars/var_serial.right new file mode 100644 index 000000000..42aa33057 --- /dev/null +++ b/shell/hush_test/hush-vars/var_serial.right | |||
@@ -0,0 +1,5 @@ | |||
1 | Assignments only: c=a | ||
2 | Assignments and a command: c=a | ||
3 | Assignments and a builtin: c=a | ||
4 | Assignments and a function: c=a | ||
5 | Done | ||
diff --git a/shell/hush_test/hush-vars/var_serial.tests b/shell/hush_test/hush-vars/var_serial.tests new file mode 100755 index 000000000..6b4a4cdf7 --- /dev/null +++ b/shell/hush_test/hush-vars/var_serial.tests | |||
@@ -0,0 +1,22 @@ | |||
1 | a=a | ||
2 | |||
3 | b=b | ||
4 | c=c | ||
5 | # Second assignment depends on the first: | ||
6 | b=$a c=$b | ||
7 | echo Assignments only: c=$c | ||
8 | |||
9 | b=b | ||
10 | c=c | ||
11 | b=$a c=$b "$THIS_SH" -c 'echo Assignments and a command: c=$c' | ||
12 | |||
13 | b=b | ||
14 | c=c | ||
15 | b=$a c=$b eval 'echo Assignments and a builtin: c=$c' | ||
16 | |||
17 | b=b | ||
18 | c=c | ||
19 | f() { echo Assignments and a function: c=$c; } | ||
20 | b=$a c=$b f | ||
21 | |||
22 | echo Done | ||
diff --git a/testsuite/ash.tests b/testsuite/ash.tests index dd626e6d1..2eeb746e4 100755 --- a/testsuite/ash.tests +++ b/testsuite/ash.tests | |||
@@ -6,7 +6,6 @@ | |||
6 | # Licensed under GPL v2, see file LICENSE for details. | 6 | # Licensed under GPL v2, see file LICENSE for details. |
7 | 7 | ||
8 | . ./testing.sh | 8 | . ./testing.sh |
9 | |||
10 | test -f "$bindir/.config" && . "$bindir/.config" | 9 | test -f "$bindir/.config" && . "$bindir/.config" |
11 | 10 | ||
12 | test x"CONFIG_SCRIPT" = x"y" || exit 0 | 11 | test x"CONFIG_SCRIPT" = x"y" || exit 0 |
diff --git a/testsuite/cal.tests b/testsuite/cal.tests index 30985688b..db693ee59 100755 --- a/testsuite/cal.tests +++ b/testsuite/cal.tests | |||
@@ -3,7 +3,6 @@ | |||
3 | # Licensed under GPL v2, see file LICENSE for details. | 3 | # Licensed under GPL v2, see file LICENSE for details. |
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | |||
7 | test -f "$bindir/.config" && . "$bindir/.config" | 6 | test -f "$bindir/.config" && . "$bindir/.config" |
8 | 7 | ||
9 | # testing "test name" "command" "expected result" "file input" "stdin" | 8 | # testing "test name" "command" "expected result" "file input" "stdin" |
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests index 5b397b01c..7aee774a1 100755 --- a/testsuite/cpio.tests +++ b/testsuite/cpio.tests | |||
@@ -99,7 +99,7 @@ SKIP= | |||
99 | 99 | ||
100 | # chown on a link was affecting file, dropping its suid/sgid bits | 100 | # chown on a link was affecting file, dropping its suid/sgid bits |
101 | rm -rf cpio.testdir | 101 | rm -rf cpio.testdir |
102 | optional FEATURE_CPIO_O | 102 | optional FEATURE_CPIO_O FEATURE_STAT_FORMAT |
103 | mkdir cpio.testdir | 103 | mkdir cpio.testdir |
104 | touch cpio.testdir/file | 104 | touch cpio.testdir/file |
105 | chmod 6755 cpio.testdir/file # sets suid/sgid bits | 105 | chmod 6755 cpio.testdir/file # sets suid/sgid bits |
diff --git a/testsuite/date/date-works-1 b/testsuite/date/date-works-1 index 1b3e47ab0..e745d3841 100644 --- a/testsuite/date/date-works-1 +++ b/testsuite/date/date-works-1 | |||
@@ -1,3 +1,5 @@ | |||
1 | unset LANG | ||
2 | |||
1 | dt=`busybox date -d 1:2 +%T` | 3 | dt=`busybox date -d 1:2 +%T` |
2 | test x"$dt" = x"01:02:00" | 4 | test x"$dt" = x"01:02:00" |
3 | 5 | ||
diff --git a/testsuite/diff.tests b/testsuite/diff.tests index 06d5a4fd7..27a4b33a7 100755 --- a/testsuite/diff.tests +++ b/testsuite/diff.tests | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | 6 | ||
7 | # testing "test name" "options" "expected result" "file input" "stdin" | 7 | # testing "test name" "commands" "expected result" "file input" "stdin" |
8 | 8 | ||
9 | # diff outputs date/time in the header, which should not be analysed | 9 | # diff outputs date/time in the header, which should not be analysed |
10 | # NB: sed has tab character in s command! | 10 | # NB: sed has tab character in s command! |
@@ -100,9 +100,11 @@ testing "diff always takes context from old file" \ | |||
100 | "abc\na c\ndef\n" \ | 100 | "abc\na c\ndef\n" \ |
101 | "a c\n" | 101 | "a c\n" |
102 | 102 | ||
103 | # testing "test name" "options" "expected result" "file input" "stdin" | 103 | # testing "test name" "commands" "expected result" "file input" "stdin" |
104 | 104 | ||
105 | # clean up | ||
105 | rm -rf diff1 diff2 | 106 | rm -rf diff1 diff2 |
107 | |||
106 | mkdir diff1 diff2 diff2/subdir | 108 | mkdir diff1 diff2 diff2/subdir |
107 | echo qwe >diff1/- | 109 | echo qwe >diff1/- |
108 | echo asd >diff2/subdir/- | 110 | echo asd >diff2/subdir/- |
@@ -187,4 +189,29 @@ SKIP= | |||
187 | # clean up | 189 | # clean up |
188 | rm -rf diff1 diff2 | 190 | rm -rf diff1 diff2 |
189 | 191 | ||
192 | # NOT using directory structure from prev test... | ||
193 | mkdir diff1 diff2 | ||
194 | echo qwe >diff1/- | ||
195 | echo rty >diff2/- | ||
196 | optional FEATURE_DIFF_DIR | ||
197 | testing "diff diff1 diff2/" \ | ||
198 | "diff -ur diff1 diff2/ | $TRIM_TAB; diff -ur .///diff1 diff2//// | $TRIM_TAB" \ | ||
199 | "\ | ||
200 | --- diff1/- | ||
201 | +++ diff2/- | ||
202 | @@ -1 +1 @@ | ||
203 | -qwe | ||
204 | +rty | ||
205 | --- .///diff1/- | ||
206 | +++ diff2////- | ||
207 | @@ -1 +1 @@ | ||
208 | -qwe | ||
209 | +rty | ||
210 | " \ | ||
211 | "" "" | ||
212 | SKIP= | ||
213 | |||
214 | # clean up | ||
215 | rm -rf diff1 diff2 | ||
216 | |||
190 | exit $FAILCOUNT | 217 | exit $FAILCOUNT |
diff --git a/testsuite/expand.tests b/testsuite/expand.tests index 357a9ad6b..631ab4db3 100755 --- a/testsuite/expand.tests +++ b/testsuite/expand.tests | |||
@@ -3,6 +3,7 @@ | |||
3 | # Licensed under GPL v2, see file LICENSE for details. | 3 | # Licensed under GPL v2, see file LICENSE for details. |
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | test -f "$bindir/.config" && . "$bindir/.config" | ||
6 | 7 | ||
7 | # testing "test name" "options" "expected result" "file input" "stdin" | 8 | # testing "test name" "options" "expected result" "file input" "stdin" |
8 | 9 | ||
@@ -12,13 +13,12 @@ testing "expand" \ | |||
12 | "" \ | 13 | "" \ |
13 | "\t12345678\t12345678\n" | 14 | "\t12345678\t12345678\n" |
14 | 15 | ||
15 | optional UNICODE_SUPPORT | 16 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ |
16 | testing "expand with unicode characher 0x394" \ | 17 | && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ |
18 | && testing "expand with unicode characher 0x394" \ | ||
17 | "expand" \ | 19 | "expand" \ |
18 | "Δ 12345ΔΔΔ 12345678\n" \ | 20 | "Δ 12345ΔΔΔ 12345678\n" \ |
19 | "" \ | 21 | "" \ |
20 | "Δ\t12345ΔΔΔ\t12345678\n" | 22 | "Δ\t12345ΔΔΔ\t12345678\n" |
21 | SKIP= | ||
22 | |||
23 | 23 | ||
24 | exit $FAILCOUNT | 24 | exit $FAILCOUNT |
diff --git a/testsuite/fold.tests b/testsuite/fold.tests index 0197d024d..e5700cc2b 100755 --- a/testsuite/fold.tests +++ b/testsuite/fold.tests | |||
@@ -3,6 +3,7 @@ | |||
3 | # Licensed under GPL v2, see file LICENSE for details. | 3 | # Licensed under GPL v2, see file LICENSE for details. |
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | test -f "$bindir/.config" && . "$bindir/.config" | ||
6 | 7 | ||
7 | # testing "test name" "options" "expected result" "file input" "stdin" | 8 | # testing "test name" "options" "expected result" "file input" "stdin" |
8 | 9 | ||
@@ -28,9 +29,10 @@ be preserved | |||
28 | is here:>\0< - they must be preserved | 29 | is here:>\0< - they must be preserved |
29 | " \ | 30 | " \ |
30 | 31 | ||
31 | optional UNICODE_SUPPORT | ||
32 | # The text was taken from English and Ukrainian wikipedia pages | 32 | # The text was taken from English and Ukrainian wikipedia pages |
33 | testing "fold -sw66 with unicode input" "fold -sw66" \ | 33 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ |
34 | && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ | ||
35 | && testing "fold -sw66 with unicode input" "fold -sw66" \ | ||
34 | "\ | 36 | "\ |
35 | The Andromeda Galaxy (pronounced /ænˈdrɒmədə/, also known as \n\ | 37 | The Andromeda Galaxy (pronounced /ænˈdrɒmədə/, also known as \n\ |
36 | Messier 31, M31, or NGC224; often referred to as the Great \n\ | 38 | Messier 31, M31, or NGC224; often referred to as the Great \n\ |
@@ -56,6 +58,5 @@ Way. | |||
56 | спіральна галактика, що знаходиться на відстані приблизно у 2,5 \ | 58 | спіральна галактика, що знаходиться на відстані приблизно у 2,5 \ |
57 | мільйони світлових років від нашої планети у сузір'ї Андромеди. \ | 59 | мільйони світлових років від нашої планети у сузір'ї Андромеди. \ |
58 | На початку ХХІ ст. в центрі галактики виявлено чорну дірку." | 60 | На початку ХХІ ст. в центрі галактики виявлено чорну дірку." |
59 | SKIP= | ||
60 | 61 | ||
61 | exit $FAILCOUNT | 62 | exit $FAILCOUNT |
diff --git a/testsuite/ls.tests b/testsuite/ls.tests index 0680762fc..dc842123d 100755 --- a/testsuite/ls.tests +++ b/testsuite/ls.tests | |||
@@ -3,10 +3,9 @@ | |||
3 | # Licensed under GPL v2, see file LICENSE for details. | 3 | # Licensed under GPL v2, see file LICENSE for details. |
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | |||
7 | test -f "$bindir/.config" && . "$bindir/.config" | 6 | test -f "$bindir/.config" && . "$bindir/.config" |
8 | 7 | ||
9 | rm -rf ls.testdir >/dev/null | 8 | rm -rf ls.testdir 2>/dev/null |
10 | mkdir ls.testdir || exit 1 | 9 | mkdir ls.testdir || exit 1 |
11 | 10 | ||
12 | # testing "test name" "command" "expected result" "file input" "stdin" | 11 | # testing "test name" "command" "expected result" "file input" "stdin" |
@@ -15,9 +14,10 @@ mkdir ls.testdir || exit 1 | |||
15 | # I suspect we might fail to skip exactly correct number of bytes | 14 | # I suspect we might fail to skip exactly correct number of bytes |
16 | # over broked unicode sequences. | 15 | # over broked unicode sequences. |
17 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ | 16 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ |
18 | && test x"$CONFIG_LOCALE_SUPPORT" != x"y" \ | 17 | && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ |
19 | && test x"$CONFIG_SUBST_WCHAR" = x"63" \ | 18 | && test x"$CONFIG_SUBST_WCHAR" = x"63" \ |
20 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"767" \ | 19 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"767" \ |
20 | && test x"$CONFIG_FEATURE_LS_SORTFILES" = x"y" \ | ||
21 | && testing "ls unicode test with codepoints limited to 767" \ | 21 | && testing "ls unicode test with codepoints limited to 767" \ |
22 | "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1 ls.testdir" \ | 22 | "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1 ls.testdir" \ |
23 | '0001_1__Some_correct_UTF-8_text___________________________________________| | 23 | '0001_1__Some_correct_UTF-8_text___________________________________________| |
@@ -134,7 +134,7 @@ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ | |||
134 | 134 | ||
135 | # Currently fails on "0080_4.2.2__U-000007FF_=_e0_9f_bf" line | 135 | # Currently fails on "0080_4.2.2__U-000007FF_=_e0_9f_bf" line |
136 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ | 136 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ |
137 | && test x"$CONFIG_LOCALE_SUPPORT" != x"y" \ | 137 | && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ |
138 | && test x"$CONFIG_SUBST_WCHAR" = x"63" \ | 138 | && test x"$CONFIG_SUBST_WCHAR" = x"63" \ |
139 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"0" \ | 139 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"0" \ |
140 | && testing "ls unicode test with unlimited codepoints" \ | 140 | && testing "ls unicode test with unlimited codepoints" \ |
diff --git a/testsuite/mount.tests b/testsuite/mount.tests index 3c7405fbd..ce1a6006b 100755 --- a/testsuite/mount.tests +++ b/testsuite/mount.tests | |||
@@ -3,7 +3,6 @@ | |||
3 | # Licensed under GPL v2, see file LICENSE for details. | 3 | # Licensed under GPL v2, see file LICENSE for details. |
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | |||
7 | test -f "$bindir/.config" && . "$bindir/.config" | 6 | test -f "$bindir/.config" && . "$bindir/.config" |
8 | 7 | ||
9 | test "`id -u`" = 0 || { | 8 | test "`id -u`" = 0 || { |
diff --git a/testsuite/unexpand.tests b/testsuite/unexpand.tests index a48e3214e..8dbe3eb27 100755 --- a/testsuite/unexpand.tests +++ b/testsuite/unexpand.tests | |||
@@ -3,6 +3,7 @@ | |||
3 | # Licensed under GPL v2, see file LICENSE for details. | 3 | # Licensed under GPL v2, see file LICENSE for details. |
4 | 4 | ||
5 | . ./testing.sh | 5 | . ./testing.sh |
6 | test -f "$bindir/.config" && . "$bindir/.config" | ||
6 | 7 | ||
7 | # testing "test name" "options" "expected result" "file input" "stdin" | 8 | # testing "test name" "options" "expected result" "file input" "stdin" |
8 | 9 | ||
@@ -30,9 +31,9 @@ testing "unexpand case 7" "unexpand" \ | |||
30 | testing "unexpand case 8" "unexpand" \ | 31 | testing "unexpand case 8" "unexpand" \ |
31 | "a b\n" "" "a b\n" \ | 32 | "a b\n" "" "a b\n" \ |
32 | 33 | ||
33 | optional UNICODE_SUPPORT | 34 | test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ |
34 | testing "unexpand with unicode characher 0x394" "unexpand" \ | 35 | && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ |
36 | && testing "unexpand with unicode characher 0x394" "unexpand" \ | ||
35 | "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n" | 37 | "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n" |
36 | SKIP= | ||
37 | 38 | ||
38 | exit $FAILCOUNT | 39 | exit $FAILCOUNT |
diff --git a/util-linux/Config.src b/util-linux/Config.src index 3c3e05ec4..91d1fc2ce 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src | |||
@@ -470,221 +470,6 @@ config FEATURE_USE_TERMIOS | |||
470 | will be unable to determine the current screen size, and will be | 470 | will be unable to determine the current screen size, and will be |
471 | unable to move the cursor. | 471 | unable to move the cursor. |
472 | 472 | ||
473 | config VOLUMEID | ||
474 | bool #No description makes it a hidden option | ||
475 | default n | ||
476 | |||
477 | config FEATURE_VOLUMEID_EXT | ||
478 | bool "Ext filesystem" | ||
479 | default y | ||
480 | depends on VOLUMEID | ||
481 | help | ||
482 | TODO | ||
483 | |||
484 | config FEATURE_VOLUMEID_BTRFS | ||
485 | bool "btrfs filesystem" | ||
486 | default y | ||
487 | depends on VOLUMEID | ||
488 | help | ||
489 | TODO | ||
490 | |||
491 | config FEATURE_VOLUMEID_REISERFS | ||
492 | bool "Reiser filesystem" | ||
493 | default y | ||
494 | depends on VOLUMEID | ||
495 | help | ||
496 | TODO | ||
497 | |||
498 | config FEATURE_VOLUMEID_FAT | ||
499 | bool "fat filesystem" | ||
500 | default y | ||
501 | depends on VOLUMEID | ||
502 | help | ||
503 | TODO | ||
504 | |||
505 | config FEATURE_VOLUMEID_HFS | ||
506 | bool "hfs filesystem" | ||
507 | default y | ||
508 | depends on VOLUMEID | ||
509 | help | ||
510 | TODO | ||
511 | |||
512 | config FEATURE_VOLUMEID_JFS | ||
513 | bool "jfs filesystem" | ||
514 | default y | ||
515 | depends on VOLUMEID | ||
516 | help | ||
517 | TODO | ||
518 | |||
519 | ### config FEATURE_VOLUMEID_UFS | ||
520 | ### bool "ufs filesystem" | ||
521 | ### default y | ||
522 | ### depends on VOLUMEID | ||
523 | ### help | ||
524 | ### TODO | ||
525 | |||
526 | config FEATURE_VOLUMEID_XFS | ||
527 | bool "xfs filesystem" | ||
528 | default y | ||
529 | depends on VOLUMEID | ||
530 | help | ||
531 | TODO | ||
532 | |||
533 | config FEATURE_VOLUMEID_NTFS | ||
534 | bool "ntfs filesystem" | ||
535 | default y | ||
536 | depends on VOLUMEID | ||
537 | help | ||
538 | TODO | ||
539 | |||
540 | config FEATURE_VOLUMEID_ISO9660 | ||
541 | bool "iso9660 filesystem" | ||
542 | default y | ||
543 | depends on VOLUMEID | ||
544 | help | ||
545 | TODO | ||
546 | |||
547 | config FEATURE_VOLUMEID_UDF | ||
548 | bool "udf filesystem" | ||
549 | default y | ||
550 | depends on VOLUMEID | ||
551 | help | ||
552 | TODO | ||
553 | |||
554 | config FEATURE_VOLUMEID_LUKS | ||
555 | bool "luks filesystem" | ||
556 | default y | ||
557 | depends on VOLUMEID | ||
558 | help | ||
559 | TODO | ||
560 | |||
561 | config FEATURE_VOLUMEID_LINUXSWAP | ||
562 | bool "linux swap filesystem" | ||
563 | default y | ||
564 | depends on VOLUMEID | ||
565 | help | ||
566 | TODO | ||
567 | |||
568 | ### config FEATURE_VOLUMEID_LVM | ||
569 | ### bool "lvm" | ||
570 | ### default y | ||
571 | ### depends on VOLUMEID | ||
572 | ### help | ||
573 | ### TODO | ||
574 | |||
575 | config FEATURE_VOLUMEID_CRAMFS | ||
576 | bool "cramfs filesystem" | ||
577 | default y | ||
578 | depends on VOLUMEID | ||
579 | help | ||
580 | TODO | ||
581 | |||
582 | ### config FEATURE_VOLUMEID_HPFS | ||
583 | ### bool "hpfs filesystem" | ||
584 | ### default y | ||
585 | ### depends on VOLUMEID | ||
586 | ### help | ||
587 | ### TODO | ||
588 | |||
589 | config FEATURE_VOLUMEID_ROMFS | ||
590 | bool "romfs filesystem" | ||
591 | default y | ||
592 | depends on VOLUMEID | ||
593 | help | ||
594 | TODO | ||
595 | |||
596 | config FEATURE_VOLUMEID_SYSV | ||
597 | bool "sysv filesystem" | ||
598 | default y | ||
599 | depends on VOLUMEID | ||
600 | help | ||
601 | TODO | ||
602 | |||
603 | ### config FEATURE_VOLUMEID_MINIX | ||
604 | ### bool "minix filesystem" | ||
605 | ### default y | ||
606 | ### depends on VOLUMEID | ||
607 | ### help | ||
608 | ### TODO | ||
609 | |||
610 | ### These only detect partition tables - not used (yet?) | ||
611 | ### config FEATURE_VOLUMEID_MAC | ||
612 | ### bool "mac filesystem" | ||
613 | ### default y | ||
614 | ### depends on VOLUMEID | ||
615 | ### help | ||
616 | ### TODO | ||
617 | ### | ||
618 | ### config FEATURE_VOLUMEID_MSDOS | ||
619 | ### bool "msdos filesystem" | ||
620 | ### default y | ||
621 | ### depends on VOLUMEID | ||
622 | ### help | ||
623 | ### TODO | ||
624 | |||
625 | config FEATURE_VOLUMEID_OCFS2 | ||
626 | bool "ocfs2 filesystem" | ||
627 | default y | ||
628 | depends on VOLUMEID | ||
629 | help | ||
630 | TODO | ||
631 | |||
632 | ### config FEATURE_VOLUMEID_HIGHPOINTRAID | ||
633 | ### bool "highpoint raid" | ||
634 | ### default y | ||
635 | ### depends on VOLUMEID | ||
636 | ### help | ||
637 | ### TODO | ||
638 | |||
639 | ### config FEATURE_VOLUMEID_ISWRAID | ||
640 | ### bool "intel raid" | ||
641 | ### default y | ||
642 | ### depends on VOLUMEID | ||
643 | ### help | ||
644 | ### TODO | ||
645 | |||
646 | ### config FEATURE_VOLUMEID_LSIRAID | ||
647 | ### bool "lsi raid" | ||
648 | ### default y | ||
649 | ### depends on VOLUMEID | ||
650 | ### help | ||
651 | ### TODO | ||
652 | |||
653 | ### config FEATURE_VOLUMEID_VIARAID | ||
654 | ### bool "via raid" | ||
655 | ### default y | ||
656 | ### depends on VOLUMEID | ||
657 | ### help | ||
658 | ### TODO | ||
659 | |||
660 | ### config FEATURE_VOLUMEID_SILICONRAID | ||
661 | ### bool "silicon raid" | ||
662 | ### default y | ||
663 | ### depends on VOLUMEID | ||
664 | ### help | ||
665 | ### TODO | ||
666 | |||
667 | ### config FEATURE_VOLUMEID_NVIDIARAID | ||
668 | ### bool "nvidia raid" | ||
669 | ### default y | ||
670 | ### depends on VOLUMEID | ||
671 | ### help | ||
672 | ### TODO | ||
673 | |||
674 | ### config FEATURE_VOLUMEID_PROMISERAID | ||
675 | ### bool "promise raid" | ||
676 | ### default y | ||
677 | ### depends on VOLUMEID | ||
678 | ### help | ||
679 | ### TODO | ||
680 | |||
681 | config FEATURE_VOLUMEID_LINUXRAID | ||
682 | bool "linuxraid" | ||
683 | default y | ||
684 | depends on VOLUMEID | ||
685 | help | ||
686 | TODO | ||
687 | |||
688 | config MOUNT | 473 | config MOUNT |
689 | bool "mount" | 474 | bool "mount" |
690 | default y | 475 | default y |
@@ -937,4 +722,224 @@ config FEATURE_MTAB_SUPPORT | |||
937 | About the only reason to use this is if you've removed /proc from | 722 | About the only reason to use this is if you've removed /proc from |
938 | your kernel. | 723 | your kernel. |
939 | 724 | ||
725 | config VOLUMEID | ||
726 | bool #No description makes it a hidden option | ||
727 | default n | ||
728 | |||
729 | menu "Filesystem/Volume identification" | ||
730 | depends on VOLUMEID | ||
731 | |||
732 | config FEATURE_VOLUMEID_EXT | ||
733 | bool "Ext filesystem" | ||
734 | default y | ||
735 | depends on VOLUMEID | ||
736 | help | ||
737 | TODO | ||
738 | |||
739 | config FEATURE_VOLUMEID_BTRFS | ||
740 | bool "btrfs filesystem" | ||
741 | default y | ||
742 | depends on VOLUMEID | ||
743 | help | ||
744 | TODO | ||
745 | |||
746 | config FEATURE_VOLUMEID_REISERFS | ||
747 | bool "Reiser filesystem" | ||
748 | default y | ||
749 | depends on VOLUMEID | ||
750 | help | ||
751 | TODO | ||
752 | |||
753 | config FEATURE_VOLUMEID_FAT | ||
754 | bool "fat filesystem" | ||
755 | default y | ||
756 | depends on VOLUMEID | ||
757 | help | ||
758 | TODO | ||
759 | |||
760 | config FEATURE_VOLUMEID_HFS | ||
761 | bool "hfs filesystem" | ||
762 | default y | ||
763 | depends on VOLUMEID | ||
764 | help | ||
765 | TODO | ||
766 | |||
767 | config FEATURE_VOLUMEID_JFS | ||
768 | bool "jfs filesystem" | ||
769 | default y | ||
770 | depends on VOLUMEID | ||
771 | help | ||
772 | TODO | ||
773 | |||
774 | ### config FEATURE_VOLUMEID_UFS | ||
775 | ### bool "ufs filesystem" | ||
776 | ### default y | ||
777 | ### depends on VOLUMEID | ||
778 | ### help | ||
779 | ### TODO | ||
780 | |||
781 | config FEATURE_VOLUMEID_XFS | ||
782 | bool "xfs filesystem" | ||
783 | default y | ||
784 | depends on VOLUMEID | ||
785 | help | ||
786 | TODO | ||
787 | |||
788 | config FEATURE_VOLUMEID_NTFS | ||
789 | bool "ntfs filesystem" | ||
790 | default y | ||
791 | depends on VOLUMEID | ||
792 | help | ||
793 | TODO | ||
794 | |||
795 | config FEATURE_VOLUMEID_ISO9660 | ||
796 | bool "iso9660 filesystem" | ||
797 | default y | ||
798 | depends on VOLUMEID | ||
799 | help | ||
800 | TODO | ||
801 | |||
802 | config FEATURE_VOLUMEID_UDF | ||
803 | bool "udf filesystem" | ||
804 | default y | ||
805 | depends on VOLUMEID | ||
806 | help | ||
807 | TODO | ||
808 | |||
809 | config FEATURE_VOLUMEID_LUKS | ||
810 | bool "luks filesystem" | ||
811 | default y | ||
812 | depends on VOLUMEID | ||
813 | help | ||
814 | TODO | ||
815 | |||
816 | config FEATURE_VOLUMEID_LINUXSWAP | ||
817 | bool "linux swap filesystem" | ||
818 | default y | ||
819 | depends on VOLUMEID | ||
820 | help | ||
821 | TODO | ||
822 | |||
823 | ### config FEATURE_VOLUMEID_LVM | ||
824 | ### bool "lvm" | ||
825 | ### default y | ||
826 | ### depends on VOLUMEID | ||
827 | ### help | ||
828 | ### TODO | ||
829 | |||
830 | config FEATURE_VOLUMEID_CRAMFS | ||
831 | bool "cramfs filesystem" | ||
832 | default y | ||
833 | depends on VOLUMEID | ||
834 | help | ||
835 | TODO | ||
836 | |||
837 | ### config FEATURE_VOLUMEID_HPFS | ||
838 | ### bool "hpfs filesystem" | ||
839 | ### default y | ||
840 | ### depends on VOLUMEID | ||
841 | ### help | ||
842 | ### TODO | ||
843 | |||
844 | config FEATURE_VOLUMEID_ROMFS | ||
845 | bool "romfs filesystem" | ||
846 | default y | ||
847 | depends on VOLUMEID | ||
848 | help | ||
849 | TODO | ||
850 | |||
851 | config FEATURE_VOLUMEID_SYSV | ||
852 | bool "sysv filesystem" | ||
853 | default y | ||
854 | depends on VOLUMEID | ||
855 | help | ||
856 | TODO | ||
857 | |||
858 | ### config FEATURE_VOLUMEID_MINIX | ||
859 | ### bool "minix filesystem" | ||
860 | ### default y | ||
861 | ### depends on VOLUMEID | ||
862 | ### help | ||
863 | ### TODO | ||
864 | |||
865 | ### These only detect partition tables - not used (yet?) | ||
866 | ### config FEATURE_VOLUMEID_MAC | ||
867 | ### bool "mac filesystem" | ||
868 | ### default y | ||
869 | ### depends on VOLUMEID | ||
870 | ### help | ||
871 | ### TODO | ||
872 | ### | ||
873 | ### config FEATURE_VOLUMEID_MSDOS | ||
874 | ### bool "msdos filesystem" | ||
875 | ### default y | ||
876 | ### depends on VOLUMEID | ||
877 | ### help | ||
878 | ### TODO | ||
879 | |||
880 | config FEATURE_VOLUMEID_OCFS2 | ||
881 | bool "ocfs2 filesystem" | ||
882 | default y | ||
883 | depends on VOLUMEID | ||
884 | help | ||
885 | TODO | ||
886 | |||
887 | ### config FEATURE_VOLUMEID_HIGHPOINTRAID | ||
888 | ### bool "highpoint raid" | ||
889 | ### default y | ||
890 | ### depends on VOLUMEID | ||
891 | ### help | ||
892 | ### TODO | ||
893 | |||
894 | ### config FEATURE_VOLUMEID_ISWRAID | ||
895 | ### bool "intel raid" | ||
896 | ### default y | ||
897 | ### depends on VOLUMEID | ||
898 | ### help | ||
899 | ### TODO | ||
900 | |||
901 | ### config FEATURE_VOLUMEID_LSIRAID | ||
902 | ### bool "lsi raid" | ||
903 | ### default y | ||
904 | ### depends on VOLUMEID | ||
905 | ### help | ||
906 | ### TODO | ||
907 | |||
908 | ### config FEATURE_VOLUMEID_VIARAID | ||
909 | ### bool "via raid" | ||
910 | ### default y | ||
911 | ### depends on VOLUMEID | ||
912 | ### help | ||
913 | ### TODO | ||
914 | |||
915 | ### config FEATURE_VOLUMEID_SILICONRAID | ||
916 | ### bool "silicon raid" | ||
917 | ### default y | ||
918 | ### depends on VOLUMEID | ||
919 | ### help | ||
920 | ### TODO | ||
921 | |||
922 | ### config FEATURE_VOLUMEID_NVIDIARAID | ||
923 | ### bool "nvidia raid" | ||
924 | ### default y | ||
925 | ### depends on VOLUMEID | ||
926 | ### help | ||
927 | ### TODO | ||
928 | |||
929 | ### config FEATURE_VOLUMEID_PROMISERAID | ||
930 | ### bool "promise raid" | ||
931 | ### default y | ||
932 | ### depends on VOLUMEID | ||
933 | ### help | ||
934 | ### TODO | ||
935 | |||
936 | config FEATURE_VOLUMEID_LINUXRAID | ||
937 | bool "linuxraid" | ||
938 | default y | ||
939 | depends on VOLUMEID | ||
940 | help | ||
941 | TODO | ||
942 | |||
943 | endmenu | ||
944 | |||
940 | endmenu | 945 | endmenu |
diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 342930964..11a9f624a 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c | |||
@@ -9,9 +9,25 @@ | |||
9 | #include "libbb.h" | 9 | #include "libbb.h" |
10 | 10 | ||
11 | #include <linux/input.h> | 11 | #include <linux/input.h> |
12 | #ifndef EV_SW | ||
13 | # define EV_SW 0x05 | ||
14 | #endif | ||
15 | #ifndef EV_KEY | ||
16 | # define EV_KEY 0x01 | ||
17 | #endif | ||
18 | #ifndef SW_LID | ||
19 | # define SW_LID 0x00 | ||
20 | #endif | ||
12 | #ifndef SW_RFKILL_ALL | 21 | #ifndef SW_RFKILL_ALL |
13 | # define SW_RFKILL_ALL 3 | 22 | # define SW_RFKILL_ALL 0x03 |
14 | #endif | 23 | #endif |
24 | #ifndef KEY_POWER | ||
25 | # define KEY_POWER 116 /* SC System Power Down */ | ||
26 | #endif | ||
27 | #ifndef KEY_SLEEP | ||
28 | # define KEY_SLEEP 142 /* SC System Sleep */ | ||
29 | #endif | ||
30 | |||
15 | 31 | ||
16 | /* | 32 | /* |
17 | * acpid listens to ACPI events coming either in textual form | 33 | * acpid listens to ACPI events coming either in textual form |
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 7227a829e..aa718c787 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c | |||
@@ -2805,7 +2805,7 @@ list_devs_in_proc_partititons(void) | |||
2805 | &ma, &mi, &sz, ptname) != 4) | 2805 | &ma, &mi, &sz, ptname) != 4) |
2806 | continue; | 2806 | continue; |
2807 | for (s = ptname; *s; s++) | 2807 | for (s = ptname; *s; s++) |
2808 | continue; | 2808 | continue; |
2809 | /* note: excluding '0': e.g. mmcblk0 is not a partition name! */ | 2809 | /* note: excluding '0': e.g. mmcblk0 is not a partition name! */ |
2810 | if (s[-1] >= '1' && s[-1] <= '9') | 2810 | if (s[-1] >= '1' && s[-1] <= '9') |
2811 | continue; | 2811 | continue; |
diff --git a/util-linux/losetup.c b/util-linux/losetup.c index 0f5914c88..3873be399 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c | |||
@@ -65,9 +65,9 @@ int losetup_main(int argc UNUSED_PARAM, char **argv) | |||
65 | n = 0; | 65 | n = 0; |
66 | while (1) { | 66 | while (1) { |
67 | char *s; | 67 | char *s; |
68 | char dev[sizeof(LOOP_NAME) + sizeof(int)*3]; | 68 | char dev[LOOP_NAMESIZE]; |
69 | 69 | ||
70 | sprintf(dev, LOOP_NAME"%u", n); | 70 | sprintf(dev, LOOP_FORMAT, n); |
71 | s = query_loop(dev); | 71 | s = query_loop(dev); |
72 | n++; | 72 | n++; |
73 | if (!s) { | 73 | if (!s) { |
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 217075660..b4042c07e 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -374,10 +374,8 @@ static void make_device(char *path, int delete) | |||
374 | putenv(s1); | 374 | putenv(s1); |
375 | if (system(command) == -1) | 375 | if (system(command) == -1) |
376 | bb_perror_msg("can't run '%s'", command); | 376 | bb_perror_msg("can't run '%s'", command); |
377 | unsetenv("SUBSYSTEM"); | 377 | bb_unsetenv_and_free(s1); |
378 | free(s1); | 378 | bb_unsetenv_and_free(s); |
379 | unsetenv("MDEV"); | ||
380 | free(s); | ||
381 | free(command); | 379 | free(command); |
382 | } | 380 | } |
383 | 381 | ||
diff --git a/util-linux/more.c b/util-linux/more.c index 55694e434..9216b6137 100644 --- a/util-linux/more.c +++ b/util-linux/more.c | |||
@@ -31,7 +31,7 @@ struct globals { | |||
31 | 31 | ||
32 | #define setTermSettings(fd, argp) do { \ | 32 | #define setTermSettings(fd, argp) do { \ |
33 | if (ENABLE_FEATURE_USE_TERMIOS) tcsetattr(fd, TCSANOW, argp); \ | 33 | if (ENABLE_FEATURE_USE_TERMIOS) tcsetattr(fd, TCSANOW, argp); \ |
34 | } while(0) | 34 | } while (0) |
35 | #define getTermSettings(fd, argp) tcgetattr(fd, argp) | 35 | #define getTermSettings(fd, argp) tcgetattr(fd, argp) |
36 | 36 | ||
37 | static void gotsig(int sig UNUSED_PARAM) | 37 | static void gotsig(int sig UNUSED_PARAM) |
@@ -46,7 +46,7 @@ static void gotsig(int sig UNUSED_PARAM) | |||
46 | int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 46 | int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
47 | int more_main(int argc UNUSED_PARAM, char **argv) | 47 | int more_main(int argc UNUSED_PARAM, char **argv) |
48 | { | 48 | { |
49 | int c = c; /* for gcc */ | 49 | int c = c; /* for compiler */ |
50 | int lines; | 50 | int lines; |
51 | int input = 0; | 51 | int input = 0; |
52 | int spaces = 0; | 52 | int spaces = 0; |
diff --git a/util-linux/mount.c b/util-linux/mount.c index aed6f798b..9107e4308 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
@@ -1718,9 +1718,9 @@ static int singlemount(struct mntent *mp, int ignore_busy) | |||
1718 | 1718 | ||
1719 | // If we know the fstype (or don't need to), jump straight | 1719 | // If we know the fstype (or don't need to), jump straight |
1720 | // to the actual mount. | 1720 | // to the actual mount. |
1721 | if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) | 1721 | if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { |
1722 | rc = mount_it_now(mp, vfsflags, filteropts); | 1722 | rc = mount_it_now(mp, vfsflags, filteropts); |
1723 | else { | 1723 | } else { |
1724 | // Loop through filesystem types until mount succeeds | 1724 | // Loop through filesystem types until mount succeeds |
1725 | // or we run out | 1725 | // or we run out |
1726 | 1726 | ||
@@ -1756,7 +1756,7 @@ static int singlemount(struct mntent *mp, int ignore_busy) | |||
1756 | 1756 | ||
1757 | if (errno == EBUSY && ignore_busy) | 1757 | if (errno == EBUSY && ignore_busy) |
1758 | return 0; | 1758 | return 0; |
1759 | if (rc < 0) | 1759 | if (rc != 0) |
1760 | bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); | 1760 | bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); |
1761 | return rc; | 1761 | return rc; |
1762 | } | 1762 | } |
diff --git a/util-linux/rev.c b/util-linux/rev.c new file mode 100644 index 000000000..fa3a453ae --- /dev/null +++ b/util-linux/rev.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * rev implementation for busybox | ||
3 | * | ||
4 | * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com> | ||
5 | * | ||
6 | * Licensed under GPLv2, see file License in this tarball for details. | ||
7 | */ | ||
8 | |||
9 | //applet:IF_REV(APPLET(rev, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
10 | |||
11 | //kbuild:lib-$(CONFIG_REV) += rev.o | ||
12 | |||
13 | //config:config REV | ||
14 | //config: bool "rev" | ||
15 | //config: default y | ||
16 | //config: help | ||
17 | //config: Reverse lines of a file or files. | ||
18 | |||
19 | //usage:#define rev_trivial_usage | ||
20 | //usage: "[FILE]..." | ||
21 | //usage:#define rev_full_usage "\n\n" | ||
22 | //usage: "Reverse lines of FILE" | ||
23 | |||
24 | #include "libbb.h" | ||
25 | #include "unicode.h" | ||
26 | |||
27 | #undef CHAR_T | ||
28 | #if ENABLE_UNICODE_SUPPORT | ||
29 | # define CHAR_T wchar_t | ||
30 | #else | ||
31 | # define CHAR_T char | ||
32 | #endif | ||
33 | |||
34 | /* In-place invert */ | ||
35 | static void strrev(CHAR_T *s, int len) | ||
36 | { | ||
37 | int i; | ||
38 | |||
39 | if (len != 0) { | ||
40 | len--; | ||
41 | if (len != 0 && s[len] == '\n') | ||
42 | len--; | ||
43 | } | ||
44 | |||
45 | for (i = 0; i < len; i++, len--) { | ||
46 | CHAR_T c = s[i]; | ||
47 | s[i] = s[len]; | ||
48 | s[len] = c; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
53 | int rev_main(int argc UNUSED_PARAM, char **argv) | ||
54 | { | ||
55 | int retval; | ||
56 | size_t bufsize; | ||
57 | char *buf; | ||
58 | |||
59 | init_unicode(); | ||
60 | |||
61 | getopt32(argv, ""); | ||
62 | argv += optind; | ||
63 | if (!argv[0]) | ||
64 | argv = (char **)&bb_argv_dash; | ||
65 | |||
66 | retval = EXIT_SUCCESS; | ||
67 | bufsize = 256; | ||
68 | buf = xmalloc(bufsize); | ||
69 | do { | ||
70 | size_t pos; | ||
71 | FILE *fp; | ||
72 | |||
73 | fp = fopen_or_warn_stdin(*argv++); | ||
74 | if (!fp) { | ||
75 | retval = EXIT_FAILURE; | ||
76 | continue; | ||
77 | } | ||
78 | |||
79 | pos = 0; | ||
80 | while (1) { | ||
81 | /* Read one line */ | ||
82 | buf[bufsize - 1] = 1; /* not 0 */ | ||
83 | if (!fgets(buf + pos, bufsize - pos, fp)) | ||
84 | break; /* EOF/error */ | ||
85 | if (buf[bufsize - 1] == '\0' /* fgets filled entire buffer */ | ||
86 | && buf[bufsize - 2] != '\n' /* and did not read '\n' */ | ||
87 | && !feof(fp) | ||
88 | ) { | ||
89 | /* Line is too long, extend buffer */ | ||
90 | pos = bufsize - 1; | ||
91 | bufsize += 64 + bufsize / 8; | ||
92 | buf = xrealloc(buf, bufsize); | ||
93 | continue; | ||
94 | } | ||
95 | |||
96 | /* Process and print it */ | ||
97 | #if ENABLE_UNICODE_SUPPORT | ||
98 | { | ||
99 | wchar_t *tmp = xmalloc(bufsize * sizeof(wchar_t)); | ||
100 | /* Convert to wchar_t (might error out!) */ | ||
101 | int len = mbstowcs(tmp, buf, bufsize); | ||
102 | if (len >= 0) { | ||
103 | strrev(tmp, len); | ||
104 | /* Convert back to char */ | ||
105 | wcstombs(buf, tmp, bufsize); | ||
106 | } | ||
107 | free(tmp); | ||
108 | } | ||
109 | #else | ||
110 | strrev(buf, strlen(buf)); | ||
111 | #endif | ||
112 | fputs(buf, stdout); | ||
113 | } | ||
114 | fclose(fp); | ||
115 | } while (*argv); | ||
116 | |||
117 | if (ENABLE_FEATURE_CLEAN_UP) | ||
118 | free(buf); | ||
119 | |||
120 | fflush_stdout_and_exit(retval); | ||
121 | } | ||
diff --git a/util-linux/script.c b/util-linux/script.c index d9a62fbfe..c23117cf3 100644 --- a/util-linux/script.c +++ b/util-linux/script.c | |||
@@ -88,10 +88,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) | |||
88 | 88 | ||
89 | /* TODO: SIGWINCH? pass window size changes down to slave? */ | 89 | /* TODO: SIGWINCH? pass window size changes down to slave? */ |
90 | 90 | ||
91 | child_pid = vfork(); | 91 | child_pid = xvfork(); |
92 | if (child_pid < 0) { | ||
93 | bb_perror_msg_and_die("vfork"); | ||
94 | } | ||
95 | 92 | ||
96 | if (child_pid) { | 93 | if (child_pid) { |
97 | /* parent */ | 94 | /* parent */ |