aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:08:20 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:08:20 +1000
commit6a6efd31038d7afe977e3059508ae863e65cbdf5 (patch)
tree5cd69a751e893b83176751c80fcea7a7afeed1ae
parenta6a2325ecf402054132daae169f71edb0fb849e3 (diff)
parent29082231d0cb1a5b327de5d515b16f332d4dbdaf (diff)
downloadbusybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.tar.gz
busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.tar.bz2
busybox-w32-6a6efd31038d7afe977e3059508ae863e65cbdf5.zip
Merge branch 'origin/master' (early part)
-rw-r--r--.gitignore1
-rw-r--r--Config.in1
-rw-r--r--Makefile8
-rw-r--r--TODO118
-rw-r--r--applets/Kbuild.src2
-rw-r--r--applets/applet_tables.c24
-rw-r--r--applets/applets.c2
-rwxr-xr-xapplets/usage_compressed4
-rw-r--r--archival/Config.src9
-rw-r--r--archival/bbunzip.c11
-rw-r--r--archival/libunarchive/Kbuild.src2
-rw-r--r--archival/libunarchive/data_extract_all.c1
-rw-r--r--archival/libunarchive/data_extract_to_command.c134
-rw-r--r--archival/libunarchive/decompress_bunzip2.c6
-rw-r--r--archival/libunarchive/decompress_unxz.c52
-rw-r--r--archival/libunarchive/get_header_tar.c56
-rw-r--r--archival/libunarchive/open_transformer.c14
-rw-r--r--archival/libunarchive/unxz/xz.h139
-rw-r--r--archival/libunarchive/unxz/xz_config.h2
-rw-r--r--archival/libunarchive/unxz/xz_dec_lzma2.c200
-rw-r--r--archival/libunarchive/unxz/xz_dec_stream.c17
-rw-r--r--archival/libunarchive/unxz/xz_private.h41
-rw-r--r--archival/rpm2cpio.c10
-rw-r--r--archival/tar.c121
-rw-r--r--archival/unzip_doc.txt.bz2bin11359 -> 0 bytes
-rw-r--r--console-tools/openvt.c3
-rw-r--r--coreutils/chroot.c3
-rw-r--r--coreutils/env.c7
-rw-r--r--coreutils/nice.c6
-rw-r--r--coreutils/nohup.c4
-rw-r--r--coreutils/realpath.c2
-rw-r--r--debianutils/mktemp.c3
-rw-r--r--debianutils/start_stop_daemon.c6
-rw-r--r--e2fsprogs/old_e2fsprogs/fsck.c2
-rw-r--r--editors/diff.c27
-rw-r--r--editors/sed.c9
-rw-r--r--editors/vi.c1
-rw-r--r--findutils/xargs.c52
-rw-r--r--include/applets.src.h5
-rw-r--r--include/busybox.h13
-rw-r--r--include/libbb.h43
-rw-r--r--include/platform.h10
-rw-r--r--include/unarchive.h62
-rw-r--r--include/usage.src.h216
-rw-r--r--init/Config.src14
-rw-r--r--init/bootchartd.c182
-rw-r--r--libbb/Kbuild.src6
-rw-r--r--libbb/appletlib.c10
-rw-r--r--libbb/copyfd.c23
-rw-r--r--libbb/error_msg.c19
-rw-r--r--libbb/error_msg_and_die.c20
-rw-r--r--libbb/execable.c8
-rw-r--r--libbb/herror_msg.c11
-rw-r--r--libbb/herror_msg_and_die.c20
-rw-r--r--libbb/parse_config.c20
-rw-r--r--libbb/perror_msg.c17
-rw-r--r--libbb/perror_msg_and_die.c26
-rw-r--r--libbb/platform.c27
-rw-r--r--libbb/read_printf.c10
-rw-r--r--libbb/run_shell.c20
-rw-r--r--libbb/setup_environment.c4
-rw-r--r--libbb/verror_msg.c23
-rw-r--r--libbb/vfork_daemon_rexec.c52
-rw-r--r--libbb/xconnect.c1
-rw-r--r--libbb/xfuncs.c34
-rw-r--r--libbb/xfuncs_printf.c16
-rw-r--r--loginutils/login.c12
-rw-r--r--loginutils/su.c57
-rw-r--r--loginutils/sulogin.c8
-rw-r--r--mailutils/mail.c7
-rw-r--r--mailutils/mime.c3
-rw-r--r--miscutils/Config.src14
-rw-r--r--miscutils/chrt.c25
-rw-r--r--miscutils/conspy.c547
-rw-r--r--miscutils/crond.c893
-rw-r--r--miscutils/crontab.c8
-rw-r--r--miscutils/ionice.c5
-rw-r--r--miscutils/setsid.c4
-rw-r--r--miscutils/taskset.c5
-rw-r--r--miscutils/time.c15
-rw-r--r--miscutils/timeout.c7
-rw-r--r--modutils/Config.src4
-rw-r--r--modutils/modinfo.c35
-rw-r--r--modutils/modprobe.c10
-rw-r--r--networking/Config.src23
-rw-r--r--networking/ftpd.c5
-rw-r--r--networking/httpd.c2
-rw-r--r--networking/ifplugd.c95
-rw-r--r--networking/ifupdown.c11
-rw-r--r--networking/inetd.c4
-rw-r--r--networking/ipcalc.c6
-rw-r--r--networking/libiproute/ipaddress.c47
-rw-r--r--networking/nc.c95
-rw-r--r--networking/nc_bloaty.c46
-rw-r--r--networking/ntpd.c16
-rw-r--r--networking/tcpudp.c7
-rw-r--r--networking/udhcp/dhcpc.c3
-rw-r--r--networking/udhcp/dhcprelay.c3
-rw-r--r--networking/wget.c2
-rw-r--r--printutils/lpd.c3
-rw-r--r--procps/smemcap.c129
-rw-r--r--procps/sysctl.c1
-rw-r--r--procps/top.c8
-rw-r--r--runit/chpst.c3
-rw-r--r--runit/svlogd.c2
-rw-r--r--scripts/Makefile.build7
-rw-r--r--scripts/basic/docproc.c2
-rwxr-xr-xscripts/gen_build_files.sh55
-rwxr-xr-xscripts/randomtest14
-rwxr-xr-xscripts/test_make_O11
-rwxr-xr-xscripts/trylink38
-rw-r--r--selinux/runcon.c1
-rw-r--r--shell/Config.src106
-rw-r--r--shell/Kbuild.src2
-rw-r--r--shell/ash.c48
-rw-r--r--shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right10
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests21
-rw-r--r--shell/ash_test/ash-redir/redir9.right2
-rw-r--r--shell/ash_test/ash-redir/redir9.tests4
-rw-r--r--shell/cttyhack.c3
-rw-r--r--shell/hush.c384
-rw-r--r--shell/hush_test/hush-vars/var_serial.right5
-rwxr-xr-xshell/hush_test/hush-vars/var_serial.tests22
-rwxr-xr-xtestsuite/ash.tests1
-rwxr-xr-xtestsuite/cal.tests1
-rwxr-xr-xtestsuite/cpio.tests2
-rw-r--r--testsuite/date/date-works-12
-rwxr-xr-xtestsuite/diff.tests31
-rwxr-xr-xtestsuite/expand.tests8
-rwxr-xr-xtestsuite/fold.tests7
-rwxr-xr-xtestsuite/ls.tests8
-rwxr-xr-xtestsuite/mount.tests1
-rwxr-xr-xtestsuite/unexpand.tests7
-rw-r--r--util-linux/Config.src435
-rw-r--r--util-linux/acpid.c18
-rw-r--r--util-linux/fdisk.c2
-rw-r--r--util-linux/losetup.c4
-rw-r--r--util-linux/mdev.c6
-rw-r--r--util-linux/more.c4
-rw-r--r--util-linux/mount.c6
-rw-r--r--util-linux/rev.c121
-rw-r--r--util-linux/script.c5
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
9Kbuild 9Kbuild
10Config.in
10 11
11# 12#
12# Never ignore these 13# Never ignore these
diff --git a/Config.in b/Config.in
index 0f0601245..0a90f6a8a 100644
--- a/Config.in
+++ b/Config.in
@@ -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
156config FEATURE_CHECK_UNICODE_IN_ENV 157config FEATURE_CHECK_UNICODE_IN_ENV
157 bool "Check $LANG environment variable" 158 bool "Check $LANG environment variable"
diff --git a/Makefile b/Makefile
index a1b6250a4..0a2a3db01 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 17 2PATCHLEVEL = 18
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = 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
363PHONY += gen_build_files 363PHONY += gen_build_files
364gen_build_files: 364gen_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
514include/autoconf.h: .kconfig.d .config 514include/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
517include/usage.h: gen_build_files
518
517else 519else
518# Dummy target needed, because used as prerequisite 520# Dummy target needed, because used as prerequisite
519include/autoconf.h: ; 521include/autoconf.h: ;
diff --git a/TODO b/TODO
index af4c467c2..6f8cd8a32 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,8 @@
1Busybox TODO 1Busybox TODO
2 2
3Harvest patches from
4http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/
5
3Stuff that needs to be done. This is organized by who plans to get around to 6Stuff that needs to be done. This is organized by who plans to get around to
4doing it eventually, but that doesn't mean they "own" the item. If you want to 7doing it eventually, but that doesn't mean they "own" the item. If you want to
5do one of these bounce an email off the person it's listed under to see if they 8do 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.
9Rob Landley suggested this: 12Rob 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
97Bernhard Reutner-Fischer <busybox@busybox.net> suggests to look at these: 101Bernhard 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---
180Switch 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---
214FEATURE_CLEAN_UP 184FEATURE_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
271Code cleanup:
272
273Replace deprecated functions.
274
275--- 240---
276vdprintf() -> similar sized functionality 241vdprintf() -> 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
316Unicode work needed:
317
318Unicode support uses libc multibyte functions if LOCALE_SUPPORT is on
319(in this case, the code will also support many more encodings),
320or uses a limited subset of re-implemented multibyte functions
321which only understand "one byte == one char" and unicode.
322This is useful if you build against uclibc with locale support disabled.
323
324Unicode-dependent applets must call check_unicode_in_env() when they
325begin executing.
326
327Applet code may conditionalize on UNICODE_SUPPORT in order to use
328more efficient code if unicode support is not requested.
329
330Available functions (if you need more, implement them in libbb/unicode.c
331so that they work without LOCALE_SUPPORT too):
332
333int bb_mbstrlen(str) - multibyte-aware strlen
334size_t mbstowcs(wdest, src, n)
335size_t wcstombs(dest, wsrc, n)
336size_t wcrtomb(str, wc, wstate)
337int iswspace(wc)
338int iswalnum(wc)
339int iswpunct(wc)
340
341Applets which only need to align columns on screen correctly:
342
343ls - already done, use source as an example
344df
345dumpleases
346lsmod
347
348Applets which need to account for Unicode chars
349while processing the output:
350
351[un]expand
352fold
353man
354watch
355cut (-b and -c are currently the same, needs fixing)
356
357These applets need to ensure that unicode input
358is handled correctly (say, <unicode><backspace> sequence):
359
360getty, login
361rm -i
362unzip (overwrite prompt)
363
364Viewers/editors are more difficult (many cases to get right).
365libbb/lineedit.c is an example how to do it:
366
367less, most, ed, vi
368awk
369[ef]grep
370sed
371
372Probably needs some specialized work:
373
374loadkeys
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
40quiet_cmd_gen_applet_tables = GEN include/applet_tables.h 40quiet_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
43include/applet_tables.h: applets/applet_tables 43include/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
9test "$SED" || SED=sed 9test "$SED" || SED=sed
10test "$DD" || DD=dd 10test "$DD" || DD=dd
11 11
12exec >"$target" 12exec >"$target.$$"
13 13
14echo '#define UNPACKED_USAGE "" \' 14echo '#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/$/ \\/'
41echo '' 41echo ''
42
43mv -- "$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
283config 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
283config FEATURE_TAR_UNAME_GNAME 292config 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)
373static 373static
374IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) 374IF_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}
378int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 387int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
379int unxz_main(int argc UNUSED_PARAM, char **argv) 388int 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
38lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o 38lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
39lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o 39lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o
40lib-$(CONFIG_UNLZMA) += decompress_unlzma.o 40lib-$(CONFIG_UNLZMA) += decompress_unlzma.o
41lib-$(CONFIG_UNXZ) += decompress_unxz.o
41lib-$(CONFIG_CPIO) += get_header_cpio.o 42lib-$(CONFIG_CPIO) += get_header_cpio.o
42lib-$(CONFIG_DPKG) += $(DPKG_FILES) 43lib-$(CONFIG_DPKG) += $(DPKG_FILES)
43lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) 44lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
@@ -53,6 +54,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2
53lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o 54lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o
54lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o 55lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
55lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o 56lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o
57lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
56 58
57ifneq ($(lib-y),) 59ifneq ($(lib-y),)
58lib-y += $(COMMON_FILES) 60lib-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
9enum {
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
24static 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
38static void xputenv(char *str)
39{
40 if (putenv(str))
41 bb_error_msg_and_die(bb_msg_memory_exhausted);
42}
43
44static 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
50static 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
56static 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
62void 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)
692IF_DESKTOP(long long) int FAST_FUNC 692IF_DESKTOP(long long) int FAST_FUNC
693unpack_bz2_stream_prime(int src_fd, int dst_fd) 693unpack_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
53IF_DESKTOP(long long) int FAST_FUNC 48IF_DESKTOP(long long) int FAST_FUNC
54unpack_xz_stream(int src_fd, int dst_fd) 49unpack_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
121void BUG_tar_header_size(void);
122char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) 121char 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 */
57enum 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 */
148XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max); 199XZ_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 */
171XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); 220XZ_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
122struct lzma_dec { 132struct 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
214struct 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
204struct xz_dec_lzma2 { 253struct 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 */
270static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) 286static 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. */
425static __always_inline void XZ_FUNC rc_reset(struct rc_dec *rc) 441static 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
1091XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(uint32_t dict_max) 1107XZ_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
1149XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) 1169XZ_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
770XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max) 770XZ_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 */
73XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( 112XZ_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"
58typedef 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
196static void chksum_and_xwrite(int fd, struct TarHeader* hp) 165static 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 */
265void BUG_tar_header_size(void);
266static int writeTarHeader(struct TarBallInfo *tbInfo, 234static 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
741enum { 766enum {
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 {
121struct globals { 121struct 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))
76IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) 76IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk))
77IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) 77IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename))
78IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) 78IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash))
79IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash))
80IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) 79IF_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))
82IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 81IF_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
183IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) 182IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid))
184IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) 183IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP))
185IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 184IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
186IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP))
187IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) 185IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP))
188IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 186IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP))
189IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) 187IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP))
@@ -218,7 +216,6 @@ IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_DROP))
218IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) 216IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall))
219IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) 217IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5))
220IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) 218IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP))
221IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP))
222IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 219IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP))
223IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) 220IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length))
224IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 221IF_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))
273IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) 270IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP))
274IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) 271IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP)))
275IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) 272IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP))
276IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP))
277IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) 273IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP))
278IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) 274IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP))
279IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) 275IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP))
@@ -349,7 +345,6 @@ IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
349IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 345IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP))
350IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) 346IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid))
351IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) 347IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh))
352IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh))
353IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) 348IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum))
354IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) 349IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum))
355IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) 350IF_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[];
35extern const uint8_t applet_install_loc[]; 35extern 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;
419void xchroot(const char *path) FAST_FUNC; 419void xchroot(const char *path) FAST_FUNC;
420void xsetenv(const char *key, const char *value) FAST_FUNC; 420void xsetenv(const char *key, const char *value) FAST_FUNC;
421void bb_unsetenv(const char *key) FAST_FUNC; 421void bb_unsetenv(const char *key) FAST_FUNC;
422void bb_unsetenv_and_free(char *key) FAST_FUNC;
422void xunlink(const char *pathname) FAST_FUNC; 423void xunlink(const char *pathname) FAST_FUNC;
423void xstat(const char *pathname, struct stat *buf) FAST_FUNC; 424void xstat(const char *pathname, struct stat *buf) FAST_FUNC;
424int xopen(const char *pathname, int flags) FAST_FUNC; 425int 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
858int 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
870pid_t xfork(void) FAST_FUNC;
871#endif
857 872
858/* NOMMU friendy fork+exec: */ 873/* NOMMU friendy fork+exec: */
859pid_t spawn(char **argv) FAST_FUNC; 874pid_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;
1142parser_t* config_open(const char *filename) FAST_FUNC; 1157parser_t* config_open(const char *filename) FAST_FUNC;
1143parser_t* config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) FAST_FUNC; 1158parser_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 */
1144int config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) FAST_FUNC; 1160int 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;
1171extern void bb_do_delay(int seconds) FAST_FUNC; 1187extern void bb_do_delay(int seconds) FAST_FUNC;
1172extern void change_identity(const struct passwd *pw) FAST_FUNC; 1188extern void change_identity(const struct passwd *pw) FAST_FUNC;
1173extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC; 1189extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC;
1174extern 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
1176extern void renew_current_security_context(void) FAST_FUNC; 1191extern void renew_current_security_context(void) FAST_FUNC;
1177extern void set_current_security_context(security_context_t sid) FAST_FUNC; 1192extern 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"
1615extern const char bb_default_login_shell[]; 1630extern 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;
419extern char *strchrnul(const char *s, int c) FAST_FUNC; 421extern char *strchrnul(const char *s, int c) FAST_FUNC;
420#endif 422#endif
421 423
424#ifndef HAVE_STRSEP
425extern 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
7enum { 7enum {
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"
127typedef 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;
150struct 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 */
115typedef struct unpack_info_t { 158typedef struct unpack_info_t {
@@ -128,6 +171,7 @@ extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC;
128extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; 171extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC;
129extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; 172extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC;
130extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; 173extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC;
174extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC;
131 175
132extern void header_skip(const file_header_t *file_header) FAST_FUNC; 176extern void header_skip(const file_header_t *file_header) FAST_FUNC;
133extern void header_list(const file_header_t *file_header) FAST_FUNC; 177extern 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
161IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; 205IF_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 */
163IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; 207IF_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 */
165IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; 209IF_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
125config 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
139endmenu 125endmenu
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
129static char *make_tempdir(const char *prog) 172static 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
165static void do_logging(void) 200static 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
214static void finalize(char *tempdir) 249static 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
256int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 325int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
257int bootchartd_main(int argc UNUSED_PARAM, char **argv) 326int 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
7libbb/appletlib.o: include/usage_compressed.h
8
7lib-y:= 9lib-y:=
8 10
9INSERT 11INSERT
@@ -30,8 +32,6 @@ lib-y += create_icmp_socket.o
30lib-y += default_error_retval.o 32lib-y += default_error_retval.o
31lib-y += device_open.o 33lib-y += device_open.o
32lib-y += dump.o 34lib-y += dump.o
33lib-y += error_msg.o
34lib-y += error_msg_and_die.o
35lib-y += execable.o 35lib-y += execable.o
36lib-y += fclose_nonstdin.o 36lib-y += fclose_nonstdin.o
37lib-y += fflush_stdout_and_exit.o 37lib-y += fflush_stdout_and_exit.o
@@ -44,7 +44,6 @@ lib-y += get_line_from_file.o
44lib-y += getopt32.o 44lib-y += getopt32.o
45lib-y += get_volsize.o 45lib-y += get_volsize.o
46lib-y += herror_msg.o 46lib-y += herror_msg.o
47lib-y += herror_msg_and_die.o
48lib-y += human_readable.o 47lib-y += human_readable.o
49lib-y += info_msg.o 48lib-y += info_msg.o
50lib-y += inode_hash.o 49lib-y += inode_hash.o
@@ -63,7 +62,6 @@ lib-y += obscure.o
63lib-y += parse_mode.o 62lib-y += parse_mode.o
64lib-y += parse_config.o 63lib-y += parse_config.o
65lib-y += perror_msg.o 64lib-y += perror_msg.o
66lib-y += perror_msg_and_die.o
67lib-y += perror_nomsg.o 65lib-y += perror_nomsg.o
68lib-y += perror_nomsg_and_die.o 66lib-y += perror_nomsg_and_die.o
69lib-y += pidfile.o 67lib-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 @@
61static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; 61static 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
68static const char packed_usage[] = { PACKED_USAGE }; 68static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
69# include "unarchive.h" 69# include "unarchive.h"
70static const char *unpack_usage_messages(void) 70static 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 */
14static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) 16static 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)
108void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) 121void 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
12void 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
12void 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
113int 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
12void FAST_FUNC bb_herror_msg(const char *s, ...) 11void 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
20void 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
12void 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
12void FAST_FUNC bb_perror_msg(const char *s, ...) 11void 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
21void 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
22void FAST_FUNC bb_simple_perror_msg(const char *s) 32void 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
37void 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
12void 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
23void 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. */
126char* 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
57void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) 56void 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
85void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) 82void 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
141void 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
151void 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
73pid_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
83pid_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.
89int 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
108void FAST_FUNC save_nofork_data(struct nofork_save_area *save) 74void 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
258pid_t FAST_FUNC fork_or_rexec(char **argv) 224pid_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
275pid_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
272pid_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
282pid_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.
288int 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
340void 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
608pid_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. */
14static int restricted_shell(const char *shell) 14static 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
31int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 35int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
32int su_main(int argc UNUSED_PARAM, char **argv) 36int 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
277config FLASHCP 277config 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
284config FLASH_LOCK 284config 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
291config FLASH_UNLOCK 291config 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
298config FLASH_ERASEALL 298config 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
312config INOTIFYD 312config 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
550config RFKILL 550config 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
589config TASKSET 589config 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
14static const struct { 14static 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
23static void show_min_max(int pol) 27static 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
45struct 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
54struct 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
89enum {
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
100static 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
107static 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
116static 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
125static 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
141static 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
176static 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
257static 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
288static 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
301static 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
310static 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
340int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
341int 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
42typedef struct CronFile { 42typedef 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
51typedef struct CronLine { 51typedef 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
72enum { 71enum {
@@ -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
88struct globals { 87struct 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
111static void CheckUpdates(void);
112static void SynchronizeDir(void);
113static int TestJobs(time_t t1, time_t t2);
114static void RunJobs(void);
115static int CheckJobs(void);
116static void RunJob(const char *user, CronLine *line);
117#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
118static void EndJob(const char *user, CronLine *line);
119#else
120#define EndJob(user, line) ((line)->cl_Pid = 0)
121#endif
122static 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
166int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
167int 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 */
262static 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
275static 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
290static 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
302static const char DowAry[] ALIGN1 = 146static 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
453static 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.
316static 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
350static 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
540static void CheckUpdates(void) 440static 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
556static void SynchronizeDir(void) 457static 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. 498static void safe_setenv(char **pvar_val, const char *var, const char *val)
605 */
606static 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 */
649static 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
696static void RunJobs(void) 510static 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/* 525static 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 */
728static 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
763static void 540static pid_t
764ForkJob(const char *user, CronLine *line, int mailFd, 541fork_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
829static void RunJob(const char *user, CronLine *line) 595static 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 */
859static void EndJob(const char *user, CronLine *line) 634static 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
906static void RunJob(const char *user, CronLine *line) 679static 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 */
726static 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
771static 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 */
804static 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
840int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
841int 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 @@
20static void edit_file(const struct passwd *pas, const char *file) 20static 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. */
368static void run_command(char *const *cmd, resource_t *resp) 368static 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
228config DEFAULT_MODULES_DIR 228config 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
236config DEFAULT_DEPMOD_FILE 236config 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
46static void modinfo(const char *path, struct modinfo_env *env) 46static 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
626config NC
627 bool "nc"
628 default y
629 help
630 A simple Unix utility which reads and writes data across network
631 connections.
632
633config 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
640config 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
649config NETSTAT 626config 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};
82static const char api_modes[] ALIGN1 = "aempwi";
82 83
83enum { // interface status 84enum { // 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
246static smallint detect_link_mii(void) 247static 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
351static smallint detect_link_auto(void) 352static 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
387static 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
53enum { 91enum {
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
25struct fileblock {
26 struct fileblock *next;
27 char data[TAR_BLOCK_SIZE];
28};
29
30static 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
60static 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
94static 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
105int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
106int 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:
13include scripts/Kbuild.include 13include 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
16kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) 17kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
17include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile) 18include $(if $(wildcard $(src)/Kbuild), $(src)/Kbuild, \
19 $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, \
20 $(kbuild-dir)/Makefile \
21 ) \
22 )
18 23
19include scripts/Makefile.lib 24include 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
6cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } 6cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; }
7# In separate objtree build, include/ might not exist yet
8mkdir include 2>/dev/null
7 9
8srctree="$1" 10srctree="$1"
9 11
@@ -11,20 +13,19 @@ srctree="$1"
11src="$srctree/include/applets.src.h" 13src="$srctree/include/applets.src.h"
12dst="include/applets.h" 14dst="include/applets.h"
13s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` 15s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c`
14echo "/* DO NOT EDIT. This file is generated from applets.src.h */" >"$dst.$$.tmp" 16old=`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.
21new=`echo "/* DO NOT EDIT. This file is generated from applets.src.h */"
19while IFS='' read -r REPLY; do 22while 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"
22done <"$src" >>"$dst.$$.tmp" 25done <"$src"`
23if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then 26if test x"$new" != x"$old"; then
24 rm -- "$dst.$$.tmp"
25else
26 echo " GEN $dst" 27 echo " GEN $dst"
27 mv -- "$dst.$$.tmp" "$dst" 28 printf "%s\n" "$new" >"$dst"
28fi 29fi
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 ``)
37s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` 38s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c`
38echo "/* DO NOT EDIT. This file is generated from usage.src.h */" >"$dst.$$.tmp" 39old=`cat "$dst" 2>/dev/null`
39# Why "IFS='' read -r REPLY"?? 40new=`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.
43while IFS='' read -r REPLY; do 41while 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"
46done <"$src" >>"$dst.$$.tmp" 44done <"$src"`
47if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then 45if test x"$new" != x"$old"; then
48 rm -- "$dst.$$.tmp"
49else
50 echo " GEN $dst" 46 echo " GEN $dst"
51 mv -- "$dst.$$.tmp" "$dst" 47 printf "%s\n" "$new" >"$dst"
52fi 48fi
53 49
54# (Re)generate */Kbuild and */Config.in 50# (Re)generate */Kbuild and */Config.in
55find -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
96done 93done
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
43echo '# CONFIG_DEBUG_PESSIMIZE is not set' >>.config 43echo '# CONFIG_DEBUG_PESSIMIZE is not set' >>.config
44echo '# CONFIG_WERROR is not set' >>.config 44echo '# CONFIG_WERROR is not set' >>.config
45echo "CONFIG_CROSS_COMPILER_PREFIX=\"${CROSS_COMPILER_PREFIX}\"" >>.config 45echo "CONFIG_CROSS_COMPILER_PREFIX=\"${CROSS_COMPILER_PREFIX}\"" >>.config
46echo '# CONFIG_SELINUX is not set' >>.config
47echo '# CONFIG_EFENCE is not set' >>.config
48echo '# CONFIG_DMALLOC is not set' >>.config
49echo '# CONFIG_RFKILL is not set' >>.config
46 50
47# If glibc, don't build static 51# If glibc, don't build static
48if test x"$LIBC" = x"glibc"; then 52if 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
54fi 58fi
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.
58if test x"$LIBC" = x"uclibc"; then 62if 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
68fi 75fi
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
78fi 86fi
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
3b=`basename $PWD`
4test "${b#busybox}" != "$b" || { echo "Must be run in busybox tree"; exit 1; }
5
6rm -rf ../testdir_make_O.$$
7mkdir ../testdir_make_O.$$
8odir=`cd ../testdir_make_O.$$ && pwd`
9test -d "$odir" || exit 1
10
11make 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
86SORT_SECTION=`check_cc "-Wl,--sort-section,alignment" ""` 86SORT_SECTION=`check_cc "-Wl,--sort-section,alignment" ""`
87 87
88START_GROUP="-Wl,--start-group"
89END_GROUP="-Wl,--end-group"
90INFO_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)
89SORT_COMMON=`check_cc "-Wl,--sort-common" ""` 93SORT_COMMON=`check_cc "-Wl,--sort-common" ""`
90 94
@@ -114,13 +118,13 @@ LDLIBS=`echo "$LDLIBS" | xargs -n1 | sort | uniq | xargs`
114echo "Trying libraries: $LDLIBS" 118echo "Trying libraries: $LDLIBS"
115# "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" 119# "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3"
116l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` 120l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'`
117test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" 121test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP"
118try $CC $CFLAGS $LDFLAGS \ 122try $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
170echo "Final link with: ${LDLIBS:-<none>}" 174echo "Final link with: ${LDLIBS:-<none>}"
171l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` 175l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'`
172test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" 176test "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)
174if ! test -f busybox_ldscript; then 178if ! 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
113config 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
127config HUSH_BASH_COMPAT
128 bool "bash-compatible extensions"
129 default y
130 depends on HUSH
131 help
132 Enable bash-compatible extensions.
133
134config 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
141config 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
151config 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
162config 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
169config 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
176config 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
183config 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
190config 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
197config 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
204config 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
211config 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
220choice 114choice
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:=
9INSERT 9INSERT
10 10
11lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 11lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
12lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o
13lib-$(CONFIG_CTTYHACK) += cttyhack.o 12lib-$(CONFIG_CTTYHACK) += cttyhack.o
14 13
15lib-$(CONFIG_SH_MATH_SUPPORT) += math.o 14lib-$(CONFIG_SH_MATH_SUPPORT) += math.o
16lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 15lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
17lib-$(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
7174static char *expdir;
7175
7176/* 7178/*
7177 * Do metacharacter (i.e. *, ?, [...]) expansion. 7179 * Do metacharacter (i.e. *, ?, [...]) expansion.
7178 */ 7180 */
7179static void 7181static void
7180expmeta(char *enddir, char *name) 7182expmeta(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 @@
1192\.168\.0\.1
2192\.168\.0\.1[
3192\.168\.0\.1[
4192\\.168\\.0\\.1[
5192\.168\.0\.1[
6192\.168\.0\.1
7192\.168\.0\.1[
8192\.168\.0\.1[
9192\\.168\\.0\\.1[
10192\.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
5IP=192.168.0.1
6
7rm -f '192.168.0.1['
8echo "${IP//./\\.}"
9echo "${IP//./\\.}"'[' # bug was here
10echo "${IP//./\\.}[" # bug was here
11echo "${IP//./\\\\.}[" # bug was here
12echo "192\.168\.0\.1["
13
14echo >'192.168.0.1['
15echo "${IP//./\\.}"
16echo "${IP//./\\.}"'[' # bug was here
17echo "${IP//./\\.}[" # bug was here
18echo "${IP//./\\\\.}[" # bug was here
19echo "192\.168\.0\.1["
20
21rm -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 @@
1Ok
2Done: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 @@
1echo Ok >file.tmp
2cat 0<>file.tmp
3echo Done:$?
4rm 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
1218static int check_and_run_traps(int sig) 1358static 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
1322static const char* FAST_FUNC get_local_var_value(const char *name) 1462static 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)
2952static char **expand_assignments(char **argv, int count) 3106static 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
3851static 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
4342static 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}
4147static NOINLINE int run_pipe(struct pipe *pi) 4359static 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 */
5834static void add_till_backquote(o_string *dest, struct in_str *input); 6066static 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 @@
1Assignments only: c=a
2Assignments and a command: c=a
3Assignments and a builtin: c=a
4Assignments and a function: c=a
5Done
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 @@
1a=a
2
3b=b
4c=c
5# Second assignment depends on the first:
6b=$a c=$b
7echo Assignments only: c=$c
8
9b=b
10c=c
11b=$a c=$b "$THIS_SH" -c 'echo Assignments and a command: c=$c'
12
13b=b
14c=c
15b=$a c=$b eval 'echo Assignments and a builtin: c=$c'
16
17b=b
18c=c
19f() { echo Assignments and a function: c=$c; }
20b=$a c=$b f
21
22echo 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
10test -f "$bindir/.config" && . "$bindir/.config" 9test -f "$bindir/.config" && . "$bindir/.config"
11 10
12test x"CONFIG_SCRIPT" = x"y" || exit 0 11test 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
7test -f "$bindir/.config" && . "$bindir/.config" 6test -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
101rm -rf cpio.testdir 101rm -rf cpio.testdir
102optional FEATURE_CPIO_O 102optional FEATURE_CPIO_O FEATURE_STAT_FORMAT
103mkdir cpio.testdir 103mkdir cpio.testdir
104touch cpio.testdir/file 104touch cpio.testdir/file
105chmod 6755 cpio.testdir/file # sets suid/sgid bits 105chmod 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 @@
1unset LANG
2
1dt=`busybox date -d 1:2 +%T` 3dt=`busybox date -d 1:2 +%T`
2test x"$dt" = x"01:02:00" 4test 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
105rm -rf diff1 diff2 106rm -rf diff1 diff2
107
106mkdir diff1 diff2 diff2/subdir 108mkdir diff1 diff2 diff2/subdir
107echo qwe >diff1/- 109echo qwe >diff1/-
108echo asd >diff2/subdir/- 110echo asd >diff2/subdir/-
@@ -187,4 +189,29 @@ SKIP=
187# clean up 189# clean up
188rm -rf diff1 diff2 190rm -rf diff1 diff2
189 191
192# NOT using directory structure from prev test...
193mkdir diff1 diff2
194echo qwe >diff1/-
195echo rty >diff2/-
196optional FEATURE_DIFF_DIR
197testing "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 "" ""
212SKIP=
213
214# clean up
215rm -rf diff1 diff2
216
190exit $FAILCOUNT 217exit $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
6test -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
15optional UNICODE_SUPPORT 16test x"$CONFIG_UNICODE_SUPPORT" = x"y" \
16testing "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"
21SKIP=
22
23 23
24exit $FAILCOUNT 24exit $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
6test -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
28is here:>\0< - they must be preserved 29is here:>\0< - they must be preserved
29" \ 30" \
30 31
31optional UNICODE_SUPPORT
32# The text was taken from English and Ukrainian wikipedia pages 32# The text was taken from English and Ukrainian wikipedia pages
33testing "fold -sw66 with unicode input" "fold -sw66" \ 33test 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 "\
35The Andromeda Galaxy (pronounced /ænˈdrɒmədə/, also known as \n\ 37The Andromeda Galaxy (pronounced /ænˈdrɒmədə/, also known as \n\
36Messier 31, M31, or NGC224; often referred to as the Great \n\ 38Messier 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На початку ХХІ ст. в центрі галактики виявлено чорну дірку."
59SKIP=
60 61
61exit $FAILCOUNT 62exit $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
7test -f "$bindir/.config" && . "$bindir/.config" 6test -f "$bindir/.config" && . "$bindir/.config"
8 7
9rm -rf ls.testdir >/dev/null 8rm -rf ls.testdir 2>/dev/null
10mkdir ls.testdir || exit 1 9mkdir 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.
17test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ 16test 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
136test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ 136test 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
7test -f "$bindir/.config" && . "$bindir/.config" 6test -f "$bindir/.config" && . "$bindir/.config"
8 7
9test "`id -u`" = 0 || { 8test "`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
6test -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" \
30testing "unexpand case 8" "unexpand" \ 31testing "unexpand case 8" "unexpand" \
31 "a b\n" "" "a b\n" \ 32 "a b\n" "" "a b\n" \
32 33
33optional UNICODE_SUPPORT 34test x"$CONFIG_UNICODE_SUPPORT" = x"y" \
34testing "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"
36SKIP=
37 38
38exit $FAILCOUNT 39exit $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
473config VOLUMEID
474 bool #No description makes it a hidden option
475 default n
476
477config FEATURE_VOLUMEID_EXT
478 bool "Ext filesystem"
479 default y
480 depends on VOLUMEID
481 help
482 TODO
483
484config FEATURE_VOLUMEID_BTRFS
485 bool "btrfs filesystem"
486 default y
487 depends on VOLUMEID
488 help
489 TODO
490
491config FEATURE_VOLUMEID_REISERFS
492 bool "Reiser filesystem"
493 default y
494 depends on VOLUMEID
495 help
496 TODO
497
498config FEATURE_VOLUMEID_FAT
499 bool "fat filesystem"
500 default y
501 depends on VOLUMEID
502 help
503 TODO
504
505config FEATURE_VOLUMEID_HFS
506 bool "hfs filesystem"
507 default y
508 depends on VOLUMEID
509 help
510 TODO
511
512config 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
526config FEATURE_VOLUMEID_XFS
527 bool "xfs filesystem"
528 default y
529 depends on VOLUMEID
530 help
531 TODO
532
533config FEATURE_VOLUMEID_NTFS
534 bool "ntfs filesystem"
535 default y
536 depends on VOLUMEID
537 help
538 TODO
539
540config FEATURE_VOLUMEID_ISO9660
541 bool "iso9660 filesystem"
542 default y
543 depends on VOLUMEID
544 help
545 TODO
546
547config FEATURE_VOLUMEID_UDF
548 bool "udf filesystem"
549 default y
550 depends on VOLUMEID
551 help
552 TODO
553
554config FEATURE_VOLUMEID_LUKS
555 bool "luks filesystem"
556 default y
557 depends on VOLUMEID
558 help
559 TODO
560
561config 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
575config 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
589config FEATURE_VOLUMEID_ROMFS
590 bool "romfs filesystem"
591 default y
592 depends on VOLUMEID
593 help
594 TODO
595
596config 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
625config 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
681config FEATURE_VOLUMEID_LINUXRAID
682 bool "linuxraid"
683 default y
684 depends on VOLUMEID
685 help
686 TODO
687
688config MOUNT 473config 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
725config VOLUMEID
726 bool #No description makes it a hidden option
727 default n
728
729menu "Filesystem/Volume identification"
730 depends on VOLUMEID
731
732config FEATURE_VOLUMEID_EXT
733 bool "Ext filesystem"
734 default y
735 depends on VOLUMEID
736 help
737 TODO
738
739config FEATURE_VOLUMEID_BTRFS
740 bool "btrfs filesystem"
741 default y
742 depends on VOLUMEID
743 help
744 TODO
745
746config FEATURE_VOLUMEID_REISERFS
747 bool "Reiser filesystem"
748 default y
749 depends on VOLUMEID
750 help
751 TODO
752
753config FEATURE_VOLUMEID_FAT
754 bool "fat filesystem"
755 default y
756 depends on VOLUMEID
757 help
758 TODO
759
760config FEATURE_VOLUMEID_HFS
761 bool "hfs filesystem"
762 default y
763 depends on VOLUMEID
764 help
765 TODO
766
767config 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
781config FEATURE_VOLUMEID_XFS
782 bool "xfs filesystem"
783 default y
784 depends on VOLUMEID
785 help
786 TODO
787
788config FEATURE_VOLUMEID_NTFS
789 bool "ntfs filesystem"
790 default y
791 depends on VOLUMEID
792 help
793 TODO
794
795config FEATURE_VOLUMEID_ISO9660
796 bool "iso9660 filesystem"
797 default y
798 depends on VOLUMEID
799 help
800 TODO
801
802config FEATURE_VOLUMEID_UDF
803 bool "udf filesystem"
804 default y
805 depends on VOLUMEID
806 help
807 TODO
808
809config FEATURE_VOLUMEID_LUKS
810 bool "luks filesystem"
811 default y
812 depends on VOLUMEID
813 help
814 TODO
815
816config 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
830config 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
844config FEATURE_VOLUMEID_ROMFS
845 bool "romfs filesystem"
846 default y
847 depends on VOLUMEID
848 help
849 TODO
850
851config 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
880config 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
936config FEATURE_VOLUMEID_LINUXRAID
937 bool "linuxraid"
938 default y
939 depends on VOLUMEID
940 help
941 TODO
942
943endmenu
944
940endmenu 945endmenu
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
37static void gotsig(int sig UNUSED_PARAM) 37static void gotsig(int sig UNUSED_PARAM)
@@ -46,7 +46,7 @@ static void gotsig(int sig UNUSED_PARAM)
46int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 46int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
47int more_main(int argc UNUSED_PARAM, char **argv) 47int 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 */
35static 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
52int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
53int 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 */