Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/shell
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- Location:
- branches/2.2.9/mindi-busybox/shell
- Files:
-
- 444 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/shell/Config.in
r1765 r2725 1 # DO NOT EDIT. This file is generated from Config.src 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 6 7 menu "Shells" 7 8 8 choice9 prompt "Choose your default shell"10 default FEATURE_SH_IS_NONE11 help12 Choose a shell. The ash shell is the most bash compatible13 and full featured one.14 15 config FEATURE_SH_IS_ASH16 select ASH17 bool "ash"18 19 config FEATURE_SH_IS_HUSH20 select HUSH21 bool "hush"22 23 config FEATURE_SH_IS_LASH24 select LASH25 bool "lash"26 27 config FEATURE_SH_IS_MSH28 select MSH29 bool "msh"30 31 config FEATURE_SH_IS_NONE32 bool "none"33 34 endchoice35 36 9 config ASH 37 10 bool "ash" 38 default n39 select TEST11 default y 12 depends on !NOMMU 40 13 help 41 14 Tha 'ash' shell adds about 60k in the default configuration and is 42 15 the most complete and most pedantically correct shell included with 43 busybox. 16 busybox. This shell is actually a derivative of the Debian 'dash' 44 17 shell (by Herbert Xu), which was created by porting the 'ash' shell 45 18 (written by Kenneth Almquist) from NetBSD. 46 19 47 comment "Ash Shell Options" 48 depends on ASH 20 config ASH_BASH_COMPAT 21 bool "bash-compatible extensions" 22 default y 23 depends on ASH 24 help 25 Enable bash-compatible extensions. 49 26 50 27 config ASH_JOB_CONTROL … … 55 32 Enable job control in the ash shell. 56 33 57 config ASH_READ_NCHARS58 bool "'read -n N' and 'read -s' support"59 default n60 depends on ASH61 help62 'read -n N' will return a value after N characters have been read.63 'read -s' will read without echoing the user's input.64 65 config ASH_READ_TIMEOUT66 bool "'read -t S' support."67 default n68 depends on ASH69 help70 'read -t S' will return a value after S seconds have passed.71 This implementation will allow fractional seconds, expressed72 as a decimal fraction, e.g. 'read -t 2.5 foo'.73 74 34 config ASH_ALIAS 75 35 bool "alias support" … … 79 39 Enable alias support in the ash shell. 80 40 81 config ASH_MATH_SUPPORT82 bool "Posix math support"83 default y84 depends on ASH85 help86 Enable math support in the ash shell.87 88 config ASH_MATH_SUPPORT_6489 bool "Extend Posix math support to 64 bit"90 default n91 depends on ASH_MATH_SUPPORT92 help93 Enable 64-bit math support in the ash shell. This will make94 the shell slightly larger, but will allow computation with very95 large numbers.96 97 41 config ASH_GETOPTS 98 42 bool "Builtin getopt to parse positional parameters" 99 default n43 default y 100 44 depends on ASH 101 45 help … … 105 49 bool "Builtin version of 'echo'" 106 50 default y 107 select ECHO108 51 depends on ASH 109 52 help 110 53 Enable support for echo, builtin to ash. 54 55 config ASH_BUILTIN_PRINTF 56 bool "Builtin version of 'printf'" 57 default y 58 depends on ASH 59 help 60 Enable support for printf, builtin to ash. 111 61 112 62 config ASH_BUILTIN_TEST 113 63 bool "Builtin version of 'test'" 114 64 default y 115 select TEST116 65 depends on ASH 117 66 help … … 120 69 config ASH_CMDCMD 121 70 bool "'command' command to override shell builtins" 122 default n71 default y 123 72 depends on ASH 124 73 help … … 129 78 config ASH_MAIL 130 79 bool "Check for new mail on interactive shells" 131 default y80 default n 132 81 depends on ASH 133 82 help … … 142 91 143 92 config ASH_RANDOM_SUPPORT 144 bool "Pseudorandom generator and variable $RANDOM"145 default n93 bool "Pseudorandom generator and $RANDOM variable" 94 default y 146 95 depends on ASH 147 96 help … … 149 98 Each read of "$RANDOM" will generate a new pseudorandom value. 150 99 You can reset the generator by using a specified start value. 151 After "unset RANDOM" the ngenerator will switch off and this100 After "unset RANDOM" the generator will switch off and this 152 101 variable will no longer have special treatment. 153 102 154 103 config ASH_EXPAND_PRMT 155 104 bool "Expand prompt string" 156 default n157 depends on ASH 158 help 159 "PS#" may becontain volatile content, such as backquote commands.105 default y 106 depends on ASH 107 help 108 "PS#" may contain volatile content, such as backquote commands. 160 109 This option recreates the prompt string from the environment 161 110 variable each time it is displayed. 162 111 112 config CTTYHACK 113 bool "cttyhack" 114 default y 115 help 116 One common problem reported on the mailing list is "can't access tty; 117 job control turned off" error message which typically appears when 118 one tries to use shell with stdin/stdout opened to /dev/console. 119 This device is special - it cannot be a controlling tty. 120 121 Proper solution is to use correct device instead of /dev/console. 122 123 cttyhack provides "quick and dirty" solution to this problem. 124 It analyzes stdin with various ioctls, trying to determine whether 125 it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). 126 If it detects one, it closes stdin/out/err and reopens that device. 127 Then it executes given program. Opening the device will make 128 that device a controlling tty. This may require cttyhack 129 to be a session leader. 130 131 Example for /etc/inittab (for busybox init): 132 133 ::respawn:/bin/cttyhack /bin/sh 134 135 Starting an interactive shell from boot shell script: 136 137 setsid cttyhack sh 138 139 Giving controlling tty to shell running with PID 1: 140 141 # exec cttyhack sh 142 143 Without cttyhack, you need to know exact tty name, 144 and do something like this: 145 146 # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1' 147 163 148 config HUSH 164 149 bool "hush" 165 default n 166 select TRUE 167 select FALSE 168 select TEST 169 help 170 hush is a very small shell (just 18k) and it has fairly complete 171 Bourne shell grammar. It even handles all the normal flow control 172 options such as if/then/elif/else/fi, for/in/do/done, while loops, 173 etc. 174 175 It does not handle case/esac, select, function, here documents ( << 176 word ), arithmetic expansion, aliases, brace expansion, tilde 177 expansion, &> and >& redirection of stdout+stderr, etc. 150 default y 151 help 152 hush is a small shell (25k). It handles the normal flow control 153 constructs such as if/then/elif/else/fi, for/in/do/done, while loops, 154 case/esac. Redirections, here documents, $((arithmetic)) 155 and functions are supported. 156 157 It will compile and work on no-mmu systems. 158 159 It does not handle select, aliases, tilde expansion, 160 &>file and >&file redirection of stdout+stderr. 161 162 config HUSH_BASH_COMPAT 163 bool "bash-compatible extensions" 164 default y 165 depends on HUSH 166 help 167 Enable bash-compatible extensions. 168 169 config HUSH_BRACE_EXPANSION 170 bool "Brace expansion" 171 default y 172 depends on HUSH_BASH_COMPAT 173 help 174 Enable {abc,def} extension. 178 175 179 176 config HUSH_HELP 180 177 bool "help builtin" 181 default n178 default y 182 179 depends on HUSH 183 180 help … … 191 188 Enable interactive mode (prompt and command editing). 192 189 Without this, hush simply reads and executes commands 193 from stdin just like a shell script from thefile.190 from stdin just like a shell script from a file. 194 191 No prompt, no PS1/PS2 magic shell variables. 192 193 config HUSH_SAVEHISTORY 194 bool "Save command history to .hush_history" 195 default y 196 depends on HUSH_INTERACTIVE && FEATURE_EDITING_SAVEHISTORY 197 help 198 Enable history saving in hush. 195 199 196 200 config HUSH_JOB 197 201 bool "Job control" 198 default n202 default y 199 203 depends on HUSH_INTERACTIVE 200 204 help … … 207 211 config HUSH_TICK 208 212 bool "Process substitution" 209 default n213 default y 210 214 depends on HUSH 211 215 help … … 214 218 config HUSH_IF 215 219 bool "Support if/then/elif/else/fi" 216 default n220 default y 217 221 depends on HUSH 218 222 help … … 221 225 config HUSH_LOOPS 222 226 bool "Support for, while and until loops" 227 default y 228 depends on HUSH 229 help 230 Enable for, while and until loops in hush. 231 232 config HUSH_CASE 233 bool "Support case ... esac statement" 234 default y 235 depends on HUSH 236 help 237 Enable case ... esac statement in hush. +400 bytes. 238 239 config HUSH_FUNCTIONS 240 bool "Support funcname() { commands; } syntax" 241 default y 242 depends on HUSH 243 help 244 Enable support for shell functions in hush. +800 bytes. 245 246 config HUSH_LOCAL 247 bool "Support local builtin" 248 default y 249 depends on HUSH_FUNCTIONS 250 help 251 Enable support for local variables in functions. 252 253 config HUSH_RANDOM_SUPPORT 254 bool "Pseudorandom generator and $RANDOM variable" 255 default y 256 depends on HUSH 257 help 258 Enable pseudorandom generator and dynamic variable "$RANDOM". 259 Each read of "$RANDOM" will generate a new pseudorandom value. 260 261 config HUSH_EXPORT_N 262 bool "Support 'export -n' option" 263 default y 264 depends on HUSH 265 help 266 export -n unexports variables. It is a bash extension. 267 268 config HUSH_MODE_X 269 bool "Support 'hush -x' option and 'set -x' command" 270 default y 271 depends on HUSH 272 help 273 This instructs hush to print commands before execution. 274 Adds ~300 bytes. 275 276 config MSH 277 bool "msh (deprecated: aliased to hush)" 223 278 default n 224 depends on HUSH 225 help 226 Enable for, while and until loops in hush. 227 228 config LASH 229 bool "lash" 230 default n 231 select TRUE 232 select FALSE 233 select TEST 234 help 235 lash is the very smallest shell (adds just 10k) and it is quite 236 usable as a command prompt, but it is not suitable for any but the 237 most trivial scripting (such as an initrd that calls insmod a few 238 times) since it does not understand any Bourne shell grammar. It 239 does handle pipes, redirects, and job control though. Adding in 240 command editing makes it a very nice lightweight command prompt. 241 242 243 config MSH 244 bool "msh" 245 default n 246 select TRUE 247 select FALSE 248 select TEST 249 help 250 The minix shell (adds just 30k) is quite complete and handles things 251 like for/do/done, case/esac and all the things you expect a Bourne 252 shell to do. It is not always pedantically correct about Bourne 253 shell grammar (try running the shell testscript "tests/sh.testcases" 254 on it and compare vs bash) but for most things it works quite well. 255 It also uses only vfork, so it can be used on uClinux systems. 256 257 comment "Bourne Shell Options" 258 depends on MSH || LASH || HUSH || ASH 279 select HUSH 280 help 281 msh is deprecated and will be removed, please migrate to hush. 282 283 284 choice 285 prompt "Choose which shell is aliased to 'sh' name" 286 default FEATURE_SH_IS_ASH 287 help 288 Choose which shell you want to be executed by 'sh' alias. 289 The ash shell is the most bash compatible and full featured one. 290 291 # note: cannot use "select ASH" here, it breaks "make allnoconfig" 292 config FEATURE_SH_IS_ASH 293 depends on ASH 294 bool "ash" 295 depends on !NOMMU 296 297 config FEATURE_SH_IS_HUSH 298 depends on HUSH 299 bool "hush" 300 301 config FEATURE_SH_IS_NONE 302 bool "none" 303 304 endchoice 305 306 choice 307 prompt "Choose which shell is aliased to 'bash' name" 308 default FEATURE_BASH_IS_NONE 309 help 310 Choose which shell you want to be executed by 'bash' alias. 311 The ash shell is the most bash compatible and full featured one. 312 313 Note that selecting this option does not switch on any bash 314 compatibility code. It merely makes it possible to install 315 /bin/bash (sym)link and run scripts which start with 316 #!/bin/bash line. 317 318 Many systems use it in scripts which use bash-specific features, 319 even simple ones like $RANDOM. Without this option, busybox 320 can't be used for running them because it won't recongnize 321 "bash" as a supported applet name. 322 323 config FEATURE_BASH_IS_ASH 324 depends on ASH 325 bool "ash" 326 depends on !NOMMU 327 328 config FEATURE_BASH_IS_HUSH 329 depends on HUSH 330 bool "hush" 331 332 config FEATURE_BASH_IS_NONE 333 bool "none" 334 335 endchoice 336 337 338 config SH_MATH_SUPPORT 339 bool "POSIX math support" 340 default y 341 depends on ASH || HUSH 342 help 343 Enable math support in the shell via $((...)) syntax. 344 345 config SH_MATH_SUPPORT_64 346 bool "Extend POSIX math support to 64 bit" 347 default y 348 depends on SH_MATH_SUPPORT 349 help 350 Enable 64-bit math support in the shell. This will make the shell 351 slightly larger, but will allow computation with very large numbers. 352 This is not in POSIX, so do not rely on this in portable code. 259 353 260 354 config FEATURE_SH_EXTRA_QUIET 261 355 bool "Hide message on interactive shell startup" 262 default n263 depends on MSH || LASH ||HUSH || ASH356 default y 357 depends on HUSH || ASH 264 358 help 265 359 Remove the busybox introduction when starting a shell. … … 268 362 bool "Standalone shell" 269 363 default n 270 depends on ( MSH || LASH ||HUSH || ASH) && FEATURE_PREFER_APPLETS364 depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS 271 365 help 272 366 This option causes busybox shells to use busybox applets 273 in preference to executables in the PATH whenever possible. 367 in preference to executables in the PATH whenever possible. For 274 368 example, entering the command 'ifconfig' into the shell would cause 275 busybox to use the ifconfig busybox applet. 369 busybox to use the ifconfig busybox applet. Specifying the fully 276 370 qualified executable name, such as '/sbin/ifconfig' will still 277 execute the /sbin/ifconfig executable on the filesystem. 371 execute the /sbin/ifconfig executable on the filesystem. This option 278 372 is generally used when creating a statically linked version of busybox 279 373 for use as a rescue shell, in the event that you screw up your system. … … 289 383 # untrue? 290 384 # Note that this will *also* cause applets to take precedence 291 # over shell builtins of the same name. 385 # over shell builtins of the same name. So turning this on will 292 386 # eliminate any performance gained by turning on the builtin "echo" 293 387 # and "test" commands in ash. 294 388 # untrue? 295 389 # Note that when using this option, the shell will attempt to directly 296 # run '/bin/busybox'. 390 # run '/bin/busybox'. If you do not have the busybox binary sitting in 297 391 # that exact location with that exact name, this option will not work at 298 392 # all. 299 393 300 config CTTYHACK301 bool " cttyhack"394 config FEATURE_SH_NOFORK 395 bool "Run 'nofork' applets directly" 302 396 default n 303 help 304 One common problem reported on the mailing list is "can't access tty; 305 job control turned off" error message which typically appears when 306 one tries to use shell with stdin/stdout opened to /dev/console. 307 This device is special - it cannot be a controlling tty. 308 309 Proper solution is to use correct device instead of /dev/console. 310 311 cttyhack provides "quick and dirty" solution to this problem. 312 It analyzes stdin with various ioctls, trying to determine whether 313 it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). 314 If it detects one, it closes stdin/out/err and reopens that device. 315 Then it executes given program. Usage example for /etc/inittab 316 (for busybox init): 317 318 ::respawn:/bin/cttyhack /bin/sh 397 depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS 398 help 399 This option causes busybox shells [currently only ash] 400 to not execute typical fork/exec/wait sequence, but call <applet>_main 401 directly, if possible. (Sometimes it is not possible: for example, 402 this is not possible in pipes). 403 404 This will be done only for some applets (those which are marked 405 NOFORK in include/applets.h). 406 407 This may significantly speed up some shell scripts. 408 409 This feature is relatively new. Use with care. 319 410 320 411 endmenu -
branches/2.2.9/mindi-busybox/shell/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 4 5 # 5 # Licensed under the GPL v2, see the file LICENSE in this tarball.6 # Licensed under GPLv2, see file LICENSE in this source tree. 6 7 7 8 lib-y:= 8 lib-$(CONFIG_ASH) += ash.o9 lib-$(CONFIG_HUSH) += hush.o10 lib-$(CONFIG_LASH) += lash.o11 lib-$(CONFIG_MSH) += msh.o12 9 10 lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 11 lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 13 12 lib-$(CONFIG_CTTYHACK) += cttyhack.o 13 lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o 14 lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o 15 16 lib-$(CONFIG_SH_MATH_SUPPORT) += math.o -
branches/2.2.9/mindi-busybox/shell/README
r1765 r2725 1 Various bits of what is known about busybox shells, in no particular order. 1 http://www.opengroup.org/onlinepubs/9699919799/ 2 Open Group Base Specifications Issue 7 2 3 3 2007-06-134 hush: exec <"$1" doesn't do parameter subst5 4 6 2007-05-24 7 hush: environment-related memory leak plugged, with net code size 8 decrease. 5 http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html 6 Shell & Utilities 9 7 10 2007-05-24 11 hush: '( echo ${name )' will show syntax error message, but prompt 12 doesn't return (need to press <enter>). Pressing Ctrl-C, <enter>, 13 '( echo ${name )' again, Ctrl-C segfaults. 8 It says that any of the standard utilities may be implemented 9 as a regular shell built-in. It gives a list of utilities which 10 are usually implemented that way (and some of them can only 11 be implemented as built-ins, like "alias"): 14 12 15 2007-05-21 16 hush: environment cannot be handled by libc routines as they are leaky 17 (by API design and thus unfixable): hush will leak memory in this script, 18 bash does not: 19 pid=$$ 20 while true; do 21 unset t; 22 t=111111111111111111111111111111111111111111111111111111111111111111111111 23 export t 24 ps -o vsz,pid,comm | grep " $pid " 25 done 26 The fix is to not use setenv/putenv/unsetenv but manipulate env ourself. TODO. 27 hush: meanwhile, first three command subst bugs mentioned below are fixed. :) 13 alias 14 bg 15 cd 16 command 17 false 18 fc 19 fg 20 getopts 21 jobs 22 kill 23 newgrp 24 pwd 25 read 26 true 27 umask 28 unalias 29 wait 28 30 29 2007-05-0630 hush: more bugs spotted. Comparison with bash:31 bash-3.2# echo "TEST`date;echo;echo`BEST"32 TESTSun May 6 09:21:05 CEST 2007BEST [we dont strip eols]33 bash-3.2# echo "TEST`echo '$(echo ZZ)'`BEST"34 TEST$(echo ZZ)BEST [we execute inner echo]35 bash-3.2# echo "TEST`echo "'"`BEST"36 TEST'BEST [we totally mess up this one]37 bash-3.2# echo `sleep 5`38 [Ctrl-C should work, Ctrl-Z should do nothing][we totally mess up this one]39 bash-3.2# if true; then40 > [Ctrl-C]41 bash-3.2# [we re-issue "> "]42 bash-3.2# if echo `sleep 5`; then43 > true; fi [we execute sleep before "> "]44 31 45 2007-05-04 46 hush: made ctrl-Z/C work correctly for "while true; do true; done" 47 (namely, it backgrounds/interrupts entire "while") 32 http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 33 Shell Command Language 48 34 49 2007-05-03 50 hush: new bug spotted: Ctrl-C on "while true; do true; done" doesn't 51 work right: 52 # while true; do true; done 53 [1] 0 true <-- pressing Ctrl-C several times... 54 [2] 0 true 55 [3] 0 true 56 Segmentation fault 35 It says that shell must implement special built-ins. Special built-ins 36 differ from regular ones by the fact that variable assignments 37 done on special builtin are *PRESERVED*. That is, 57 38 58 2007-05-03 59 hush: update on "sleep 1 | exit 3; echo $?" bug. 60 parse_stream_outer() repeatedly calls parse_stream(). 61 parse_stream() is now fixed to stop on ';' in this example, 62 fixing it (parse_stream_outer() will call parse_stream() 1st time, 63 execute the parse tree, call parse_stream() 2nd time and execute the tree). 64 But it's not the end of story. 65 In more complex situations we _must_ parse way farther before executing. 66 Example #2: "{ sleep 1 | exit 3; echo $?; ...few_lines... } >file". 67 Because of redirection, we cannot execute 1st pipe before we parse it all. 68 We probably need to learn to store $var expressions in parse tree. 69 Debug printing of parse tree would be nice too. 39 VAR=VAL special_builtin; echo $VAR 70 40 71 2007-04-28 72 hush: Ctrl-C and Ctrl-Z for single NOFORK commands are working. 73 Memory and other resource leaks (opendir) are not addressed 74 (testcase is "rm -i" interrupted by ctrl-c). 41 should print VAL. 75 42 76 2007-04-21 77 hush: "sleep 5 | sleep 6" + Ctrl-Z + fg seems to work. 78 "rm -i" + Ctrl-C, "sleep 5" + Ctrl-Z still doesn't work 79 for SH_STANDALONE case :( 43 (Another distinction is that an error in special built-in should 44 abort the shell, but this is not such a critical difference, 45 and moreover, at least bash's "set" does not follow this rule, 46 which is even codified in autoconf configure logic now...) 80 47 81 2007-04-21 82 hush: fixed non-backgrounding of "sleep 1 &" and totally broken 83 "sleep 1 | sleep 2 &". Noticed a bug where successive jobs 84 get numbers 1,2,3 even when job #1 has exited before job# 2 is started. 85 (bash reuses #1 in this case) 48 List of special builtins: 86 49 87 2007-04-21 88 hush: "sleep 1 | exit 3; echo $?" prints 0 because $? is substituted 89 _before_ pipe gets executed!! run_list_real() already has "pipe;echo" 90 parsed and handed to it for execution, so it sees "pipe"; "echo 0". 50 . file 51 : [argument...] 52 break [n] 53 continue [n] 54 eval [argument...] 55 exec [command [argument...]] 56 exit [n] 57 export name[=word]... 58 export -p 59 readonly name[=word]... 60 readonly -p 61 return [n] 62 set [-abCefhmnuvx] [-o option] [argument...] 63 set [+abCefhmnuvx] [+o option] [argument...] 64 set -- [argument...] 65 set -o 66 set +o 67 shift [n] 68 times 69 trap n [condition...] 70 trap [action condition...] 71 unset [-fv] name... 91 72 92 2007-04-21 93 hush: removed setsid() and made job control sort-of-sometimes-work. 94 Ctrl-C in "rm -i" works now except for SH_STANDALONE case. 95 "sleep 1 | exit 3" + "echo $?" works, "sleep 1 | exit 3; echo $?" 96 shows exitcode 0 (should be 3). "sleep 1 | sleep 2 &" fails horribly. 73 In practice, no one uses this obscure feature - none of these builtins 74 gives any special reasons to play such dirty tricks. 97 75 98 2007-04-14 99 lash, hush: both do setsid() and as a result don't have ctty! 100 Ctrl-C doesn't work for any child (try rm -i), etc... 101 lash: bare ">file" doesn't create a file (hush works) 76 However. This section also says that *function invocation* should act 77 similar to special built-in. That is, variable assignments 78 done on function invocation should be preserved after function invocation. 79 80 This is significant: it is not unthinkable to want to run a function 81 with some variables set to special values. But because of the above, 82 it does not work: variable will "leak" out of the function. -
branches/2.2.9/mindi-busybox/shell/ash.c
r1772 r2725 2 2 /* 3 3 * ash shell port for busybox 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Original BSD copyright notice is retained at the end of this file. 4 9 * 5 10 * Copyright (c) 1989, 1991, 1993, 1994 … … 9 14 * was re-ported from NetBSD and debianized. 10 15 * 11 * 12 * This code is derived from software contributed to Berkeley by 13 * Kenneth Almquist. 14 * 15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 16 * 17 * Original BSD copyright notice is retained at the end of this file. 18 */ 19 20 /* 21 * rewrite arith.y to micro stack based cryptic algorithm by 22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 23 * 24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support 25 * dynamic variables. 26 * 27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be 28 * used in busybox and size optimizations, 29 * rewrote arith (see notes to this), added locale support, 30 * rewrote dynamic variables. 31 * 32 */ 33 34 /* 35 * The follow should be set to reflect the type of system you have: 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 17 */ 18 19 /* 20 * The following should be set to reflect the type of system you have: 36 21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 37 22 * define SYSV if you are running under System V. … … 43 28 */ 44 29 #define DEBUG 0 45 #define IFS_BROKEN 30 /* Tweak debug output verbosity here */ 31 #define DEBUG_TIME 0 32 #define DEBUG_PID 1 33 #define DEBUG_SIG 1 34 46 35 #define PROFILE 0 47 #if ENABLE_ASH_JOB_CONTROL 48 #define JOBS 1 49 #else 50 #define JOBS 0 51 #endif 52 53 #if DEBUG 54 #define _GNU_SOURCE 55 #endif 56 #include "busybox.h" /* for struct bb_applet */ 36 37 #define JOBS ENABLE_ASH_JOB_CONTROL 38 39 #include "busybox.h" /* for applet_names */ 57 40 #include <paths.h> 58 41 #include <setjmp.h> 59 42 #include <fnmatch.h> 60 #if JOBS || ENABLE_ASH_READ_NCHARS 61 #include <termios.h> 62 #endif 63 extern char **environ; 64 65 #if defined(__uClinux__) 66 #error "Do not even bother, ash will not run on uClinux" 67 #endif 68 69 70 /* ============ Misc helpers */ 71 72 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 73 74 /* C99 say: "char" declaration may be signed or unsigned default */ 75 #define signed_char2int(sc) ((int)((signed char)sc)) 43 #include <sys/times.h> 44 45 #include "shell_common.h" 46 #if ENABLE_SH_MATH_SUPPORT 47 # include "math.h" 48 #endif 49 #if ENABLE_ASH_RANDOM_SUPPORT 50 # include "random.h" 51 #else 52 # define CLEAR_RANDOM_T(rnd) ((void)0) 53 #endif 54 55 #include "NUM_APPLETS.h" 56 #if NUM_APPLETS == 1 57 /* STANDALONE does not make sense, and won't compile */ 58 # undef CONFIG_FEATURE_SH_STANDALONE 59 # undef ENABLE_FEATURE_SH_STANDALONE 60 # undef IF_FEATURE_SH_STANDALONE 61 # undef IF_NOT_FEATURE_SH_STANDALONE 62 # define ENABLE_FEATURE_SH_STANDALONE 0 63 # define IF_FEATURE_SH_STANDALONE(...) 64 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ 65 #endif 66 67 #ifndef PIPE_BUF 68 # define PIPE_BUF 4096 /* amount of buffering in a pipe */ 69 #endif 70 71 #if !BB_MMU 72 # error "Do not even bother, ash will not run on NOMMU machine" 73 #endif 74 75 //applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) 76 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) 77 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) 78 79 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 80 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 81 82 //config:config ASH 83 //config: bool "ash" 84 //config: default y 85 //config: depends on !NOMMU 86 //config: help 87 //config: Tha 'ash' shell adds about 60k in the default configuration and is 88 //config: the most complete and most pedantically correct shell included with 89 //config: busybox. This shell is actually a derivative of the Debian 'dash' 90 //config: shell (by Herbert Xu), which was created by porting the 'ash' shell 91 //config: (written by Kenneth Almquist) from NetBSD. 92 //config: 93 //config:config ASH_BASH_COMPAT 94 //config: bool "bash-compatible extensions" 95 //config: default y 96 //config: depends on ASH 97 //config: help 98 //config: Enable bash-compatible extensions. 99 //config: 100 //config:config ASH_JOB_CONTROL 101 //config: bool "Job control" 102 //config: default y 103 //config: depends on ASH 104 //config: help 105 //config: Enable job control in the ash shell. 106 //config: 107 //config:config ASH_ALIAS 108 //config: bool "alias support" 109 //config: default y 110 //config: depends on ASH 111 //config: help 112 //config: Enable alias support in the ash shell. 113 //config: 114 //config:config ASH_GETOPTS 115 //config: bool "Builtin getopt to parse positional parameters" 116 //config: default y 117 //config: depends on ASH 118 //config: help 119 //config: Enable getopts builtin in the ash shell. 120 //config: 121 //config:config ASH_BUILTIN_ECHO 122 //config: bool "Builtin version of 'echo'" 123 //config: default y 124 //config: depends on ASH 125 //config: help 126 //config: Enable support for echo, builtin to ash. 127 //config: 128 //config:config ASH_BUILTIN_PRINTF 129 //config: bool "Builtin version of 'printf'" 130 //config: default y 131 //config: depends on ASH 132 //config: help 133 //config: Enable support for printf, builtin to ash. 134 //config: 135 //config:config ASH_BUILTIN_TEST 136 //config: bool "Builtin version of 'test'" 137 //config: default y 138 //config: depends on ASH 139 //config: help 140 //config: Enable support for test, builtin to ash. 141 //config: 142 //config:config ASH_CMDCMD 143 //config: bool "'command' command to override shell builtins" 144 //config: default y 145 //config: depends on ASH 146 //config: help 147 //config: Enable support for the ash 'command' builtin, which allows 148 //config: you to run the specified command with the specified arguments, 149 //config: even when there is an ash builtin command with the same name. 150 //config: 151 //config:config ASH_MAIL 152 //config: bool "Check for new mail on interactive shells" 153 //config: default n 154 //config: depends on ASH 155 //config: help 156 //config: Enable "check for new mail" in the ash shell. 157 //config: 158 //config:config ASH_OPTIMIZE_FOR_SIZE 159 //config: bool "Optimize for size instead of speed" 160 //config: default y 161 //config: depends on ASH 162 //config: help 163 //config: Compile ash for reduced size at the price of speed. 164 //config: 165 //config:config ASH_RANDOM_SUPPORT 166 //config: bool "Pseudorandom generator and $RANDOM variable" 167 //config: default y 168 //config: depends on ASH 169 //config: help 170 //config: Enable pseudorandom generator and dynamic variable "$RANDOM". 171 //config: Each read of "$RANDOM" will generate a new pseudorandom value. 172 //config: You can reset the generator by using a specified start value. 173 //config: After "unset RANDOM" the generator will switch off and this 174 //config: variable will no longer have special treatment. 175 //config: 176 //config:config ASH_EXPAND_PRMT 177 //config: bool "Expand prompt string" 178 //config: default y 179 //config: depends on ASH 180 //config: help 181 //config: "PS#" may contain volatile content, such as backquote commands. 182 //config: This option recreates the prompt string from the environment 183 //config: variable each time it is displayed. 184 //config: 185 186 //usage:#define ash_trivial_usage NOUSAGE_STR 187 //usage:#define ash_full_usage "" 188 //usage:#define sh_trivial_usage NOUSAGE_STR 189 //usage:#define sh_full_usage "" 190 //usage:#define bash_trivial_usage NOUSAGE_STR 191 //usage:#define bash_full_usage "" 192 193 194 /* ============ Hash table sizes. Configurable. */ 195 196 #define VTABSIZE 39 197 #define ATABSIZE 39 198 #define CMDTABLESIZE 31 /* should be prime */ 76 199 77 200 … … 93 216 "u" "nounset", 94 217 "\0" "vi" 218 #if ENABLE_ASH_BASH_COMPAT 219 ,"\0" "pipefail" 220 #endif 95 221 #if DEBUG 96 222 ,"\0" "nolog" … … 99 225 }; 100 226 101 #define optletters(n) optletters_optnames[(n)][0]102 #define optnames(n) (&optletters_optnames[(n)][1])227 #define optletters(n) optletters_optnames[n][0] 228 #define optnames(n) (optletters_optnames[n] + 1) 103 229 104 230 enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; 105 231 106 static char optlist[NOPTS] ALIGN1; 107 232 233 /* ============ Misc data */ 234 235 #define msg_illnum "Illegal number: %s" 236 237 /* 238 * We enclose jmp_buf in a structure so that we can declare pointers to 239 * jump locations. The global variable handler contains the location to 240 * jump to when an exception occurs, and the global variable exception_type 241 * contains a code identifying the exception. To implement nested 242 * exception handlers, the user should save the value of handler on entry 243 * to an inner scope, set handler to point to a jmploc structure for the 244 * inner scope, and restore handler on exit from the scope. 245 */ 246 struct jmploc { 247 jmp_buf loc; 248 }; 249 250 struct globals_misc { 251 /* pid of main shell */ 252 int rootpid; 253 /* shell level: 0 for the main shell, 1 for its children, and so on */ 254 int shlvl; 255 #define rootshell (!shlvl) 256 char *minusc; /* argument to -c option */ 257 258 char *curdir; // = nullstr; /* current working directory */ 259 char *physdir; // = nullstr; /* physical working directory */ 260 261 char *arg0; /* value of $0 */ 262 263 struct jmploc *exception_handler; 264 265 volatile int suppress_int; /* counter */ 266 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ 267 /* last pending signal */ 268 volatile /*sig_atomic_t*/ smallint pending_sig; 269 smallint exception_type; /* kind of exception (0..5) */ 270 /* exceptions */ 271 #define EXINT 0 /* SIGINT received */ 272 #define EXERROR 1 /* a generic error */ 273 #define EXSHELLPROC 2 /* execute a shell procedure */ 274 #define EXEXEC 3 /* command execution failed */ 275 #define EXEXIT 4 /* exit the shell */ 276 #define EXSIG 5 /* trapped signal in wait(1) */ 277 278 smallint isloginsh; 279 char nullstr[1]; /* zero length string */ 280 281 char optlist[NOPTS]; 108 282 #define eflag optlist[0] 109 283 #define fflag optlist[1] … … 120 294 #define uflag optlist[12] 121 295 #define viflag optlist[13] 296 #if ENABLE_ASH_BASH_COMPAT 297 # define pipefail optlist[14] 298 #else 299 # define pipefail 0 300 #endif 122 301 #if DEBUG 123 #define nolog optlist[14] 124 #define debug optlist[15] 125 #endif 126 127 128 /* ============ Misc data */ 129 130 static char nullstr[1] ALIGN1; /* zero length string */ 131 static const char homestr[] ALIGN1 = "HOME"; 132 static const char snlfmt[] ALIGN1 = "%s\n"; 133 static const char illnum[] ALIGN1 = "Illegal number: %s"; 134 135 static char *minusc; /* argument to -c option */ 136 137 /* pid of main shell */ 138 static int rootpid; 139 /* shell level: 0 for the main shell, 1 for its children, and so on */ 140 static int shlvl; 141 #define rootshell (!shlvl) 142 /* trap handler commands */ 143 static char *trap[NSIG]; 144 static smallint isloginsh; 145 /* current value of signal */ 146 static char sigmode[NSIG - 1]; 147 /* indicates specified signal received */ 148 static char gotsig[NSIG - 1]; 149 static char *arg0; /* value of $0 */ 302 # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 303 # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 304 #endif 305 306 /* trap handler commands */ 307 /* 308 * Sigmode records the current value of the signal handlers for the various 309 * modes. A value of zero means that the current handler is not known. 310 * S_HARD_IGN indicates that the signal was ignored on entry to the shell. 311 */ 312 char sigmode[NSIG - 1]; 313 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 314 #define S_CATCH 2 /* signal is caught */ 315 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 316 #define S_HARD_IGN 4 /* signal is ignored permenantly */ 317 318 /* indicates specified signal received */ 319 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 320 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ 321 char *trap[NSIG]; 322 char **trap_ptr; /* used only by "trap hack" */ 323 324 /* Rarely referenced stuff */ 325 #if ENABLE_ASH_RANDOM_SUPPORT 326 random_t random_gen; 327 #endif 328 pid_t backgndpid; /* pid of last background process */ 329 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 330 }; 331 extern struct globals_misc *const ash_ptr_to_globals_misc; 332 #define G_misc (*ash_ptr_to_globals_misc) 333 #define rootpid (G_misc.rootpid ) 334 #define shlvl (G_misc.shlvl ) 335 #define minusc (G_misc.minusc ) 336 #define curdir (G_misc.curdir ) 337 #define physdir (G_misc.physdir ) 338 #define arg0 (G_misc.arg0 ) 339 #define exception_handler (G_misc.exception_handler) 340 #define exception_type (G_misc.exception_type ) 341 #define suppress_int (G_misc.suppress_int ) 342 #define pending_int (G_misc.pending_int ) 343 #define pending_sig (G_misc.pending_sig ) 344 #define isloginsh (G_misc.isloginsh ) 345 #define nullstr (G_misc.nullstr ) 346 #define optlist (G_misc.optlist ) 347 #define sigmode (G_misc.sigmode ) 348 #define gotsig (G_misc.gotsig ) 349 #define may_have_traps (G_misc.may_have_traps ) 350 #define trap (G_misc.trap ) 351 #define trap_ptr (G_misc.trap_ptr ) 352 #define random_gen (G_misc.random_gen ) 353 #define backgndpid (G_misc.backgndpid ) 354 #define job_warning (G_misc.job_warning) 355 #define INIT_G_misc() do { \ 356 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ 357 barrier(); \ 358 curdir = nullstr; \ 359 physdir = nullstr; \ 360 trap_ptr = trap; \ 361 } while (0) 362 363 364 /* ============ DEBUG */ 365 #if DEBUG 366 static void trace_printf(const char *fmt, ...); 367 static void trace_vprintf(const char *fmt, va_list va); 368 # define TRACE(param) trace_printf param 369 # define TRACEV(param) trace_vprintf param 370 # define close(fd) do { \ 371 int dfd = (fd); \ 372 if (close(dfd) < 0) \ 373 bb_error_msg("bug on %d: closing %d(0x%x)", \ 374 __LINE__, dfd, dfd); \ 375 } while (0) 376 #else 377 # define TRACE(param) 378 # define TRACEV(param) 379 #endif 380 381 382 /* ============ Utility functions */ 383 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 384 385 static int isdigit_str9(const char *str) 386 { 387 int maxlen = 9 + 1; /* max 9 digits: 999999999 */ 388 while (--maxlen && isdigit(*str)) 389 str++; 390 return (*str == '\0'); 391 } 392 393 static const char *var_end(const char *var) 394 { 395 while (*var) 396 if (*var++ == '=') 397 break; 398 return var; 399 } 150 400 151 401 152 402 /* ============ Interrupts / exceptions */ 153 154 /*155 * We enclose jmp_buf in a structure so that we can declare pointers to156 * jump locations. The global variable handler contains the location to157 * jump to when an exception occurs, and the global variable exception158 * contains a code identifying the exception. To implement nested159 * exception handlers, the user should save the value of handler on entry160 * to an inner scope, set handler to point to a jmploc structure for the161 * inner scope, and restore handler on exit from the scope.162 */163 struct jmploc {164 jmp_buf loc;165 };166 static struct jmploc *exception_handler;167 static int exception;168 /* exceptions */169 #define EXINT 0 /* SIGINT received */170 #define EXERROR 1 /* a generic error */171 #define EXSHELLPROC 2 /* execute a shell procedure */172 #define EXEXEC 3 /* command execution failed */173 #define EXEXIT 4 /* exit the shell */174 #define EXSIG 5 /* trapped signal in wait(1) */175 static volatile int suppressint;176 static volatile sig_atomic_t intpending;177 /* do we generate EXSIG events */178 static int exsig;179 /* last pending signal */180 static volatile sig_atomic_t pendingsig;181 182 /*183 * Sigmode records the current value of the signal handlers for the various184 * modes. A value of zero means that the current handler is not known.185 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,186 */187 188 #define S_DFL 1 /* default signal handling (SIG_DFL) */189 #define S_CATCH 2 /* signal is caught */190 #define S_IGN 3 /* signal is ignored (SIG_IGN) */191 #define S_HARD_IGN 4 /* signal is ignored permenantly */192 #define S_RESET 5 /* temporary - to reset a hard ignored sig */193 194 403 /* 195 404 * These macros allow the user to suspend the handling of interrupt signals 196 * over a period of time. This is similar to SIGHOLD to orsigblock, but405 * over a period of time. This is similar to SIGHOLD or to sigblock, but 197 406 * much more efficient and portable. (But hacking the kernel is so much 198 407 * more fun than worrying about efficiency and portability. :-)) 199 408 */ 200 #define INT_OFF \ 201 do { \ 202 suppressint++; \ 203 xbarrier(); \ 204 } while (0) 409 #define INT_OFF do { \ 410 suppress_int++; \ 411 xbarrier(); \ 412 } while (0) 205 413 206 414 /* 207 415 * Called to raise an exception. Since C doesn't include exceptions, we 208 416 * just do a longjmp to the exception handler. The type of exception is 209 * stored in the global variable "exception ".210 */ 211 static void raise_exception(int) ATTRIBUTE_NORETURN;417 * stored in the global variable "exception_type". 418 */ 419 static void raise_exception(int) NORETURN; 212 420 static void 213 421 raise_exception(int e) … … 218 426 #endif 219 427 INT_OFF; 220 exception = e;428 exception_type = e; 221 429 longjmp(exception_handler->loc, 1); 222 430 } 431 #if DEBUG 432 #define raise_exception(e) do { \ 433 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \ 434 raise_exception(e); \ 435 } while (0) 436 #endif 223 437 224 438 /* … … 229 443 * defensive programming.) 230 444 */ 231 static void raise_interrupt(void) ATTRIBUTE_NORETURN;445 static void raise_interrupt(void) NORETURN; 232 446 static void 233 447 raise_interrupt(void) 234 448 { 235 int i; 236 sigset_t mask; 237 238 intpending = 0; 239 /* Signal is not automatically re-enabled after it is raised, 240 * do it ourself */ 241 sigemptyset(&mask); 242 sigprocmask(SIG_SETMASK, &mask, 0); 243 /* pendingsig = 0; - now done in onsig() */ 244 245 i = EXSIG; 449 int ex_type; 450 451 pending_int = 0; 452 /* Signal is not automatically unmasked after it is raised, 453 * do it ourself - unmask all signals */ 454 sigprocmask_allsigs(SIG_UNBLOCK); 455 /* pending_sig = 0; - now done in signal_handler() */ 456 457 ex_type = EXSIG; 246 458 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 247 459 if (!(rootshell && iflag)) { 460 /* Kill ourself with SIGINT */ 248 461 signal(SIGINT, SIG_DFL); 249 462 raise(SIGINT); 250 463 } 251 i= EXINT;252 } 253 raise_exception( i);464 ex_type = EXINT; 465 } 466 raise_exception(ex_type); 254 467 /* NOTREACHED */ 255 468 } 256 257 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 258 static void 469 #if DEBUG 470 #define raise_interrupt() do { \ 471 TRACE(("raising interrupt on line %d\n", __LINE__)); \ 472 raise_interrupt(); \ 473 } while (0) 474 #endif 475 476 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void 259 477 int_on(void) 260 478 { 261 if (--suppressint == 0 && intpending) { 479 xbarrier(); 480 if (--suppress_int == 0 && pending_int) { 262 481 raise_interrupt(); 263 482 } 264 483 } 265 484 #define INT_ON int_on() 266 static void485 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void 267 486 force_int_on(void) 268 487 { 269 suppressint = 0; 270 if (intpending) 488 xbarrier(); 489 suppress_int = 0; 490 if (pending_int) 271 491 raise_interrupt(); 272 492 } 273 493 #define FORCE_INT_ON force_int_on() 274 #else 275 #define INT_ON \ 276 do { \ 277 xbarrier(); \ 278 if (--suppressint == 0 && intpending) \ 279 raise_interrupt(); \ 280 } while (0) 281 #define FORCE_INT_ON \ 282 do { \ 283 xbarrier(); \ 284 suppressint = 0; \ 285 if (intpending) \ 286 raise_interrupt(); \ 287 } while (0) 288 #endif /* ASH_OPTIMIZE_FOR_SIZE */ 289 290 #define SAVE_INT(v) ((v) = suppressint) 291 292 #define RESTORE_INT(v) \ 293 do { \ 294 xbarrier(); \ 295 suppressint = (v); \ 296 if (suppressint == 0 && intpending) \ 297 raise_interrupt(); \ 298 } while (0) 299 300 #define EXSIGON \ 301 do { \ 302 exsig++; \ 303 xbarrier(); \ 304 if (pendingsig) \ 305 raise_exception(EXSIG); \ 306 } while (0) 307 /* EXSIG is turned off by evalbltin(). */ 308 309 /* 310 * Ignore a signal. Only one usage site - in forkchild() 311 */ 312 static void 313 ignoresig(int signo) 314 { 315 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 316 signal(signo, SIG_IGN); 317 } 318 sigmode[signo - 1] = S_HARD_IGN; 319 } 320 321 /* 322 * Signal handler. Only one usage site - in setsignal() 323 */ 324 static void 325 onsig(int signo) 326 { 327 gotsig[signo - 1] = 1; 328 pendingsig = signo; 329 330 if (exsig || (signo == SIGINT && !trap[SIGINT])) { 331 if (!suppressint) { 332 pendingsig = 0; 333 raise_interrupt(); 334 } 335 intpending = 1; 336 } 337 } 494 495 #define SAVE_INT(v) ((v) = suppress_int) 496 497 #define RESTORE_INT(v) do { \ 498 xbarrier(); \ 499 suppress_int = (v); \ 500 if (suppress_int == 0 && pending_int) \ 501 raise_interrupt(); \ 502 } while (0) 338 503 339 504 … … 352 517 { 353 518 INT_OFF; 354 fflush(stdout); 355 fflush(stderr); 356 INT_ON; 357 } 358 359 static void 360 flush_stderr(void) 361 { 362 INT_OFF; 363 fflush(stderr); 519 fflush_all(); 364 520 INT_ON; 365 521 } … … 414 570 { 415 571 outstr(p, stderr); 416 flush_std err();572 flush_stdout_stderr(); 417 573 } 418 574 … … 421 577 422 578 /* control characters in argument strings */ 423 #define CTLESC '\201' /* escape next character */ 424 #define CTLVAR '\202' /* variable defn */ 425 #define CTLENDVAR '\203' 426 #define CTLBACKQ '\204' 579 #define CTL_FIRST CTLESC 580 #define CTLESC ((unsigned char)'\201') /* escape next character */ 581 #define CTLVAR ((unsigned char)'\202') /* variable defn */ 582 #define CTLENDVAR ((unsigned char)'\203') 583 #define CTLBACKQ ((unsigned char)'\204') 427 584 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 428 585 /* CTLBACKQ | CTLQUOTE == '\205' */ 429 #define CTLARI '\206' /* arithmetic expression */ 430 #define CTLENDARI '\207' 431 #define CTLQUOTEMARK '\210' 586 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ 587 #define CTLENDARI ((unsigned char)'\207') 588 #define CTLQUOTEMARK ((unsigned char)'\210') 589 #define CTL_LAST CTLQUOTEMARK 432 590 433 591 /* variable substitution byte (follows CTLVAR) */ … … 437 595 438 596 /* values of VSTYPE field */ 439 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 440 #define VSMINUS 0x2 /* ${var-text} */ 441 #define VSPLUS 0x3 /* ${var+text} */ 442 #define VSQUESTION 0x4 /* ${var?message} */ 443 #define VSASSIGN 0x5 /* ${var=text} */ 444 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 445 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 446 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 447 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 448 #define VSLENGTH 0xa /* ${#var} */ 597 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 598 #define VSMINUS 0x2 /* ${var-text} */ 599 #define VSPLUS 0x3 /* ${var+text} */ 600 #define VSQUESTION 0x4 /* ${var?message} */ 601 #define VSASSIGN 0x5 /* ${var=text} */ 602 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 603 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 604 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 605 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 606 #define VSLENGTH 0xa /* ${#var} */ 607 #if ENABLE_ASH_BASH_COMPAT 608 #define VSSUBSTR 0xc /* ${var:position:length} */ 609 #define VSREPLACE 0xd /* ${var/pattern/replacement} */ 610 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */ 611 #endif 449 612 450 613 static const char dolatstr[] ALIGN1 = { … … 452 615 }; 453 616 454 #define NCMD 0455 #define NPIPE 1456 #define NREDIR 2457 #define NBACKGND 3617 #define NCMD 0 618 #define NPIPE 1 619 #define NREDIR 2 620 #define NBACKGND 3 458 621 #define NSUBSHELL 4 459 #define NAND 5 460 #define NOR 6 461 #define NSEMI 7 462 #define NIF 8 463 #define NWHILE 9 464 #define NUNTIL 10 465 #define NFOR 11 466 #define NCASE 12 467 #define NCLIST 13 468 #define NDEFUN 14 469 #define NARG 15 470 #define NTO 16 471 #define NCLOBBER 17 472 #define NFROM 18 473 #define NFROMTO 19 474 #define NAPPEND 20 475 #define NTOFD 21 476 #define NFROMFD 22 477 #define NHERE 23 478 #define NXHERE 24 479 #define NNOT 25 622 #define NAND 5 623 #define NOR 6 624 #define NSEMI 7 625 #define NIF 8 626 #define NWHILE 9 627 #define NUNTIL 10 628 #define NFOR 11 629 #define NCASE 12 630 #define NCLIST 13 631 #define NDEFUN 14 632 #define NARG 15 633 #define NTO 16 634 #if ENABLE_ASH_BASH_COMPAT 635 #define NTO2 17 636 #endif 637 #define NCLOBBER 18 638 #define NFROM 19 639 #define NFROMTO 20 640 #define NAPPEND 21 641 #define NTOFD 22 642 #define NFROMFD 23 643 #define NHERE 24 644 #define NXHERE 25 645 #define NNOT 26 646 #define N_NUMBER 27 480 647 481 648 union node; 482 649 483 650 struct ncmd { 484 int type;651 smallint type; /* Nxxxx */ 485 652 union node *assign; 486 653 union node *args; … … 489 656 490 657 struct npipe { 491 int type;492 intbackgnd;658 smallint type; 659 smallint pipe_backgnd; 493 660 struct nodelist *cmdlist; 494 661 }; 495 662 496 663 struct nredir { 497 int type;664 smallint type; 498 665 union node *n; 499 666 union node *redirect; … … 501 668 502 669 struct nbinary { 503 int type;670 smallint type; 504 671 union node *ch1; 505 672 union node *ch2; … … 507 674 508 675 struct nif { 509 int type;676 smallint type; 510 677 union node *test; 511 678 union node *ifpart; … … 514 681 515 682 struct nfor { 516 int type;683 smallint type; 517 684 union node *args; 518 685 union node *body; … … 521 688 522 689 struct ncase { 523 int type;690 smallint type; 524 691 union node *expr; 525 692 union node *cases; … … 527 694 528 695 struct nclist { 529 int type;696 smallint type; 530 697 union node *next; 531 698 union node *pattern; … … 534 701 535 702 struct narg { 536 int type;703 smallint type; 537 704 union node *next; 538 705 char *text; … … 540 707 }; 541 708 709 /* nfile and ndup layout must match! 710 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight 711 * that it is actually NTO2 (>&file), and change its type. 712 */ 542 713 struct nfile { 543 int type;714 smallint type; 544 715 union node *next; 545 716 int fd; 717 int _unused_dupfd; 546 718 union node *fname; 547 719 char *expfname; … … 549 721 550 722 struct ndup { 551 int type;723 smallint type; 552 724 union node *next; 553 725 int fd; 554 726 int dupfd; 555 727 union node *vname; 728 char *_unused_expfname; 556 729 }; 557 730 558 731 struct nhere { 559 int type;732 smallint type; 560 733 union node *next; 561 734 int fd; … … 564 737 565 738 struct nnot { 566 int type;739 smallint type; 567 740 union node *com; 568 741 }; 569 742 570 743 union node { 571 int type;744 smallint type; 572 745 struct ncmd ncmd; 573 746 struct npipe npipe; … … 585 758 }; 586 759 760 /* 761 * NODE_EOF is returned by parsecmd when it encounters an end of file. 762 * It must be distinct from NULL. 763 */ 764 #define NODE_EOF ((union node *) -1L) 765 587 766 struct nodelist { 588 767 struct nodelist *next; … … 619 798 if (debug != 1) 620 799 return; 800 if (DEBUG_TIME) 801 fprintf(tracefile, "%u ", (int) time(NULL)); 802 if (DEBUG_PID) 803 fprintf(tracefile, "[%u] ", (int) getpid()); 804 if (DEBUG_SIG) 805 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); 621 806 va_start(va, fmt); 622 807 vfprintf(tracefile, fmt, va); … … 629 814 if (debug != 1) 630 815 return; 816 if (DEBUG_TIME) 817 fprintf(tracefile, "%u ", (int) time(NULL)); 818 if (DEBUG_PID) 819 fprintf(tracefile, "[%u] ", (int) getpid()); 820 if (DEBUG_SIG) 821 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); 631 822 vfprintf(tracefile, fmt, va); 632 823 } … … 650 841 putc('"', tracefile); 651 842 for (p = s; *p; p++) { 652 switch ( *p) {653 case '\n': c = 'n';goto backslash;654 case '\t': c = 't';goto backslash;655 case '\r': c = 'r';goto backslash;656 case ' "': c = '"';goto backslash;657 case '\\': c = '\\';goto backslash;658 case CTLESC: c = 'e';goto backslash;659 case CTLVAR: c = 'v';goto backslash;660 case CTLVAR+CTLQUOTE: 661 case CTLBACKQ: c = 'q';goto backslash;662 case CTLBACKQ+CTLQUOTE: 843 switch ((unsigned char)*p) { 844 case '\n': c = 'n'; goto backslash; 845 case '\t': c = 't'; goto backslash; 846 case '\r': c = 'r'; goto backslash; 847 case '\"': c = '\"'; goto backslash; 848 case '\\': c = '\\'; goto backslash; 849 case CTLESC: c = 'e'; goto backslash; 850 case CTLVAR: c = 'v'; goto backslash; 851 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 852 case CTLBACKQ: c = 'q'; goto backslash; 853 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 663 854 backslash: 664 855 putc('\\', tracefile); … … 670 861 else { 671 862 putc('\\', tracefile); 672 putc( *p >> 6& 03, tracefile);673 putc( *p >> 3& 07, tracefile);863 putc((*p >> 6) & 03, tracefile); 864 putc((*p >> 3) & 07, tracefile); 674 865 putc(*p & 07, tracefile); 675 866 } … … 755 946 char *p; 756 947 struct nodelist *bqlist; 757 intsubtype;948 unsigned char subtype; 758 949 759 950 if (arg->type != NARG) { … … 763 954 bqlist = arg->narg.backquote; 764 955 for (p = arg->narg.text; *p; p++) { 765 switch ( *p) {956 switch ((unsigned char)*p) { 766 957 case CTLESC: 767 putc(*++p, fp); 958 p++; 959 putc(*p, fp); 768 960 break; 769 961 case CTLVAR: … … 774 966 putc('#', fp); 775 967 776 while (*p != '=') 777 putc(*p++, fp); 968 while (*p != '=') { 969 putc(*p, fp); 970 p++; 971 } 778 972 779 973 if (subtype & VSNUL) … … 856 1050 case NCLOBBER: s = ">|"; dftfd = 1; break; 857 1051 case NAPPEND: s = ">>"; dftfd = 1; break; 1052 #if ENABLE_ASH_BASH_COMPAT 1053 case NTO2: 1054 #endif 858 1055 case NTOFD: s = ">&"; dftfd = 1; break; 859 case NFROM: s = "<"; 1056 case NFROM: s = "<"; break; 860 1057 case NFROMFD: s = "<&"; break; 861 1058 case NFROMTO: s = "<>"; break; … … 884 1081 885 1082 indent(ind, pfx, fp); 1083 1084 if (n == NODE_EOF) { 1085 fputs("<EOF>", fp); 1086 return; 1087 } 1088 886 1089 switch (n->type) { 887 1090 case NSEMI: … … 906 1109 case NPIPE: 907 1110 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 908 sh cmd(lp->n, fp);1111 shtree(lp->n, 0, NULL, fp); 909 1112 if (lp->next) 910 1113 fputs(" | ", fp); 911 1114 } 912 if (n->npipe. backgnd)1115 if (n->npipe.pipe_backgnd) 913 1116 fputs(" &", fp); 914 1117 if (ind >= 0) … … 927 1130 { 928 1131 trace_puts("showtree called\n"); 929 shtree(n, 1, NULL, stdout); 930 } 931 932 #define TRACE(param) trace_printf param 933 #define TRACEV(param) trace_vprintf param 934 935 #else 936 937 #define TRACE(param) 938 #define TRACEV(param) 1132 shtree(n, 1, NULL, stderr); 1133 } 939 1134 940 1135 #endif /* DEBUG */ … … 951 1146 }; 952 1147 953 #if ENABLE_ASH_ALIAS954 1148 struct alias; 955 #endif956 1149 957 1150 struct strpush { 958 1151 struct strpush *prev; /* preceding string on stack */ 959 char *prev string;960 int prev nleft;1152 char *prev_string; 1153 int prev_left_in_line; 961 1154 #if ENABLE_ASH_ALIAS 962 1155 struct alias *ap; /* if push was associated with an alias */ … … 968 1161 struct parsefile *prev; /* preceding file on stack */ 969 1162 int linno; /* current line */ 970 int fd;/* file descriptor (or -1 if string) */971 int nleft;/* number of chars left in this line */972 int l left; /* number of chars left in this buffer*/973 char *next c;/* next char in buffer */1163 int pf_fd; /* file descriptor (or -1 if string) */ 1164 int left_in_line; /* number of chars left in this line */ 1165 int left_in_buffer; /* number of chars left in this buffer past the line */ 1166 char *next_to_pgetc; /* next char in buffer */ 974 1167 char *buf; /* input buffer */ 975 1168 struct strpush *strpush; /* for pushing strings at this level */ … … 977 1170 }; 978 1171 979 static struct parsefile basepf; 980 static struct parsefile * parsefile = &basepf; /* current input file */1172 static struct parsefile basepf; /* top level input file */ 1173 static struct parsefile *g_parsefile = &basepf; /* current input file */ 981 1174 static int startlinno; /* line # where last token started */ 982 1175 static char *commandname; /* currently executing command */ 983 1176 static struct strlist *cmdenviron; /* environment for builtin command */ 984 static int exitstatus;/* exit status of last command */1177 static uint8_t exitstatus; /* exit status of last command */ 985 1178 986 1179 … … 994 1187 if (strcmp(arg0, commandname)) 995 1188 fprintf(stderr, "%s: ", commandname); 996 if (!iflag || parsefile->fd)1189 if (!iflag || g_parsefile->pf_fd > 0) 997 1190 fprintf(stderr, "line %d: ", startlinno); 998 1191 } … … 1006 1199 * formatting. It then raises the error exception. 1007 1200 */ 1008 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;1201 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN; 1009 1202 static void 1010 1203 ash_vmsg_and_raise(int cond, const char *msg, va_list ap) … … 1026 1219 } 1027 1220 1028 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;1221 static void ash_msg_and_raise_error(const char *, ...) NORETURN; 1029 1222 static void 1030 1223 ash_msg_and_raise_error(const char *msg, ...) … … 1038 1231 } 1039 1232 1040 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN; 1233 static void raise_error_syntax(const char *) NORETURN; 1234 static void 1235 raise_error_syntax(const char *msg) 1236 { 1237 ash_msg_and_raise_error("syntax error: %s", msg); 1238 /* NOTREACHED */ 1239 } 1240 1241 static void ash_msg_and_raise(int, const char *, ...) NORETURN; 1041 1242 static void 1042 1243 ash_msg_and_raise(int cond, const char *msg, ...) … … 1079 1280 1080 1281 /* ============ Memory allocation */ 1282 1283 #if 0 1284 /* I consider these wrappers nearly useless: 1285 * ok, they return you to nearest exception handler, but 1286 * how much memory do you leak in the process, making 1287 * memory starvation worse? 1288 */ 1289 static void * 1290 ckrealloc(void * p, size_t nbytes) 1291 { 1292 p = realloc(p, nbytes); 1293 if (!p) 1294 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1295 return p; 1296 } 1297 1298 static void * 1299 ckmalloc(size_t nbytes) 1300 { 1301 return ckrealloc(NULL, nbytes); 1302 } 1303 1304 static void * 1305 ckzalloc(size_t nbytes) 1306 { 1307 return memset(ckmalloc(nbytes), 0, nbytes); 1308 } 1309 1310 static char * 1311 ckstrdup(const char *s) 1312 { 1313 char *p = strdup(s); 1314 if (!p) 1315 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1316 return p; 1317 } 1318 #else 1319 /* Using bbox equivalents. They exit if out of memory */ 1320 # define ckrealloc xrealloc 1321 # define ckmalloc xmalloc 1322 # define ckzalloc xzalloc 1323 # define ckstrdup xstrdup 1324 #endif 1081 1325 1082 1326 /* … … 1089 1333 * in some way. The following macro will get this right 1090 1334 * on many machines. */ 1091 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,1335 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1, 1092 1336 /* Minimum size of a block */ 1093 MINSIZE 1337 MINSIZE = SHELL_ALIGN(504), 1094 1338 }; 1095 1339 … … 1106 1350 }; 1107 1351 1108 static struct stack_block stackbase; 1109 static struct stack_block *stackp = &stackbase; 1110 static struct stackmark *markp; 1111 static char *stacknxt = stackbase.space; 1112 static size_t stacknleft = MINSIZE; 1113 static char *sstrend = stackbase.space + MINSIZE; 1114 static int herefd = -1; 1115 1116 #define stackblock() ((void *)stacknxt) 1117 #define stackblocksize() stacknleft 1118 1119 static void * 1120 ckrealloc(void * p, size_t nbytes) 1121 { 1122 p = realloc(p, nbytes); 1123 if (!p) 1124 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1125 return p; 1126 } 1127 1128 static void * 1129 ckmalloc(size_t nbytes) 1130 { 1131 return ckrealloc(NULL, nbytes); 1132 } 1133 1134 /* 1135 * Make a copy of a string in safe storage. 1136 */ 1137 static char * 1138 ckstrdup(const char *s) 1139 { 1140 char *p = strdup(s); 1141 if (!p) 1142 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1143 return p; 1144 } 1352 1353 struct globals_memstack { 1354 struct stack_block *g_stackp; // = &stackbase; 1355 struct stackmark *markp; 1356 char *g_stacknxt; // = stackbase.space; 1357 char *sstrend; // = stackbase.space + MINSIZE; 1358 size_t g_stacknleft; // = MINSIZE; 1359 int herefd; // = -1; 1360 struct stack_block stackbase; 1361 }; 1362 extern struct globals_memstack *const ash_ptr_to_globals_memstack; 1363 #define G_memstack (*ash_ptr_to_globals_memstack) 1364 #define g_stackp (G_memstack.g_stackp ) 1365 #define markp (G_memstack.markp ) 1366 #define g_stacknxt (G_memstack.g_stacknxt ) 1367 #define sstrend (G_memstack.sstrend ) 1368 #define g_stacknleft (G_memstack.g_stacknleft) 1369 #define herefd (G_memstack.herefd ) 1370 #define stackbase (G_memstack.stackbase ) 1371 #define INIT_G_memstack() do { \ 1372 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ 1373 barrier(); \ 1374 g_stackp = &stackbase; \ 1375 g_stacknxt = stackbase.space; \ 1376 g_stacknleft = MINSIZE; \ 1377 sstrend = stackbase.space + MINSIZE; \ 1378 herefd = -1; \ 1379 } while (0) 1380 1381 1382 #define stackblock() ((void *)g_stacknxt) 1383 #define stackblocksize() g_stacknleft 1145 1384 1146 1385 /* … … 1159 1398 1160 1399 aligned = SHELL_ALIGN(nbytes); 1161 if (aligned > stacknleft) {1400 if (aligned > g_stacknleft) { 1162 1401 size_t len; 1163 1402 size_t blocksize; … … 1172 1411 INT_OFF; 1173 1412 sp = ckmalloc(len); 1174 sp->prev = stackp;1175 stacknxt = sp->space;1176 stacknleft = blocksize;1177 sstrend = stacknxt + blocksize;1178 stackp = sp;1413 sp->prev = g_stackp; 1414 g_stacknxt = sp->space; 1415 g_stacknleft = blocksize; 1416 sstrend = g_stacknxt + blocksize; 1417 g_stackp = sp; 1179 1418 INT_ON; 1180 1419 } 1181 p = stacknxt;1182 stacknxt += aligned;1183 stacknleft -= aligned;1420 p = g_stacknxt; 1421 g_stacknxt += aligned; 1422 g_stacknleft -= aligned; 1184 1423 return p; 1424 } 1425 1426 static void * 1427 stzalloc(size_t nbytes) 1428 { 1429 return memset(stalloc(nbytes), 0, nbytes); 1185 1430 } 1186 1431 … … 1189 1434 { 1190 1435 #if DEBUG 1191 if (!p || ( stacknxt < (char *)p) || ((char *)p <stackp->space)) {1192 write( 2, "stunalloc\n", 10);1436 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) { 1437 write(STDERR_FILENO, "stunalloc\n", 10); 1193 1438 abort(); 1194 1439 } 1195 1440 #endif 1196 stacknleft +=stacknxt - (char *)p;1197 stacknxt = p;1441 g_stacknleft += g_stacknxt - (char *)p; 1442 g_stacknxt = p; 1198 1443 } 1199 1444 … … 1211 1456 setstackmark(struct stackmark *mark) 1212 1457 { 1213 mark->stackp = stackp;1214 mark->stacknxt = stacknxt;1215 mark->stacknleft = stacknleft;1458 mark->stackp = g_stackp; 1459 mark->stacknxt = g_stacknxt; 1460 mark->stacknleft = g_stacknleft; 1216 1461 mark->marknext = markp; 1217 1462 markp = mark; … … 1228 1473 INT_OFF; 1229 1474 markp = mark->marknext; 1230 while ( stackp != mark->stackp) {1231 sp = stackp;1232 stackp = sp->prev;1475 while (g_stackp != mark->stackp) { 1476 sp = g_stackp; 1477 g_stackp = sp->prev; 1233 1478 free(sp); 1234 1479 } 1235 stacknxt = mark->stacknxt;1236 stacknleft = mark->stacknleft;1480 g_stacknxt = mark->stacknxt; 1481 g_stacknleft = mark->stacknleft; 1237 1482 sstrend = mark->stacknxt + mark->stacknleft; 1238 1483 INT_ON; … … 1253 1498 size_t newlen; 1254 1499 1255 newlen = stacknleft * 2;1256 if (newlen < stacknleft)1500 newlen = g_stacknleft * 2; 1501 if (newlen < g_stacknleft) 1257 1502 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1258 1503 if (newlen < 128) 1259 1504 newlen += 128; 1260 1505 1261 if ( stacknxt == stackp->space &&stackp != &stackbase) {1506 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) { 1262 1507 struct stack_block *oldstackp; 1263 1508 struct stackmark *xmark; … … 1267 1512 1268 1513 INT_OFF; 1269 oldstackp = stackp;1270 sp = stackp;1514 oldstackp = g_stackp; 1515 sp = g_stackp; 1271 1516 prevstackp = sp->prev; 1272 1517 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 1273 1518 sp = ckrealloc(sp, grosslen); 1274 1519 sp->prev = prevstackp; 1275 stackp = sp;1276 stacknxt = sp->space;1277 stacknleft = newlen;1520 g_stackp = sp; 1521 g_stacknxt = sp->space; 1522 g_stacknleft = newlen; 1278 1523 sstrend = sp->space + newlen; 1279 1524 … … 1284 1529 xmark = markp; 1285 1530 while (xmark != NULL && xmark->stackp == oldstackp) { 1286 xmark->stackp = stackp;1287 xmark->stacknxt = stacknxt;1288 xmark->stacknleft = stacknleft;1531 xmark->stackp = g_stackp; 1532 xmark->stacknxt = g_stacknxt; 1533 xmark->stacknleft = g_stacknleft; 1289 1534 xmark = xmark->marknext; 1290 1535 } 1291 1536 INT_ON; 1292 1537 } else { 1293 char *oldspace = stacknxt;1294 int oldlen =stacknleft;1538 char *oldspace = g_stacknxt; 1539 size_t oldlen = g_stacknleft; 1295 1540 char *p = stalloc(newlen); 1296 1541 1297 1542 /* free the space we just allocated */ 1298 stacknxt = memcpy(p, oldspace, oldlen);1299 stacknleft += newlen;1543 g_stacknxt = memcpy(p, oldspace, oldlen); 1544 g_stacknleft += newlen; 1300 1545 } 1301 1546 } … … 1305 1550 { 1306 1551 len = SHELL_ALIGN(len); 1307 stacknxt += len;1308 stacknleft -= len;1552 g_stacknxt += len; 1553 g_stacknleft -= len; 1309 1554 } 1310 1555 … … 1335 1580 } 1336 1581 growstackblock(); 1337 return stackblock() + len;1582 return (char *)stackblock() + len; 1338 1583 } 1339 1584 … … 1344 1589 makestrspace(size_t newlen, char *p) 1345 1590 { 1346 size_t len = p - stacknxt;1591 size_t len = p - g_stacknxt; 1347 1592 size_t size = stackblocksize(); 1348 1593 … … 1356 1601 growstackblock(); 1357 1602 } 1358 return stackblock() + len;1603 return (char *)stackblock() + len; 1359 1604 } 1360 1605 … … 1363 1608 { 1364 1609 p = makestrspace(n, p); 1365 p = memcpy(p, s, n) + n;1610 p = (char *)memcpy(p, s, n) + n; 1366 1611 return p; 1367 1612 } … … 1384 1629 #define STARTSTACKSTR(p) ((p) = stackblock()) 1385 1630 #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) 1386 #define CHECKSTRSPACE(n, p) \ 1387 do { \ 1388 char *q = (p); \ 1389 size_t l = (n); \ 1390 size_t m = sstrend - q; \ 1391 if (l > m) \ 1392 (p) = makestrspace(l, q); \ 1393 } while (0) 1394 #define USTPUTC(c, p) (*p++ = (c)) 1395 #define STACKSTRNUL(p) \ 1396 do { \ 1397 if ((p) == sstrend) \ 1398 p = growstackstr(); \ 1399 *p = '\0'; \ 1400 } while (0) 1401 #define STUNPUTC(p) (--p) 1402 #define STTOPC(p) (p[-1]) 1403 #define STADJUST(amount, p) (p += (amount)) 1631 #define CHECKSTRSPACE(n, p) do { \ 1632 char *q = (p); \ 1633 size_t l = (n); \ 1634 size_t m = sstrend - q; \ 1635 if (l > m) \ 1636 (p) = makestrspace(l, q); \ 1637 } while (0) 1638 #define USTPUTC(c, p) (*(p)++ = (c)) 1639 #define STACKSTRNUL(p) do { \ 1640 if ((p) == sstrend) \ 1641 (p) = growstackstr(); \ 1642 *(p) = '\0'; \ 1643 } while (0) 1644 #define STUNPUTC(p) (--(p)) 1645 #define STTOPC(p) ((p)[-1]) 1646 #define STADJUST(amount, p) ((p) += (amount)) 1404 1647 1405 1648 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1406 #define ungrabstackstr(s, p) stunalloc( (s))1649 #define ungrabstackstr(s, p) stunalloc(s) 1407 1650 #define stackstrend() ((void *)sstrend) 1408 1651 … … 1418 1661 while (*pfx) { 1419 1662 if (*pfx++ != *string++) 1420 return 0;1663 return NULL; 1421 1664 } 1422 1665 return (char *) string; … … 1444 1687 { 1445 1688 if (!is_number(s)) 1446 ash_msg_and_raise_error( illnum, s);1689 ash_msg_and_raise_error(msg_illnum, s); 1447 1690 return atoi(s); 1448 1691 } … … 1468 1711 1469 1712 *q++ = '\''; 1470 q = memcpy(q, s, len) + len;1713 q = (char *)memcpy(q, s, len) + len; 1471 1714 *q++ = '\''; 1472 1715 s += len; … … 1474 1717 STADJUST(q - p, p); 1475 1718 1476 len = strspn(s, "'"); 1477 if (!len) 1719 if (*s != '\'') 1478 1720 break; 1721 len = 0; 1722 do len++; while (*++s == '\''); 1479 1723 1480 1724 q = p = makestrspace(len + 3, p); 1481 1725 1482 1726 *q++ = '"'; 1483 q = memcpy(q, s, len) + len;1727 q = (char *)memcpy(q, s - len, len) + len; 1484 1728 *q++ = '"'; 1485 s += len;1486 1729 1487 1730 STADJUST(q - p, p); 1488 1731 } while (*s); 1489 1732 1490 USTPUTC( 0, p);1733 USTPUTC('\0', p); 1491 1734 1492 1735 return stackblock(); … … 1501 1744 1502 1745 /* 1503 * XXX - should get rid of. have all builtins use getopt(3). the1504 * library getopt must have the BSD extension static variable "optreset"1505 * otherwise it can't be used within the shell safely.1746 * XXX - should get rid of. Have all builtins use getopt(3). 1747 * The library getopt must have the BSD extension static variable 1748 * "optreset", otherwise it can't be used within the shell safely. 1506 1749 * 1507 * Standard option processing (a la getopt) for builtin routines. The1508 * only argument that is passed to nextopt is the option string; the1509 * other arguments are unnecessary. It return the character, or '\0' on1510 * end of input.1750 * Standard option processing (a la getopt) for builtin routines. 1751 * The only argument that is passed to nextopt is the option string; 1752 * the other arguments are unnecessary. It returns the character, 1753 * or '\0' on end of input. 1511 1754 */ 1512 1755 static int … … 1519 1762 p = optptr; 1520 1763 if (p == NULL || *p == '\0') { 1764 /* We ate entire "-param", take next one */ 1521 1765 p = *argptr; 1522 if (p == NULL || *p != '-' || *++p == '\0') 1766 if (p == NULL) 1767 return '\0'; 1768 if (*p != '-') 1769 return '\0'; 1770 if (*++p == '\0') /* just "-" ? */ 1523 1771 return '\0'; 1524 1772 argptr++; 1525 if (LONE_DASH(p)) /* check for "--"*/1773 if (LONE_DASH(p)) /* "--" ? */ 1526 1774 return '\0'; 1527 } 1775 /* p => next "-param" */ 1776 } 1777 /* p => some option char in the middle of a "-param" */ 1528 1778 c = *p++; 1529 for (q = optstring; *q != c; 1779 for (q = optstring; *q != c;) { 1530 1780 if (*q == '\0') 1531 1781 ash_msg_and_raise_error("illegal option -%c", c); … … 1534 1784 } 1535 1785 if (*++q == ':') { 1536 if (*p == '\0' && (p = *argptr++) == NULL) 1537 ash_msg_and_raise_error("no arg for -%c option", c); 1786 if (*p == '\0') { 1787 p = *argptr++; 1788 if (p == NULL) 1789 ash_msg_and_raise_error("no arg for -%c option", c); 1790 } 1538 1791 optionarg = p; 1539 1792 p = NULL; … … 1544 1797 1545 1798 1546 /* ============ Math support definitions */1547 1548 #if ENABLE_ASH_MATH_SUPPORT_641549 typedef int64_t arith_t;1550 #define arith_t_type long long1551 #else1552 typedef long arith_t;1553 #define arith_t_type long1554 #endif1555 1556 #if ENABLE_ASH_MATH_SUPPORT1557 static arith_t dash_arith(const char *);1558 static arith_t arith(const char *expr, int *perrcode);1559 #endif1560 1561 #if ENABLE_ASH_RANDOM_SUPPORT1562 static unsigned long rseed;1563 #ifndef DYNAMIC_VAR1564 #define DYNAMIC_VAR1565 #endif1566 #endif1567 1568 1569 1799 /* ============ Shell variables */ 1800 1801 /* 1802 * The parsefile structure pointed to by the global variable parsefile 1803 * contains information about the current file being read. 1804 */ 1805 struct shparam { 1806 int nparam; /* # of positional parameters (without $0) */ 1807 #if ENABLE_ASH_GETOPTS 1808 int optind; /* next parameter to be processed by getopts */ 1809 int optoff; /* used by getopts */ 1810 #endif 1811 unsigned char malloced; /* if parameter list dynamically allocated */ 1812 char **p; /* parameter list */ 1813 }; 1814 1815 /* 1816 * Free the list of positional parameters. 1817 */ 1818 static void 1819 freeparam(volatile struct shparam *param) 1820 { 1821 if (param->malloced) { 1822 char **ap, **ap1; 1823 ap = ap1 = param->p; 1824 while (*ap) 1825 free(*ap++); 1826 free(ap1); 1827 } 1828 } 1829 1830 #if ENABLE_ASH_GETOPTS 1831 static void FAST_FUNC getoptsreset(const char *value); 1832 #endif 1833 1834 struct var { 1835 struct var *next; /* next entry in hash list */ 1836 int flags; /* flags are defined above */ 1837 const char *var_text; /* name=value */ 1838 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */ 1839 /* the variable gets set/unset */ 1840 }; 1841 1842 struct localvar { 1843 struct localvar *next; /* next local variable in list */ 1844 struct var *vp; /* the variable that was made local */ 1845 int flags; /* saved flags */ 1846 const char *text; /* saved text */ 1847 }; 1570 1848 1571 1849 /* flags */ … … 1579 1857 #define VNOSET 0x80 /* do not set variable - just readonly test */ 1580 1858 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1581 #if def DYNAMIC_VAR1859 #if ENABLE_ASH_RANDOM_SUPPORT 1582 1860 # define VDYNAMIC 0x200 /* dynamic variable */ 1583 1861 #else … … 1585 1863 #endif 1586 1864 1587 #ifdef IFS_BROKEN 1588 static const char defifsvar[] ALIGN1 = "IFS= \t\n"; 1589 #define defifs (defifsvar + 4) 1590 #else 1591 static const char defifs[] ALIGN1 = " \t\n"; 1592 #endif 1593 1594 struct shparam { 1595 int nparam; /* # of positional parameters (without $0) */ 1596 unsigned char malloc; /* if parameter list dynamically allocated */ 1597 char **p; /* parameter list */ 1598 #if ENABLE_ASH_GETOPTS 1599 int optind; /* next parameter to be processed by getopts */ 1600 int optoff; /* used by getopts */ 1601 #endif 1602 }; 1603 1604 static struct shparam shellparam; /* $@ current positional parameters */ 1605 1606 /* 1607 * Free the list of positional parameters. 1608 */ 1609 static void 1610 freeparam(volatile struct shparam *param) 1611 { 1612 char **ap; 1613 1614 if (param->malloc) { 1615 for (ap = param->p; *ap; ap++) 1616 free(*ap); 1617 free(param->p); 1618 } 1619 } 1620 1621 #if ENABLE_ASH_GETOPTS 1622 static void 1623 getoptsreset(const char *value) 1624 { 1625 shellparam.optind = number(value); 1626 shellparam.optoff = -1; 1627 } 1628 #endif 1629 1630 struct var { 1631 struct var *next; /* next entry in hash list */ 1632 int flags; /* flags are defined above */ 1633 const char *text; /* name=value */ 1634 void (*func)(const char *); /* function to be called when */ 1635 /* the variable gets set/unset */ 1636 }; 1637 1638 struct localvar { 1639 struct localvar *next; /* next local variable in list */ 1640 struct var *vp; /* the variable that was made local */ 1641 int flags; /* saved flags */ 1642 const char *text; /* saved text */ 1643 }; 1644 1645 /* Forward decls for varinit[] */ 1865 1866 /* Need to be before varinit_data[] */ 1646 1867 #if ENABLE_LOCALE_SUPPORT 1647 static void 1868 static void FAST_FUNC 1648 1869 change_lc_all(const char *value) 1649 1870 { … … 1651 1872 setlocale(LC_ALL, value); 1652 1873 } 1653 static void 1874 static void FAST_FUNC 1654 1875 change_lc_ctype(const char *value) 1655 1876 { … … 1660 1881 #if ENABLE_ASH_MAIL 1661 1882 static void chkmail(void); 1662 static void changemail(const char *) ;1663 #endif 1664 static void changepath(const char *) ;1883 static void changemail(const char *) FAST_FUNC; 1884 #endif 1885 static void changepath(const char *) FAST_FUNC; 1665 1886 #if ENABLE_ASH_RANDOM_SUPPORT 1666 static void change_random(const char *); 1667 #endif 1668 1669 static struct var varinit[] = { 1670 #ifdef IFS_BROKEN 1671 { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, 1887 static void change_random(const char *) FAST_FUNC; 1888 #endif 1889 1890 static const struct { 1891 int flags; 1892 const char *var_text; 1893 void (*var_func)(const char *) FAST_FUNC; 1894 } varinit_data[] = { 1895 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, 1896 #if ENABLE_ASH_MAIL 1897 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, 1898 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail }, 1899 #endif 1900 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath }, 1901 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL }, 1902 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL }, 1903 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL }, 1904 #if ENABLE_ASH_GETOPTS 1905 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset }, 1906 #endif 1907 #if ENABLE_ASH_RANDOM_SUPPORT 1908 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, 1909 #endif 1910 #if ENABLE_LOCALE_SUPPORT 1911 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all }, 1912 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype }, 1913 #endif 1914 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 1915 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, 1916 #endif 1917 }; 1918 1919 struct redirtab; 1920 1921 struct globals_var { 1922 struct shparam shellparam; /* $@ current positional parameters */ 1923 struct redirtab *redirlist; 1924 int g_nullredirs; 1925 int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1926 struct var *vartab[VTABSIZE]; 1927 struct var varinit[ARRAY_SIZE(varinit_data)]; 1928 }; 1929 extern struct globals_var *const ash_ptr_to_globals_var; 1930 #define G_var (*ash_ptr_to_globals_var) 1931 #define shellparam (G_var.shellparam ) 1932 //#define redirlist (G_var.redirlist ) 1933 #define g_nullredirs (G_var.g_nullredirs ) 1934 #define preverrout_fd (G_var.preverrout_fd) 1935 #define vartab (G_var.vartab ) 1936 #define varinit (G_var.varinit ) 1937 #define INIT_G_var() do { \ 1938 unsigned i; \ 1939 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ 1940 barrier(); \ 1941 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ 1942 varinit[i].flags = varinit_data[i].flags; \ 1943 varinit[i].var_text = varinit_data[i].var_text; \ 1944 varinit[i].var_func = varinit_data[i].var_func; \ 1945 } \ 1946 } while (0) 1947 1948 #define vifs varinit[0] 1949 #if ENABLE_ASH_MAIL 1950 # define vmail (&vifs)[1] 1951 # define vmpath (&vmail)[1] 1952 # define vpath (&vmpath)[1] 1672 1953 #else 1673 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, 1674 #endif 1675 #if ENABLE_ASH_MAIL 1676 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1677 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1678 #endif 1679 { NULL, VSTRFIXED|VTEXTFIXED, bb_PATH_root_path, changepath }, 1680 { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, 1681 { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, 1682 { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, 1954 # define vpath (&vifs)[1] 1955 #endif 1956 #define vps1 (&vpath)[1] 1957 #define vps2 (&vps1)[1] 1958 #define vps4 (&vps2)[1] 1683 1959 #if ENABLE_ASH_GETOPTS 1684 { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1685 #endif 1686 #if ENABLE_ASH_RANDOM_SUPPORT 1687 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1688 #endif 1689 #if ENABLE_LOCALE_SUPPORT 1690 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1691 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1692 #endif 1693 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 1694 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1695 #endif 1696 }; 1697 1698 #define vifs varinit[0] 1699 #if ENABLE_ASH_MAIL 1700 #define vmail (&vifs)[1] 1701 #define vmpath (&vmail)[1] 1960 # define voptind (&vps4)[1] 1961 # if ENABLE_ASH_RANDOM_SUPPORT 1962 # define vrandom (&voptind)[1] 1963 # endif 1702 1964 #else 1703 #define vmpath vifs 1704 #endif 1705 #define vpath (&vmpath)[1] 1706 #define vps1 (&vpath)[1] 1707 #define vps2 (&vps1)[1] 1708 #define vps4 (&vps2)[1] 1709 #define voptind (&vps4)[1] 1710 #if ENABLE_ASH_GETOPTS 1711 #define vrandom (&voptind)[1] 1712 #else 1713 #define vrandom (&vps4)[1] 1965 # if ENABLE_ASH_RANDOM_SUPPORT 1966 # define vrandom (&vps4)[1] 1967 # endif 1714 1968 #endif 1715 1969 … … 1719 1973 * for unset variables. 1720 1974 */ 1721 #define ifsval() (vifs. text + 4)1975 #define ifsval() (vifs.var_text + 4) 1722 1976 #define ifsset() ((vifs.flags & VUNSET) == 0) 1723 #define mailval() (vmail.text + 5) 1724 #define mpathval() (vmpath.text + 9) 1725 #define pathval() (vpath.text + 5) 1726 #define ps1val() (vps1.text + 4) 1727 #define ps2val() (vps2.text + 4) 1728 #define ps4val() (vps4.text + 4) 1729 #define optindval() (voptind.text + 7) 1730 1731 #define mpathset() ((vmpath.flags & VUNSET) == 0) 1732 1733 /* 1734 * The parsefile structure pointed to by the global variable parsefile 1735 * contains information about the current file being read. 1736 */ 1737 struct redirtab { 1738 struct redirtab *next; 1739 int renamed[10]; 1740 int nullredirs; 1741 }; 1742 1743 static struct redirtab *redirlist; 1744 static int nullredirs; 1745 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1746 1747 #define VTABSIZE 39 1748 1749 static struct var *vartab[VTABSIZE]; 1750 1977 #if ENABLE_ASH_MAIL 1978 # define mailval() (vmail.var_text + 5) 1979 # define mpathval() (vmpath.var_text + 9) 1980 # define mpathset() ((vmpath.flags & VUNSET) == 0) 1981 #endif 1982 #define pathval() (vpath.var_text + 5) 1983 #define ps1val() (vps1.var_text + 4) 1984 #define ps2val() (vps2.var_text + 4) 1985 #define ps4val() (vps4.var_text + 4) 1986 #if ENABLE_ASH_GETOPTS 1987 # define optindval() (voptind.var_text + 7) 1988 #endif 1989 1990 #if ENABLE_ASH_GETOPTS 1991 static void FAST_FUNC 1992 getoptsreset(const char *value) 1993 { 1994 shellparam.optind = number(value); 1995 shellparam.optoff = -1; 1996 } 1997 #endif 1998 1999 /* math.h has these, otherwise define our private copies */ 2000 #if !ENABLE_SH_MATH_SUPPORT 1751 2001 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1752 2002 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 1753 1754 /* 1755 * Return of a legal variable name (a letter or underscore followed by zero or 1756 * more letters, underscores, and digits). 1757 */ 1758 static char * 2003 /* 2004 * Return the pointer to the first char which is not part of a legal variable name 2005 * (a letter or underscore followed by letters, underscores, and digits). 2006 */ 2007 static const char* 1759 2008 endofname(const char *name) 1760 2009 { 1761 char *p; 1762 1763 p = (char *) name; 1764 if (!is_name(*p)) 1765 return p; 1766 while (*++p) { 1767 if (!is_in_name(*p)) 2010 if (!is_name(*name)) 2011 return name; 2012 while (*++name) { 2013 if (!is_in_name(*name)) 1768 2014 break; 1769 2015 } 1770 return p; 1771 } 2016 return name; 2017 } 2018 #endif 1772 2019 1773 2020 /* … … 1795 2042 } 1796 2043 1797 static int1798 varequal(const char *a, const char *b)1799 {1800 return !varcmp(a, b);1801 }1802 1803 2044 /* 1804 2045 * Find the appropriate entry in the hash table from the name. … … 1835 2076 */ 1836 2077 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT 1837 vps1. text = "PS1=\\w \\$ ";2078 vps1.var_text = "PS1=\\w \\$ "; 1838 2079 #else 1839 2080 if (!geteuid()) 1840 vps1. text = "PS1=# ";2081 vps1.var_text = "PS1=# "; 1841 2082 #endif 1842 2083 vp = varinit; 1843 2084 end = vp + ARRAY_SIZE(varinit); 1844 2085 do { 1845 vpp = hashvar(vp-> text);2086 vpp = hashvar(vp->var_text); 1846 2087 vp->next = *vpp; 1847 2088 *vpp = vp; … … 1853 2094 { 1854 2095 for (; *vpp; vpp = &(*vpp)->next) { 1855 if (var equal((*vpp)->text, name)) {2096 if (varcmp((*vpp)->var_text, name) == 0) { 1856 2097 break; 1857 2098 } … … 1863 2104 * Find the value of a variable. Returns NULL if not set. 1864 2105 */ 1865 static c har *2106 static const char* FAST_FUNC 1866 2107 lookupvar(const char *name) 1867 2108 { … … 1870 2111 v = *findvar(hashvar(name), name); 1871 2112 if (v) { 1872 #if def DYNAMIC_VAR2113 #if ENABLE_ASH_RANDOM_SUPPORT 1873 2114 /* 1874 2115 * Dynamic variables are implemented roughly the same way they are … … 1877 2118 * lookup will no longer happen at that point. -- PFM. 1878 2119 */ 1879 if ( (v->flags & VDYNAMIC))1880 (*v->func)(NULL);2120 if (v->flags & VDYNAMIC) 2121 v->var_func(NULL); 1881 2122 #endif 1882 2123 if (!(v->flags & VUNSET)) 1883 return strchrnul(v->text, '=') + 1;2124 return var_end(v->var_text); 1884 2125 } 1885 2126 return NULL; … … 1889 2130 * Search the environment of a builtin command. 1890 2131 */ 1891 static c har *2132 static const char * 1892 2133 bltinlookup(const char *name) 1893 2134 { … … 1895 2136 1896 2137 for (sp = cmdenviron; sp; sp = sp->next) { 1897 if (var equal(sp->text, name))1898 return strchrnul(sp->text, '=') + 1;2138 if (varcmp(sp->text, name) == 0) 2139 return var_end(sp->text); 1899 2140 } 1900 2141 return lookupvar(name); … … 1922 2163 if (flags & VNOSAVE) 1923 2164 free(s); 1924 n = vp-> text;2165 n = vp->var_text; 1925 2166 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); 1926 2167 } … … 1929 2170 return; 1930 2171 1931 if (vp-> func && (flags & VNOFUNC) == 0)1932 (*vp->func)(strchrnul(s, '=') + 1);1933 1934 if ( (vp->flags & (VTEXTFIXED|VSTACK)) == 0)1935 free((char*)vp-> text);2172 if (vp->var_func && !(flags & VNOFUNC)) 2173 vp->var_func(var_end(s)); 2174 2175 if (!(vp->flags & (VTEXTFIXED|VSTACK))) 2176 free((char*)vp->var_text); 1936 2177 1937 2178 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 1938 2179 } else { 2180 /* variable s is not found */ 1939 2181 if (flags & VNOSET) 1940 2182 return; 1941 /* not found */ 1942 vp = ckmalloc(sizeof(*vp)); 2183 vp = ckzalloc(sizeof(*vp)); 1943 2184 vp->next = *vpp; 1944 vp->func = NULL;2185 /*vp->func = NULL; - ckzalloc did it */ 1945 2186 *vpp = vp; 1946 2187 } 1947 2188 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 1948 2189 s = ckstrdup(s); 1949 vp-> text = s;2190 vp->var_text = s; 1950 2191 vp->flags = flags; 1951 2192 } … … 1958 2199 setvar(const char *name, const char *val, int flags) 1959 2200 { 1960 char *p, *q; 2201 const char *q; 2202 char *p; 2203 char *nameeq; 1961 2204 size_t namelen; 1962 char *nameeq;1963 2205 size_t vallen; 1964 2206 … … 1974 2216 vallen = strlen(val); 1975 2217 } 2218 1976 2219 INT_OFF; 1977 2220 nameeq = ckmalloc(namelen + vallen + 2); … … 1984 2227 setvareq(nameeq, flags | VNOSAVE); 1985 2228 INT_ON; 2229 } 2230 2231 static void FAST_FUNC 2232 setvar2(const char *name, const char *val) 2233 { 2234 setvar(name, val, 0); 1986 2235 } 1987 2236 … … 2031 2280 if (flags & VREADONLY) 2032 2281 goto out; 2033 #if def DYNAMIC_VAR2282 #if ENABLE_ASH_RANDOM_SUPPORT 2034 2283 vp->flags &= ~VDYNAMIC; 2035 2284 #endif … … 2039 2288 INT_OFF; 2040 2289 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 2041 free((char*)vp-> text);2290 free((char*)vp->var_text); 2042 2291 *vpp = vp->next; 2043 2292 free(vp); … … 2091 2340 if (ep == stackstrend()) 2092 2341 ep = growstackstr(); 2093 *ep++ = (char *) vp->text;2342 *ep++ = (char*)vp->var_text; 2094 2343 } 2095 2344 } … … 2107 2356 * 2108 2357 * The variable path (passed by reference) should be set to the start 2109 * of the path before the first call; pa dvance will update2110 * this value as it proceeds. Successive calls to pa dvance will return2358 * of the path before the first call; path_advance will update 2359 * this value as it proceeds. Successive calls to path_advance will return 2111 2360 * the possible path expansions in sequence. If an option (indicated by 2112 2361 * a percent sign) appears in the path entry then the global variable … … 2114 2363 * NULL. 2115 2364 */ 2116 static const char *pathopt; /* set by pa dvance */2365 static const char *pathopt; /* set by path_advance */ 2117 2366 2118 2367 static char * 2119 pa dvance(const char **path, const char *name)2368 path_advance(const char **path, const char *name) 2120 2369 { 2121 2370 const char *p; … … 2127 2376 return NULL; 2128 2377 start = *path; 2129 for (p = start; *p && *p != ':' && *p != '%'; p++); 2378 for (p = start; *p && *p != ':' && *p != '%'; p++) 2379 continue; 2130 2380 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2131 2381 while (stackblocksize() < len) … … 2141 2391 if (*p == '%') { 2142 2392 pathopt = ++p; 2143 while (*p && *p != ':') p++; 2393 while (*p && *p != ':') 2394 p++; 2144 2395 } 2145 2396 if (*p == ':') … … 2153 2404 /* ============ Prompt */ 2154 2405 2155 static int doprompt; /* if set, prompt the user */2156 static int needprompt; /* true if interactive and at start of line */2406 static smallint doprompt; /* if set, prompt the user */ 2407 static smallint needprompt; /* true if interactive and at start of line */ 2157 2408 2158 2409 #if ENABLE_FEATURE_EDITING … … 2185 2436 2186 2437 static void 2187 setprompt (int whichprompt)2438 setprompt_if(smallint do_set, int whichprompt) 2188 2439 { 2189 2440 const char *prompt; 2190 #if ENABLE_ASH_EXPAND_PRMT 2191 struct stackmark smark; 2192 #endif 2441 IF_ASH_EXPAND_PRMT(struct stackmark smark;) 2442 2443 if (!do_set) 2444 return; 2193 2445 2194 2446 needprompt = 0; … … 2220 2472 #define CD_PRINT 2 2221 2473 2222 static int docd(const char *, int);2223 2224 static char *curdir = nullstr; /* current working directory */2225 static char *physdir = nullstr; /* physical working directory */2226 2227 2474 static int 2228 2475 cdopt(void) … … 2232 2479 2233 2480 j = 'L'; 2234 while ((i = nextopt("LP")) ) {2481 while ((i = nextopt("LP")) != '\0') { 2235 2482 if (i != j) { 2236 2483 flags ^= CD_PHYSICAL; … … 2262 2509 } 2263 2510 new = makestrspace(strlen(dir) + 2, new); 2264 lim = stackblock() + 1;2511 lim = (char *)stackblock() + 1; 2265 2512 if (*dir != '/') { 2266 2513 if (new[-1] != '/') … … 2311 2558 getpwd(void) 2312 2559 { 2313 char *dir = getcwd( 0, 0);2560 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */ 2314 2561 return dir ? dir : nullstr; 2315 2562 } … … 2355 2602 docd(const char *dest, int flags) 2356 2603 { 2357 const char *dir = 0;2604 const char *dir = NULL; 2358 2605 int err; 2359 2606 … … 2376 2623 } 2377 2624 2378 static int 2379 cdcmd(int argc , char **argv)2625 static int FAST_FUNC 2626 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 2380 2627 { 2381 2628 const char *dest; … … 2389 2636 dest = *argptr; 2390 2637 if (!dest) 2391 dest = bltinlookup( homestr);2638 dest = bltinlookup("HOME"); 2392 2639 else if (LONE_DASH(dest)) { 2393 2640 dest = bltinlookup("OLDPWD"); … … 2422 2669 do { 2423 2670 c = *path; 2424 p = pa dvance(&path, dest);2671 p = path_advance(&path, dest); 2425 2672 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2426 2673 if (c && c != ':') … … 2436 2683 out: 2437 2684 if (flags & CD_PRINT) 2438 out1fmt( snlfmt, curdir);2685 out1fmt("%s\n", curdir); 2439 2686 return 0; 2440 2687 } 2441 2688 2442 static int 2443 pwdcmd(int argc , char **argv)2689 static int FAST_FUNC 2690 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 2444 2691 { 2445 2692 int flags; … … 2452 2699 dir = physdir; 2453 2700 } 2454 out1fmt( snlfmt, dir);2701 out1fmt("%s\n", dir); 2455 2702 return 0; 2456 2703 } … … 2459 2706 /* ============ ... */ 2460 2707 2461 #define IBUFSIZ (BUFSIZ + 1) 2462 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */2708 2709 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) 2463 2710 2464 2711 /* Syntax classes */ 2465 #define CWORD 0/* character is nothing special */2466 #define CNL 1/* newline character */2467 #define CBACK 2/* a backslash character */2468 #define CSQUOTE 3/* single quote */2469 #define CDQUOTE 4/* double quote */2712 #define CWORD 0 /* character is nothing special */ 2713 #define CNL 1 /* newline character */ 2714 #define CBACK 2 /* a backslash character */ 2715 #define CSQUOTE 3 /* single quote */ 2716 #define CDQUOTE 4 /* double quote */ 2470 2717 #define CENDQUOTE 5 /* a terminating quote */ 2471 #define CBQUOTE 6/* backwards single quote */2472 #define CVAR 7/* a dollar sign */2473 #define CENDVAR 8/* a '}' character */2474 #define CLP 9/* a left paren in arithmetic */2475 #define CRP 10/* a right paren in arithmetic */2718 #define CBQUOTE 6 /* backwards single quote */ 2719 #define CVAR 7 /* a dollar sign */ 2720 #define CENDVAR 8 /* a '}' character */ 2721 #define CLP 9 /* a left paren in arithmetic */ 2722 #define CRP 10 /* a right paren in arithmetic */ 2476 2723 #define CENDFILE 11 /* end of file */ 2477 #define CCTL 12 /* like CWORD, except it must be escaped */ 2478 #define CSPCL 13 /* these terminate a word */ 2479 #define CIGN 14 /* character should be ignored */ 2480 2724 #define CCTL 12 /* like CWORD, except it must be escaped */ 2725 #define CSPCL 13 /* these terminate a word */ 2726 #define CIGN 14 /* character should be ignored */ 2727 2728 #define PEOF 256 2481 2729 #if ENABLE_ASH_ALIAS 2482 #define SYNBASE 130 2483 #define PEOF -130 2484 #define PEOA -129 2485 #define PEOA_OR_PEOF PEOA 2730 # define PEOA 257 2731 #endif 2732 2733 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE 2734 2735 #if ENABLE_SH_MATH_SUPPORT 2736 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12)) 2486 2737 #else 2487 #define SYNBASE 129 2488 #define PEOF -129 2489 #define PEOA_OR_PEOF PEOF 2490 #endif 2491 2492 /* number syntax index */ 2738 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) 2739 #endif 2740 static const uint16_t S_I_T[] = { 2741 #if ENABLE_ASH_ALIAS 2742 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */ 2743 #endif 2744 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */ 2745 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */ 2746 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */ 2747 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */ 2748 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */ 2749 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */ 2750 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */ 2751 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */ 2752 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */ 2753 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */ 2754 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */ 2755 #if !USE_SIT_FUNCTION 2756 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */ 2757 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */ 2758 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */ 2759 #endif 2760 #undef SIT_ITEM 2761 }; 2762 /* Constants below must match table above */ 2763 enum { 2764 #if ENABLE_ASH_ALIAS 2765 CSPCL_CIGN_CIGN_CIGN , /* 0 */ 2766 #endif 2767 CSPCL_CWORD_CWORD_CWORD , /* 1 */ 2768 CNL_CNL_CNL_CNL , /* 2 */ 2769 CWORD_CCTL_CCTL_CWORD , /* 3 */ 2770 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */ 2771 CVAR_CVAR_CWORD_CVAR , /* 5 */ 2772 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */ 2773 CSPCL_CWORD_CWORD_CLP , /* 7 */ 2774 CSPCL_CWORD_CWORD_CRP , /* 8 */ 2775 CBACK_CBACK_CCTL_CBACK , /* 9 */ 2776 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */ 2777 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */ 2778 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */ 2779 CWORD_CWORD_CWORD_CWORD , /* 13 */ 2780 CCTL_CCTL_CCTL_CCTL , /* 14 */ 2781 }; 2782 2783 /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF, 2784 * caller must ensure proper cast on it if c is *char_ptr! 2785 */ 2786 /* Values for syntax param */ 2493 2787 #define BASESYNTAX 0 /* not in quotes */ 2494 2788 #define DQSYNTAX 1 /* in double quotes */ 2495 2789 #define SQSYNTAX 2 /* in single quotes */ 2496 2790 #define ARISYNTAX 3 /* in arithmetic */ 2497 2498 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 2499 #define USE_SIT_FUNCTION 2500 #endif 2501 2502 #if ENABLE_ASH_MATH_SUPPORT 2503 static const char S_I_T[][4] = { 2504 #if ENABLE_ASH_ALIAS 2505 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ 2506 #endif 2507 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */ 2508 { CNL, CNL, CNL, CNL }, /* 2, \n */ 2509 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */ 2510 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */ 2511 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */ 2512 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */ 2513 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */ 2514 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */ 2515 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */ 2516 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */ 2517 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */ 2518 #ifndef USE_SIT_FUNCTION 2519 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2520 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2521 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 2522 #endif 2523 }; 2524 #else 2525 static const char S_I_T[][3] = { 2526 #if ENABLE_ASH_ALIAS 2527 { CSPCL, CIGN, CIGN }, /* 0, PEOA */ 2528 #endif 2529 { CSPCL, CWORD, CWORD }, /* 1, ' ' */ 2530 { CNL, CNL, CNL }, /* 2, \n */ 2531 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */ 2532 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */ 2533 { CVAR, CVAR, CWORD }, /* 5, $ */ 2534 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */ 2535 { CSPCL, CWORD, CWORD }, /* 7, ( */ 2536 { CSPCL, CWORD, CWORD }, /* 8, ) */ 2537 { CBACK, CBACK, CCTL }, /* 9, \ */ 2538 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */ 2539 { CENDVAR, CENDVAR, CWORD }, /* 11, } */ 2540 #ifndef USE_SIT_FUNCTION 2541 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2542 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2543 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 2544 #endif 2545 }; 2546 #endif /* ASH_MATH_SUPPORT */ 2547 2548 #ifdef USE_SIT_FUNCTION 2791 #define PSSYNTAX 4 /* prompt. never passed to SIT() */ 2792 2793 #if USE_SIT_FUNCTION 2549 2794 2550 2795 static int … … 2552 2797 { 2553 2798 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 2554 # if ENABLE_ASH_ALIAS2555 static const charsyntax_index_table[] ALIGN1 = {2799 # if ENABLE_ASH_ALIAS 2800 static const uint8_t syntax_index_table[] ALIGN1 = { 2556 2801 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 2557 2802 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ … … 2559 2804 11, 3 /* "}~" */ 2560 2805 }; 2561 # else2562 static const charsyntax_index_table[] ALIGN1 = {2806 # else 2807 static const uint8_t syntax_index_table[] ALIGN1 = { 2563 2808 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 2564 2809 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ … … 2566 2811 10, 2 /* "}~" */ 2567 2812 }; 2568 # endif2813 # endif 2569 2814 const char *s; 2570 2815 int indx; 2571 2816 2572 if (c == PEOF) /* 2^8+2 */2817 if (c == PEOF) 2573 2818 return CENDFILE; 2574 # if ENABLE_ASH_ALIAS2575 if (c == PEOA) /* 2^8+1 */2819 # if ENABLE_ASH_ALIAS 2820 if (c == PEOA) 2576 2821 indx = 0; 2577 2822 else 2578 #endif 2579 #define U_C(c) ((unsigned char)(c)) 2580 2581 if ((unsigned char)c >= (unsigned char)(CTLESC) 2582 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) 2583 ) { 2584 return CCTL; 2585 } else { 2586 s = strchr(spec_symbls, c); 2587 if (s == NULL || *s == '\0') 2823 # endif 2824 { 2825 /* Cast is purely for paranoia here, 2826 * just in case someone passed signed char to us */ 2827 if ((unsigned char)c >= CTL_FIRST 2828 && (unsigned char)c <= CTL_LAST 2829 ) { 2830 return CCTL; 2831 } 2832 s = strchrnul(spec_symbls, c); 2833 if (*s == '\0') 2588 2834 return CWORD; 2589 indx = syntax_index_table[ (s - spec_symbls)];2590 } 2591 return S_I_T[indx][syntax];2835 indx = syntax_index_table[s - spec_symbls]; 2836 } 2837 return (S_I_T[indx] >> (syntax*4)) & 0xf; 2592 2838 } 2593 2839 2594 2840 #else /* !USE_SIT_FUNCTION */ 2595 2841 2596 #if ENABLE_ASH_ALIAS 2597 #define CSPCL_CIGN_CIGN_CIGN 0 2598 #define CSPCL_CWORD_CWORD_CWORD 1 2599 #define CNL_CNL_CNL_CNL 2 2600 #define CWORD_CCTL_CCTL_CWORD 3 2601 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 2602 #define CVAR_CVAR_CWORD_CVAR 5 2603 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 2604 #define CSPCL_CWORD_CWORD_CLP 7 2605 #define CSPCL_CWORD_CWORD_CRP 8 2606 #define CBACK_CBACK_CCTL_CBACK 9 2607 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 2608 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11 2609 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 2610 #define CWORD_CWORD_CWORD_CWORD 13 2611 #define CCTL_CCTL_CCTL_CCTL 14 2612 #else 2613 #define CSPCL_CWORD_CWORD_CWORD 0 2614 #define CNL_CNL_CNL_CNL 1 2615 #define CWORD_CCTL_CCTL_CWORD 2 2616 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3 2617 #define CVAR_CVAR_CWORD_CVAR 4 2618 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5 2619 #define CSPCL_CWORD_CWORD_CLP 6 2620 #define CSPCL_CWORD_CWORD_CRP 7 2621 #define CBACK_CBACK_CCTL_CBACK 8 2622 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9 2623 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10 2624 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11 2625 #define CWORD_CWORD_CWORD_CWORD 12 2626 #define CCTL_CCTL_CCTL_CCTL 13 2627 #endif 2628 2629 static const char syntax_index_table[258] = { 2842 static const uint8_t syntax_index_table[] = { 2630 2843 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 2631 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,2632 #if ENABLE_ASH_ALIAS 2633 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,2634 #endif 2635 /* 2 -128 0x80*/ CWORD_CWORD_CWORD_CWORD,2636 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,2637 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,2638 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,2639 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,2640 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,2641 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,2642 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,2643 /* 1 0 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,2644 /* 1 1 -119*/ CWORD_CWORD_CWORD_CWORD,2645 /* 1 2 -118*/ CWORD_CWORD_CWORD_CWORD,2646 /* 1 3 -117*/ CWORD_CWORD_CWORD_CWORD,2647 /* 1 4 -116 */ CWORD_CWORD_CWORD_CWORD,2648 /* 1 5 -115*/ CWORD_CWORD_CWORD_CWORD,2649 /* 1 6 -114*/ CWORD_CWORD_CWORD_CWORD,2650 /* 1 7 -113*/ CWORD_CWORD_CWORD_CWORD,2651 /* 18 -112*/ CWORD_CWORD_CWORD_CWORD,2652 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,2653 /* 2 0 -110*/ CWORD_CWORD_CWORD_CWORD,2654 /* 2 1 -109*/ CWORD_CWORD_CWORD_CWORD,2655 /* 2 2 -108*/ CWORD_CWORD_CWORD_CWORD,2656 /* 2 3 -107*/ CWORD_CWORD_CWORD_CWORD,2657 /* 2 4 -106 */ CWORD_CWORD_CWORD_CWORD,2658 /* 2 5 -105*/ CWORD_CWORD_CWORD_CWORD,2659 /* 2 6 -104*/ CWORD_CWORD_CWORD_CWORD,2660 /* 2 7 -103*/ CWORD_CWORD_CWORD_CWORD,2661 /* 28 -102*/ CWORD_CWORD_CWORD_CWORD,2662 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,2663 /* 3 0 -100 */ CWORD_CWORD_CWORD_CWORD,2664 /* 3 1 -99 */ CWORD_CWORD_CWORD_CWORD,2665 /* 3 2 -98 */ CWORD_CWORD_CWORD_CWORD,2666 /* 3 3 -97*/ CWORD_CWORD_CWORD_CWORD,2667 /* 3 4 -96 */ CWORD_CWORD_CWORD_CWORD,2668 /* 3 5 -95*/ CWORD_CWORD_CWORD_CWORD,2669 /* 3 6 -94 */ CWORD_CWORD_CWORD_CWORD,2670 /* 3 7 -93 */ CWORD_CWORD_CWORD_CWORD,2671 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,2672 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,2673 /* 4 0 -90 */ CWORD_CWORD_CWORD_CWORD,2674 /* 4 1 -89*/ CWORD_CWORD_CWORD_CWORD,2675 /* 4 2 -88*/ CWORD_CWORD_CWORD_CWORD,2676 /* 4 3 -87 */ CWORD_CWORD_CWORD_CWORD,2677 /* 4 4 -86*/ CWORD_CWORD_CWORD_CWORD,2678 /* 4 5 -85 */ CWORD_CWORD_CWORD_CWORD,2679 /* 4 6 -84*/ CWORD_CWORD_CWORD_CWORD,2680 /* 4 7 -83*/ CWORD_CWORD_CWORD_CWORD,2681 /* 48 -82*/ CWORD_CWORD_CWORD_CWORD,2682 /* 49 -81*/ CWORD_CWORD_CWORD_CWORD,2683 /* 5 0 -80*/ CWORD_CWORD_CWORD_CWORD,2684 /* 5 1 -79*/ CWORD_CWORD_CWORD_CWORD,2685 /* 5 2 -78*/ CWORD_CWORD_CWORD_CWORD,2686 /* 5 3 -77*/ CWORD_CWORD_CWORD_CWORD,2687 /* 5 4 -76*/ CWORD_CWORD_CWORD_CWORD,2688 /* 5 5 -75*/ CWORD_CWORD_CWORD_CWORD,2689 /* 5 6 -74 */ CWORD_CWORD_CWORD_CWORD,2690 /* 5 7 -73 */ CWORD_CWORD_CWORD_CWORD,2691 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,2692 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,2693 /* 6 0 -70 */ CWORD_CWORD_CWORD_CWORD,2694 /* 6 1 -69 */ CWORD_CWORD_CWORD_CWORD,2695 /* 6 2 -68*/ CWORD_CWORD_CWORD_CWORD,2696 /* 6 3 -67*/ CWORD_CWORD_CWORD_CWORD,2697 /* 6 4 -66*/ CWORD_CWORD_CWORD_CWORD,2698 /* 6 5 -65*/ CWORD_CWORD_CWORD_CWORD,2699 /* 6 6 -64*/ CWORD_CWORD_CWORD_CWORD,2700 /* 6 7 -63*/ CWORD_CWORD_CWORD_CWORD,2701 /* 68 -62*/ CWORD_CWORD_CWORD_CWORD,2702 /* 69 -61*/ CWORD_CWORD_CWORD_CWORD,2703 /* 7 0 -60*/ CWORD_CWORD_CWORD_CWORD,2704 /* 7 1 -59*/ CWORD_CWORD_CWORD_CWORD,2705 /* 7 2 -58*/ CWORD_CWORD_CWORD_CWORD,2706 /* 7 3 -57*/ CWORD_CWORD_CWORD_CWORD,2707 /* 7 4 -56*/ CWORD_CWORD_CWORD_CWORD,2708 /* 7 5 -55*/ CWORD_CWORD_CWORD_CWORD,2709 /* 7 6 -54*/ CWORD_CWORD_CWORD_CWORD,2710 /* 7 7 -53*/ CWORD_CWORD_CWORD_CWORD,2711 /* 78 -52*/ CWORD_CWORD_CWORD_CWORD,2712 /* 79 -51*/ CWORD_CWORD_CWORD_CWORD,2713 /* 8 0 -50*/ CWORD_CWORD_CWORD_CWORD,2714 /* 8 1 -49*/ CWORD_CWORD_CWORD_CWORD,2715 /* 8 2 -48*/ CWORD_CWORD_CWORD_CWORD,2716 /* 8 3 -47*/ CWORD_CWORD_CWORD_CWORD,2717 /* 8 4 -46*/ CWORD_CWORD_CWORD_CWORD,2718 /* 8 5 -45*/ CWORD_CWORD_CWORD_CWORD,2719 /* 8 6 -44*/ CWORD_CWORD_CWORD_CWORD,2720 /* 8 7 -43*/ CWORD_CWORD_CWORD_CWORD,2721 /* 88 -42*/ CWORD_CWORD_CWORD_CWORD,2722 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,2723 /* 9 0 -40 */ CWORD_CWORD_CWORD_CWORD,2724 /* 9 1 -39 */ CWORD_CWORD_CWORD_CWORD,2725 /* 9 2 -38*/ CWORD_CWORD_CWORD_CWORD,2726 /* 9 3 -37*/ CWORD_CWORD_CWORD_CWORD,2727 /* 9 4 -36 */ CWORD_CWORD_CWORD_CWORD,2728 /* 9 5 -35*/ CWORD_CWORD_CWORD_CWORD,2729 /* 9 6 -34*/ CWORD_CWORD_CWORD_CWORD,2730 /* 9 7 -33*/ CWORD_CWORD_CWORD_CWORD,2731 /* 98 -32*/ CWORD_CWORD_CWORD_CWORD,2732 /* 99 -31*/ CWORD_CWORD_CWORD_CWORD,2733 /* 10 0 -30*/ CWORD_CWORD_CWORD_CWORD,2734 /* 10 1 -29*/ CWORD_CWORD_CWORD_CWORD,2735 /* 10 2 -28*/ CWORD_CWORD_CWORD_CWORD,2736 /* 10 3 -27*/ CWORD_CWORD_CWORD_CWORD,2737 /* 10 4 -26*/ CWORD_CWORD_CWORD_CWORD,2738 /* 10 5 -25*/ CWORD_CWORD_CWORD_CWORD,2739 /* 10 6 -24*/ CWORD_CWORD_CWORD_CWORD,2740 /* 10 7 -23*/ CWORD_CWORD_CWORD_CWORD,2741 /* 1 08 -22*/ CWORD_CWORD_CWORD_CWORD,2742 /* 1 09 -21*/ CWORD_CWORD_CWORD_CWORD,2743 /* 11 0 -20*/ CWORD_CWORD_CWORD_CWORD,2744 /* 11 1 -19*/ CWORD_CWORD_CWORD_CWORD,2745 /* 11 2 -18*/ CWORD_CWORD_CWORD_CWORD,2746 /* 11 3 -17*/ CWORD_CWORD_CWORD_CWORD,2747 /* 11 4 -16*/ CWORD_CWORD_CWORD_CWORD,2748 /* 11 5 -15*/ CWORD_CWORD_CWORD_CWORD,2749 /* 11 6 -14*/ CWORD_CWORD_CWORD_CWORD,2750 /* 11 7 -13*/ CWORD_CWORD_CWORD_CWORD,2751 /* 1 18 -12*/ CWORD_CWORD_CWORD_CWORD,2752 /* 1 19 -11*/ CWORD_CWORD_CWORD_CWORD,2753 /* 12 0 -10*/ CWORD_CWORD_CWORD_CWORD,2754 /* 12 1 -9*/ CWORD_CWORD_CWORD_CWORD,2755 /* 12 2 -8 */ CWORD_CWORD_CWORD_CWORD,2756 /* 12 3 -7 */ CWORD_CWORD_CWORD_CWORD,2757 /* 12 4 -6 */ CWORD_CWORD_CWORD_CWORD,2758 /* 12 5 -5*/ CWORD_CWORD_CWORD_CWORD,2759 /* 12 6 -4*/ CWORD_CWORD_CWORD_CWORD,2760 /* 12 7 -3 */ CWORD_CWORD_CWORD_CWORD,2761 /* 1 28 -2 */ CWORD_CWORD_CWORD_CWORD,2762 /* 1 29 -1 */ CWORD_CWORD_CWORD_CWORD,2763 /* 13 0 0 */ CWORD_CWORD_CWORD_CWORD,2764 /* 13 1 1 */ CWORD_CWORD_CWORD_CWORD,2765 /* 13 2 2 */ CWORD_CWORD_CWORD_CWORD,2766 /* 13 3 3 */ CWORD_CWORD_CWORD_CWORD,2767 /* 13 4 4 */ CWORD_CWORD_CWORD_CWORD,2768 /* 13 5 5*/ CWORD_CWORD_CWORD_CWORD,2769 /* 13 6 6*/ CWORD_CWORD_CWORD_CWORD,2770 /* 13 7 7*/ CWORD_CWORD_CWORD_CWORD,2771 /* 1 38 8*/ CWORD_CWORD_CWORD_CWORD,2772 /* 1 39 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,2773 /* 14 0 10 "\n" */ CNL_CNL_CNL_CNL,2774 /* 14 1 11*/ CWORD_CWORD_CWORD_CWORD,2775 /* 14 2 12*/ CWORD_CWORD_CWORD_CWORD,2776 /* 14 3 13*/ CWORD_CWORD_CWORD_CWORD,2777 /* 14 4 14*/ CWORD_CWORD_CWORD_CWORD,2778 /* 14 5 15*/ CWORD_CWORD_CWORD_CWORD,2779 /* 14 6 16*/ CWORD_CWORD_CWORD_CWORD,2780 /* 14 7 17*/ CWORD_CWORD_CWORD_CWORD,2781 /* 1 48 18*/ CWORD_CWORD_CWORD_CWORD,2782 /* 1 49 19*/ CWORD_CWORD_CWORD_CWORD,2783 /* 15 0 20*/ CWORD_CWORD_CWORD_CWORD,2784 /* 15 1 21*/ CWORD_CWORD_CWORD_CWORD,2785 /* 15 2 22*/ CWORD_CWORD_CWORD_CWORD,2786 /* 15 3 23*/ CWORD_CWORD_CWORD_CWORD,2787 /* 15 4 24*/ CWORD_CWORD_CWORD_CWORD,2788 /* 15 5 25*/ CWORD_CWORD_CWORD_CWORD,2789 /* 15 6 26*/ CWORD_CWORD_CWORD_CWORD,2790 /* 15 7 27*/ CWORD_CWORD_CWORD_CWORD,2791 /* 1 58 28*/ CWORD_CWORD_CWORD_CWORD,2792 /* 1 59 29*/ CWORD_CWORD_CWORD_CWORD,2793 /* 16 0 30*/ CWORD_CWORD_CWORD_CWORD,2794 /* 16 1 31*/ CWORD_CWORD_CWORD_CWORD,2795 /* 16 2 32 " " */ CSPCL_CWORD_CWORD_CWORD,2796 /* 16 3 33 "!" */ CWORD_CCTL_CCTL_CWORD,2797 /* 16 4 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,2798 /* 16 5 35 "#"*/ CWORD_CWORD_CWORD_CWORD,2799 /* 16 6 36 "$" */ CVAR_CVAR_CWORD_CVAR,2800 /* 16 7 37 "%"*/ CWORD_CWORD_CWORD_CWORD,2801 /* 1 68 38 "&" */ CSPCL_CWORD_CWORD_CWORD,2802 /* 1 69 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,2803 /* 17 0 40 "(" */ CSPCL_CWORD_CWORD_CLP,2804 /* 17 1 41 ")" */ CSPCL_CWORD_CWORD_CRP,2805 /* 17 2 42 "*" */ CWORD_CCTL_CCTL_CWORD,2806 /* 17 3 43 "+"*/ CWORD_CWORD_CWORD_CWORD,2807 /* 17 4 44 ","*/ CWORD_CWORD_CWORD_CWORD,2808 /* 17 5 45 "-" */ CWORD_CCTL_CCTL_CWORD,2809 /* 17 6 46 "."*/ CWORD_CWORD_CWORD_CWORD,2810 /* 17 7 47 "/" */ CWORD_CCTL_CCTL_CWORD,2811 /* 1 78 48 "0"*/ CWORD_CWORD_CWORD_CWORD,2812 /* 1 79 49 "1"*/ CWORD_CWORD_CWORD_CWORD,2813 /* 18 0 50 "2"*/ CWORD_CWORD_CWORD_CWORD,2814 /* 18 1 51 "3"*/ CWORD_CWORD_CWORD_CWORD,2815 /* 18 2 52 "4"*/ CWORD_CWORD_CWORD_CWORD,2816 /* 18 3 53 "5"*/ CWORD_CWORD_CWORD_CWORD,2817 /* 18 4 54 "6"*/ CWORD_CWORD_CWORD_CWORD,2818 /* 18 5 55 "7"*/ CWORD_CWORD_CWORD_CWORD,2819 /* 18 6 56 "8"*/ CWORD_CWORD_CWORD_CWORD,2820 /* 18 7 57 "9"*/ CWORD_CWORD_CWORD_CWORD,2821 /* 1 88 58 ":" */ CWORD_CCTL_CCTL_CWORD,2822 /* 1 89 59 ";" */ CSPCL_CWORD_CWORD_CWORD,2823 /* 19 0 60 "<" */ CSPCL_CWORD_CWORD_CWORD,2824 /* 19 1 61 "=" */ CWORD_CCTL_CCTL_CWORD,2825 /* 19 2 62 ">" */ CSPCL_CWORD_CWORD_CWORD,2826 /* 19 3 63 "?" */ CWORD_CCTL_CCTL_CWORD,2827 /* 19 4 64 "@"*/ CWORD_CWORD_CWORD_CWORD,2828 /* 19 5 65 "A"*/ CWORD_CWORD_CWORD_CWORD,2829 /* 19 6 66 "B"*/ CWORD_CWORD_CWORD_CWORD,2830 /* 19 7 67 "C"*/ CWORD_CWORD_CWORD_CWORD,2831 /* 198 68 "D"*/ CWORD_CWORD_CWORD_CWORD,2832 /* 199 69 "E"*/ CWORD_CWORD_CWORD_CWORD,2833 /* 20 0 70 "F"*/ CWORD_CWORD_CWORD_CWORD,2834 /* 20 1 71 "G"*/ CWORD_CWORD_CWORD_CWORD,2835 /* 20 2 72 "H"*/ CWORD_CWORD_CWORD_CWORD,2836 /* 20 3 73 "I"*/ CWORD_CWORD_CWORD_CWORD,2837 /* 20 4 74 "J"*/ CWORD_CWORD_CWORD_CWORD,2838 /* 20 5 75 "K"*/ CWORD_CWORD_CWORD_CWORD,2839 /* 20 6 76 "L"*/ CWORD_CWORD_CWORD_CWORD,2840 /* 20 7 77 "M"*/ CWORD_CWORD_CWORD_CWORD,2841 /* 2 08 78 "N"*/ CWORD_CWORD_CWORD_CWORD,2842 /* 2 09 79 "O"*/ CWORD_CWORD_CWORD_CWORD,2843 /* 21 0 80 "P"*/ CWORD_CWORD_CWORD_CWORD,2844 /* 21 1 81 "Q"*/ CWORD_CWORD_CWORD_CWORD,2845 /* 21 2 82 "R"*/ CWORD_CWORD_CWORD_CWORD,2846 /* 21 3 83 "S"*/ CWORD_CWORD_CWORD_CWORD,2847 /* 21 4 84 "T"*/ CWORD_CWORD_CWORD_CWORD,2848 /* 21 5 85 "U"*/ CWORD_CWORD_CWORD_CWORD,2849 /* 21 6 86 "V"*/ CWORD_CWORD_CWORD_CWORD,2850 /* 21 7 87 "W"*/ CWORD_CWORD_CWORD_CWORD,2851 /* 2 18 88 "X"*/ CWORD_CWORD_CWORD_CWORD,2852 /* 2 19 89 "Y"*/ CWORD_CWORD_CWORD_CWORD,2853 /* 22 0 90 "Z"*/ CWORD_CWORD_CWORD_CWORD,2854 /* 22 1 91 "[" */ CWORD_CCTL_CCTL_CWORD,2855 /* 22 2 92 "\" */ CBACK_CBACK_CCTL_CBACK,2856 /* 22 3 93 "]" */ CWORD_CCTL_CCTL_CWORD,2857 /* 22 4 94 "^"*/ CWORD_CWORD_CWORD_CWORD,2858 /* 22 5 95 "_"*/ CWORD_CWORD_CWORD_CWORD,2859 /* 22 6 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,2860 /* 22 7 97 "a"*/ CWORD_CWORD_CWORD_CWORD,2861 /* 2 28 98 "b"*/ CWORD_CWORD_CWORD_CWORD,2862 /* 2 29 99 "c"*/ CWORD_CWORD_CWORD_CWORD,2863 /* 23 0 100 "d"*/ CWORD_CWORD_CWORD_CWORD,2864 /* 23 1 101 "e"*/ CWORD_CWORD_CWORD_CWORD,2865 /* 23 2 102 "f"*/ CWORD_CWORD_CWORD_CWORD,2866 /* 23 3 103 "g"*/ CWORD_CWORD_CWORD_CWORD,2867 /* 23 4 104 "h"*/ CWORD_CWORD_CWORD_CWORD,2868 /* 23 5 105 "i"*/ CWORD_CWORD_CWORD_CWORD,2869 /* 23 6 106 "j"*/ CWORD_CWORD_CWORD_CWORD,2870 /* 23 7 107 "k"*/ CWORD_CWORD_CWORD_CWORD,2871 /* 23 8 108 "l"*/ CWORD_CWORD_CWORD_CWORD,2872 /* 2 39 109 "m"*/ CWORD_CWORD_CWORD_CWORD,2873 /* 24 0 110 "n"*/ CWORD_CWORD_CWORD_CWORD,2874 /* 24 1 111 "o"*/ CWORD_CWORD_CWORD_CWORD,2875 /* 24 2 112 "p"*/ CWORD_CWORD_CWORD_CWORD,2876 /* 24 3 113 "q"*/ CWORD_CWORD_CWORD_CWORD,2877 /* 24 4 114 "r"*/ CWORD_CWORD_CWORD_CWORD,2878 /* 24 5 115 "s"*/ CWORD_CWORD_CWORD_CWORD,2879 /* 24 6 116 "t"*/ CWORD_CWORD_CWORD_CWORD,2880 /* 24 7 117 "u"*/ CWORD_CWORD_CWORD_CWORD,2881 /* 2 48 118 "v"*/ CWORD_CWORD_CWORD_CWORD,2882 /* 2 49 119 "w"*/ CWORD_CWORD_CWORD_CWORD,2883 /* 25 0 120 "x"*/ CWORD_CWORD_CWORD_CWORD,2884 /* 25 1 121 "y"*/ CWORD_CWORD_CWORD_CWORD,2885 /* 25 2 122 "z"*/ CWORD_CWORD_CWORD_CWORD,2886 /* 25 3 123 "{"*/ CWORD_CWORD_CWORD_CWORD,2887 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,2888 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, 2889 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,2890 /* 257 127 */ CWORD_CWORD_CWORD_CWORD, 2844 /* 0 */ CWORD_CWORD_CWORD_CWORD, 2845 /* 1 */ CWORD_CWORD_CWORD_CWORD, 2846 /* 2 */ CWORD_CWORD_CWORD_CWORD, 2847 /* 3 */ CWORD_CWORD_CWORD_CWORD, 2848 /* 4 */ CWORD_CWORD_CWORD_CWORD, 2849 /* 5 */ CWORD_CWORD_CWORD_CWORD, 2850 /* 6 */ CWORD_CWORD_CWORD_CWORD, 2851 /* 7 */ CWORD_CWORD_CWORD_CWORD, 2852 /* 8 */ CWORD_CWORD_CWORD_CWORD, 2853 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD, 2854 /* 10 "\n" */ CNL_CNL_CNL_CNL, 2855 /* 11 */ CWORD_CWORD_CWORD_CWORD, 2856 /* 12 */ CWORD_CWORD_CWORD_CWORD, 2857 /* 13 */ CWORD_CWORD_CWORD_CWORD, 2858 /* 14 */ CWORD_CWORD_CWORD_CWORD, 2859 /* 15 */ CWORD_CWORD_CWORD_CWORD, 2860 /* 16 */ CWORD_CWORD_CWORD_CWORD, 2861 /* 17 */ CWORD_CWORD_CWORD_CWORD, 2862 /* 18 */ CWORD_CWORD_CWORD_CWORD, 2863 /* 19 */ CWORD_CWORD_CWORD_CWORD, 2864 /* 20 */ CWORD_CWORD_CWORD_CWORD, 2865 /* 21 */ CWORD_CWORD_CWORD_CWORD, 2866 /* 22 */ CWORD_CWORD_CWORD_CWORD, 2867 /* 23 */ CWORD_CWORD_CWORD_CWORD, 2868 /* 24 */ CWORD_CWORD_CWORD_CWORD, 2869 /* 25 */ CWORD_CWORD_CWORD_CWORD, 2870 /* 26 */ CWORD_CWORD_CWORD_CWORD, 2871 /* 27 */ CWORD_CWORD_CWORD_CWORD, 2872 /* 28 */ CWORD_CWORD_CWORD_CWORD, 2873 /* 29 */ CWORD_CWORD_CWORD_CWORD, 2874 /* 30 */ CWORD_CWORD_CWORD_CWORD, 2875 /* 31 */ CWORD_CWORD_CWORD_CWORD, 2876 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD, 2877 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD, 2878 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD, 2879 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD, 2880 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR, 2881 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD, 2882 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD, 2883 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD, 2884 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP, 2885 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP, 2886 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD, 2887 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD, 2888 /* 44 "," */ CWORD_CWORD_CWORD_CWORD, 2889 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD, 2890 /* 46 "." */ CWORD_CWORD_CWORD_CWORD, 2891 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD, 2892 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD, 2893 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD, 2894 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD, 2895 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD, 2896 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD, 2897 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD, 2898 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD, 2899 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD, 2900 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD, 2901 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD, 2902 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD, 2903 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD, 2904 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD, 2905 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD, 2906 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD, 2907 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD, 2908 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD, 2909 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD, 2910 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD, 2911 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD, 2912 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD, 2913 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD, 2914 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD, 2915 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD, 2916 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD, 2917 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD, 2918 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD, 2919 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD, 2920 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD, 2921 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD, 2922 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD, 2923 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD, 2924 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD, 2925 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD, 2926 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD, 2927 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD, 2928 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD, 2929 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD, 2930 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD, 2931 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD, 2932 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD, 2933 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD, 2934 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD, 2935 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD, 2936 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK, 2937 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD, 2938 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD, 2939 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD, 2940 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE, 2941 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD, 2942 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD, 2943 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD, 2944 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD, 2945 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD, 2946 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD, 2947 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD, 2948 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD, 2949 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD, 2950 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD, 2951 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD, 2952 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD, 2953 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD, 2954 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD, 2955 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD, 2956 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD, 2957 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD, 2958 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD, 2959 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD, 2960 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD, 2961 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD, 2962 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD, 2963 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD, 2964 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD, 2965 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD, 2966 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD, 2967 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD, 2968 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD, 2969 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, 2970 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD, 2971 /* 127 del */ CWORD_CWORD_CWORD_CWORD, 2972 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD, 2973 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL, 2974 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL, 2975 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, 2976 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, 2977 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, 2978 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, 2979 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, 2980 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, 2981 /* 137 */ CWORD_CWORD_CWORD_CWORD, 2982 /* 138 */ CWORD_CWORD_CWORD_CWORD, 2983 /* 139 */ CWORD_CWORD_CWORD_CWORD, 2984 /* 140 */ CWORD_CWORD_CWORD_CWORD, 2985 /* 141 */ CWORD_CWORD_CWORD_CWORD, 2986 /* 142 */ CWORD_CWORD_CWORD_CWORD, 2987 /* 143 */ CWORD_CWORD_CWORD_CWORD, 2988 /* 144 */ CWORD_CWORD_CWORD_CWORD, 2989 /* 145 */ CWORD_CWORD_CWORD_CWORD, 2990 /* 146 */ CWORD_CWORD_CWORD_CWORD, 2991 /* 147 */ CWORD_CWORD_CWORD_CWORD, 2992 /* 148 */ CWORD_CWORD_CWORD_CWORD, 2993 /* 149 */ CWORD_CWORD_CWORD_CWORD, 2994 /* 150 */ CWORD_CWORD_CWORD_CWORD, 2995 /* 151 */ CWORD_CWORD_CWORD_CWORD, 2996 /* 152 */ CWORD_CWORD_CWORD_CWORD, 2997 /* 153 */ CWORD_CWORD_CWORD_CWORD, 2998 /* 154 */ CWORD_CWORD_CWORD_CWORD, 2999 /* 155 */ CWORD_CWORD_CWORD_CWORD, 3000 /* 156 */ CWORD_CWORD_CWORD_CWORD, 3001 /* 157 */ CWORD_CWORD_CWORD_CWORD, 3002 /* 158 */ CWORD_CWORD_CWORD_CWORD, 3003 /* 159 */ CWORD_CWORD_CWORD_CWORD, 3004 /* 160 */ CWORD_CWORD_CWORD_CWORD, 3005 /* 161 */ CWORD_CWORD_CWORD_CWORD, 3006 /* 162 */ CWORD_CWORD_CWORD_CWORD, 3007 /* 163 */ CWORD_CWORD_CWORD_CWORD, 3008 /* 164 */ CWORD_CWORD_CWORD_CWORD, 3009 /* 165 */ CWORD_CWORD_CWORD_CWORD, 3010 /* 166 */ CWORD_CWORD_CWORD_CWORD, 3011 /* 167 */ CWORD_CWORD_CWORD_CWORD, 3012 /* 168 */ CWORD_CWORD_CWORD_CWORD, 3013 /* 169 */ CWORD_CWORD_CWORD_CWORD, 3014 /* 170 */ CWORD_CWORD_CWORD_CWORD, 3015 /* 171 */ CWORD_CWORD_CWORD_CWORD, 3016 /* 172 */ CWORD_CWORD_CWORD_CWORD, 3017 /* 173 */ CWORD_CWORD_CWORD_CWORD, 3018 /* 174 */ CWORD_CWORD_CWORD_CWORD, 3019 /* 175 */ CWORD_CWORD_CWORD_CWORD, 3020 /* 176 */ CWORD_CWORD_CWORD_CWORD, 3021 /* 177 */ CWORD_CWORD_CWORD_CWORD, 3022 /* 178 */ CWORD_CWORD_CWORD_CWORD, 3023 /* 179 */ CWORD_CWORD_CWORD_CWORD, 3024 /* 180 */ CWORD_CWORD_CWORD_CWORD, 3025 /* 181 */ CWORD_CWORD_CWORD_CWORD, 3026 /* 182 */ CWORD_CWORD_CWORD_CWORD, 3027 /* 183 */ CWORD_CWORD_CWORD_CWORD, 3028 /* 184 */ CWORD_CWORD_CWORD_CWORD, 3029 /* 185 */ CWORD_CWORD_CWORD_CWORD, 3030 /* 186 */ CWORD_CWORD_CWORD_CWORD, 3031 /* 187 */ CWORD_CWORD_CWORD_CWORD, 3032 /* 188 */ CWORD_CWORD_CWORD_CWORD, 3033 /* 189 */ CWORD_CWORD_CWORD_CWORD, 3034 /* 190 */ CWORD_CWORD_CWORD_CWORD, 3035 /* 191 */ CWORD_CWORD_CWORD_CWORD, 3036 /* 192 */ CWORD_CWORD_CWORD_CWORD, 3037 /* 193 */ CWORD_CWORD_CWORD_CWORD, 3038 /* 194 */ CWORD_CWORD_CWORD_CWORD, 3039 /* 195 */ CWORD_CWORD_CWORD_CWORD, 3040 /* 196 */ CWORD_CWORD_CWORD_CWORD, 3041 /* 197 */ CWORD_CWORD_CWORD_CWORD, 3042 /* 198 */ CWORD_CWORD_CWORD_CWORD, 3043 /* 199 */ CWORD_CWORD_CWORD_CWORD, 3044 /* 200 */ CWORD_CWORD_CWORD_CWORD, 3045 /* 201 */ CWORD_CWORD_CWORD_CWORD, 3046 /* 202 */ CWORD_CWORD_CWORD_CWORD, 3047 /* 203 */ CWORD_CWORD_CWORD_CWORD, 3048 /* 204 */ CWORD_CWORD_CWORD_CWORD, 3049 /* 205 */ CWORD_CWORD_CWORD_CWORD, 3050 /* 206 */ CWORD_CWORD_CWORD_CWORD, 3051 /* 207 */ CWORD_CWORD_CWORD_CWORD, 3052 /* 208 */ CWORD_CWORD_CWORD_CWORD, 3053 /* 209 */ CWORD_CWORD_CWORD_CWORD, 3054 /* 210 */ CWORD_CWORD_CWORD_CWORD, 3055 /* 211 */ CWORD_CWORD_CWORD_CWORD, 3056 /* 212 */ CWORD_CWORD_CWORD_CWORD, 3057 /* 213 */ CWORD_CWORD_CWORD_CWORD, 3058 /* 214 */ CWORD_CWORD_CWORD_CWORD, 3059 /* 215 */ CWORD_CWORD_CWORD_CWORD, 3060 /* 216 */ CWORD_CWORD_CWORD_CWORD, 3061 /* 217 */ CWORD_CWORD_CWORD_CWORD, 3062 /* 218 */ CWORD_CWORD_CWORD_CWORD, 3063 /* 219 */ CWORD_CWORD_CWORD_CWORD, 3064 /* 220 */ CWORD_CWORD_CWORD_CWORD, 3065 /* 221 */ CWORD_CWORD_CWORD_CWORD, 3066 /* 222 */ CWORD_CWORD_CWORD_CWORD, 3067 /* 223 */ CWORD_CWORD_CWORD_CWORD, 3068 /* 224 */ CWORD_CWORD_CWORD_CWORD, 3069 /* 225 */ CWORD_CWORD_CWORD_CWORD, 3070 /* 226 */ CWORD_CWORD_CWORD_CWORD, 3071 /* 227 */ CWORD_CWORD_CWORD_CWORD, 3072 /* 228 */ CWORD_CWORD_CWORD_CWORD, 3073 /* 229 */ CWORD_CWORD_CWORD_CWORD, 3074 /* 230 */ CWORD_CWORD_CWORD_CWORD, 3075 /* 231 */ CWORD_CWORD_CWORD_CWORD, 3076 /* 232 */ CWORD_CWORD_CWORD_CWORD, 3077 /* 233 */ CWORD_CWORD_CWORD_CWORD, 3078 /* 234 */ CWORD_CWORD_CWORD_CWORD, 3079 /* 235 */ CWORD_CWORD_CWORD_CWORD, 3080 /* 236 */ CWORD_CWORD_CWORD_CWORD, 3081 /* 237 */ CWORD_CWORD_CWORD_CWORD, 3082 /* 238 */ CWORD_CWORD_CWORD_CWORD, 3083 /* 239 */ CWORD_CWORD_CWORD_CWORD, 3084 /* 230 */ CWORD_CWORD_CWORD_CWORD, 3085 /* 241 */ CWORD_CWORD_CWORD_CWORD, 3086 /* 242 */ CWORD_CWORD_CWORD_CWORD, 3087 /* 243 */ CWORD_CWORD_CWORD_CWORD, 3088 /* 244 */ CWORD_CWORD_CWORD_CWORD, 3089 /* 245 */ CWORD_CWORD_CWORD_CWORD, 3090 /* 246 */ CWORD_CWORD_CWORD_CWORD, 3091 /* 247 */ CWORD_CWORD_CWORD_CWORD, 3092 /* 248 */ CWORD_CWORD_CWORD_CWORD, 3093 /* 249 */ CWORD_CWORD_CWORD_CWORD, 3094 /* 250 */ CWORD_CWORD_CWORD_CWORD, 3095 /* 251 */ CWORD_CWORD_CWORD_CWORD, 3096 /* 252 */ CWORD_CWORD_CWORD_CWORD, 3097 /* 253 */ CWORD_CWORD_CWORD_CWORD, 3098 /* 254 */ CWORD_CWORD_CWORD_CWORD, 3099 /* 255 */ CWORD_CWORD_CWORD_CWORD, 3100 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 3101 # if ENABLE_ASH_ALIAS 3102 /* PEOA */ CSPCL_CIGN_CIGN_CIGN, 3103 # endif 2891 3104 }; 2892 3105 2893 # define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])2894 2895 #endif /* USE_SIT_FUNCTION */3106 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf) 3107 3108 #endif /* !USE_SIT_FUNCTION */ 2896 3109 2897 3110 … … 2902 3115 #define ALIASINUSE 1 2903 3116 #define ALIASDEAD 2 2904 2905 #define ATABSIZE 392906 3117 2907 3118 struct alias { … … 2912 3123 }; 2913 3124 2914 static struct alias *atab[ATABSIZE]; 3125 3126 static struct alias **atab; // [ATABSIZE]; 3127 #define INIT_G_alias() do { \ 3128 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ 3129 } while (0) 3130 2915 3131 2916 3132 static struct alias ** … … 2983 3199 } else { 2984 3200 /* not found */ 2985 ap = ck malloc(sizeof(struct alias));3201 ap = ckzalloc(sizeof(struct alias)); 2986 3202 ap->name = ckstrdup(name); 2987 3203 ap->val = ckstrdup(val); 2988 ap->flag = 0;2989 ap->next = 0;3204 /*ap->flag = 0; - ckzalloc did it */ 3205 /*ap->next = NULL;*/ 2990 3206 *app = ap; 2991 3207 } … … 3038 3254 * TODO - sort output 3039 3255 */ 3040 static int 3041 aliascmd(int argc , char **argv)3256 static int FAST_FUNC 3257 aliascmd(int argc UNUSED_PARAM, char **argv) 3042 3258 { 3043 3259 char *n, *v; … … 3045 3261 struct alias *ap; 3046 3262 3047 if ( argc == 1) {3263 if (!argv[1]) { 3048 3264 int i; 3049 3265 3050 for (i = 0; i < ATABSIZE; i++) 3266 for (i = 0; i < ATABSIZE; i++) { 3051 3267 for (ap = atab[i]; ap; ap = ap->next) { 3052 3268 printalias(ap); 3053 3269 } 3270 } 3054 3271 return 0; 3055 3272 } … … 3072 3289 } 3073 3290 3074 static int 3075 unaliascmd(int argc , char **argv)3291 static int FAST_FUNC 3292 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 3076 3293 { 3077 3294 int i; … … 3099 3316 3100 3317 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ 3101 #define FORK_FG 03102 #define FORK_BG 13318 #define FORK_FG 0 3319 #define FORK_BG 1 3103 3320 #define FORK_NOJOB 2 3104 3321 3105 3322 /* mode flags for showjob(s) */ 3106 #define SHOW_ PGID 0x01 /* only show pgid - for jobs -p*/3107 #define SHOW_PID 0x04 /* include process pid*/3108 #define SHOW_CHANGED 0x0 8/* only jobs whose state has changed */3323 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */ 3324 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ 3325 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ 3109 3326 3110 3327 /* … … 3114 3331 * array of pids. 3115 3332 */ 3116 3117 3333 struct procstat { 3118 pid_t p id;/* process id */3119 int status;/* last process status from wait() */3120 char * cmd;/* text of command being run */3334 pid_t ps_pid; /* process id */ 3335 int ps_status; /* last process status from wait() */ 3336 char *ps_cmd; /* text of command being run */ 3121 3337 }; 3122 3338 … … 3143 3359 }; 3144 3360 3145 static pid_t backgndpid; /* pid of last background process */ 3146 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 3147 3148 static struct job *makejob(union node *, int); 3361 static struct job *makejob(/*union node *,*/ int); 3149 3362 static int forkshell(struct job *, union node *, int); 3150 3363 static int waitforjob(struct job *); 3151 3364 3152 3365 #if !JOBS 3153 enum { jobctl = 0 };3366 enum { doing_jobctl = 0 }; 3154 3367 #define setjobctl(on) do {} while (0) 3155 3368 #else 3156 static smallint jobctl; /* true if doing job control */3369 static smallint doing_jobctl; //references:8 3157 3370 static void setjobctl(int); 3158 3371 #endif 3372 3373 /* 3374 * Ignore a signal. 3375 */ 3376 static void 3377 ignoresig(int signo) 3378 { 3379 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */ 3380 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 3381 /* No, need to do it */ 3382 signal(signo, SIG_IGN); 3383 } 3384 sigmode[signo - 1] = S_HARD_IGN; 3385 } 3386 3387 /* 3388 * Only one usage site - in setsignal() 3389 */ 3390 static void 3391 signal_handler(int signo) 3392 { 3393 gotsig[signo - 1] = 1; 3394 3395 if (signo == SIGINT && !trap[SIGINT]) { 3396 if (!suppress_int) { 3397 pending_sig = 0; 3398 raise_interrupt(); /* does not return */ 3399 } 3400 pending_int = 1; 3401 } else { 3402 pending_sig = signo; 3403 } 3404 } 3159 3405 3160 3406 /* … … 3165 3411 setsignal(int signo) 3166 3412 { 3167 int action;3168 char *t, tsig;3413 char *t; 3414 char cur_act, new_act; 3169 3415 struct sigaction act; 3170 3416 3171 3417 t = trap[signo]; 3172 if (t == NULL) 3173 action = S_DFL; 3174 else if (*t != '\0') 3175 action = S_CATCH; 3176 else 3177 action = S_IGN; 3178 if (rootshell && action == S_DFL) { 3418 new_act = S_DFL; 3419 if (t != NULL) { /* trap for this sig is set */ 3420 new_act = S_CATCH; 3421 if (t[0] == '\0') /* trap is "": ignore this sig */ 3422 new_act = S_IGN; 3423 } 3424 3425 if (rootshell && new_act == S_DFL) { 3179 3426 switch (signo) { 3180 3427 case SIGINT: 3181 3428 if (iflag || minusc || sflag == 0) 3182 action= S_CATCH;3429 new_act = S_CATCH; 3183 3430 break; 3184 3431 case SIGQUIT: … … 3187 3434 break; 3188 3435 #endif 3189 /* FALLTHROUGH */ 3436 /* man bash: 3437 * "In all cases, bash ignores SIGQUIT. Non-builtin 3438 * commands run by bash have signal handlers 3439 * set to the values inherited by the shell 3440 * from its parent". */ 3441 new_act = S_IGN; 3442 break; 3190 3443 case SIGTERM: 3191 3444 if (iflag) 3192 action= S_IGN;3445 new_act = S_IGN; 3193 3446 break; 3194 3447 #if JOBS … … 3196 3449 case SIGTTOU: 3197 3450 if (mflag) 3198 action= S_IGN;3451 new_act = S_IGN; 3199 3452 break; 3200 3453 #endif 3201 3454 } 3202 3455 } 3456 //TODO: if !rootshell, we reset SIGQUIT to DFL, 3457 //whereas we have to restore it to what shell got on entry 3458 //from the parent. See comment above 3203 3459 3204 3460 t = &sigmode[signo - 1]; 3205 tsig = *t; 3206 if (tsig == 0) { 3207 /* 3208 * current setting unknown 3209 */ 3210 if (sigaction(signo, 0, &act) == -1) { 3211 /* 3212 * Pretend it worked; maybe we should give a warning 3213 * here, but other shells don't. We don't alter 3214 * sigmode, so that we retry every time. 3215 */ 3461 cur_act = *t; 3462 if (cur_act == 0) { 3463 /* current setting is not yet known */ 3464 if (sigaction(signo, NULL, &act)) { 3465 /* pretend it worked; maybe we should give a warning, 3466 * but other shells don't. We don't alter sigmode, 3467 * so we retry every time. 3468 * btw, in Linux it never fails. --vda */ 3216 3469 return; 3217 3470 } 3218 3471 if (act.sa_handler == SIG_IGN) { 3472 cur_act = S_HARD_IGN; 3219 3473 if (mflag 3220 3474 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) 3221 3475 ) { 3222 tsig = S_IGN; /* don't hard ignore these */ 3223 } else 3224 tsig = S_HARD_IGN; 3225 } else { 3226 tsig = S_RESET; /* force to be set */ 3227 } 3228 } 3229 if (tsig == S_HARD_IGN || tsig == action) 3476 cur_act = S_IGN; /* don't hard ignore these */ 3477 } 3478 } 3479 } 3480 if (cur_act == S_HARD_IGN || cur_act == new_act) 3230 3481 return; 3231 switch (action) { 3482 3483 act.sa_handler = SIG_DFL; 3484 switch (new_act) { 3232 3485 case S_CATCH: 3233 act.sa_handler = onsig; 3486 act.sa_handler = signal_handler; 3487 act.sa_flags = 0; /* matters only if !DFL and !IGN */ 3488 sigfillset(&act.sa_mask); /* ditto */ 3234 3489 break; 3235 3490 case S_IGN: 3236 3491 act.sa_handler = SIG_IGN; 3237 3492 break; 3238 default: 3239 act.sa_handler = SIG_DFL; 3240 } 3241 *t = action; 3242 act.sa_flags = 0; 3243 sigfillset(&act.sa_mask); 3244 sigaction(signo, &act, 0); 3493 } 3494 sigaction_set(signo, &act); 3495 3496 *t = new_act; 3245 3497 } 3246 3498 … … 3251 3503 3252 3504 /* mode flags for dowait */ 3253 #define DOWAIT_NO RMAL 03254 #define DOWAIT_BLOCK 13505 #define DOWAIT_NONBLOCK WNOHANG 3506 #define DOWAIT_BLOCK 0 3255 3507 3256 3508 #if JOBS 3257 3509 /* pgrp of shell on invocation */ 3258 static int initialpgrp; 3259 static int ttyfd = -1; 3510 static int initialpgrp; //references:2 3511 static int ttyfd = -1; //5 3260 3512 #endif 3261 3513 /* array of jobs */ 3262 static struct job *jobtab; 3514 static struct job *jobtab; //5 3263 3515 /* size of array */ 3264 static unsigned njobs; 3516 static unsigned njobs; //4 3265 3517 /* current job */ 3266 static struct job *curjob; 3518 static struct job *curjob; //lots 3267 3519 /* number of presumed living untracked jobs */ 3268 static int jobless; 3520 static int jobless; //4 3269 3521 3270 3522 static void … … 3327 3579 * Convert a job name to a job structure. 3328 3580 */ 3581 #if !JOBS 3582 #define getjob(name, getctl) getjob(name) 3583 #endif 3329 3584 static struct job * 3330 3585 getjob(const char *name, int getctl) … … 3332 3587 struct job *jp; 3333 3588 struct job *found; 3334 const char *err_msg = " No such job: %s";3589 const char *err_msg = "%s: no such job"; 3335 3590 unsigned num; 3336 3591 int c; … … 3383 3638 } 3384 3639 3385 found = 0; 3386 while (1) { 3387 if (!jp) 3388 goto err; 3389 if (match(jp->ps[0].cmd, p)) { 3640 found = NULL; 3641 while (jp) { 3642 if (match(jp->ps[0].ps_cmd, p)) { 3390 3643 if (found) 3391 3644 goto err; … … 3395 3648 jp = jp->prev_job; 3396 3649 } 3650 if (!found) 3651 goto err; 3652 jp = found; 3397 3653 3398 3654 gotit: … … 3418 3674 INT_OFF; 3419 3675 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 3420 if (ps-> cmd != nullstr)3421 free(ps-> cmd);3676 if (ps->ps_cmd != nullstr) 3677 free(ps->ps_cmd); 3422 3678 } 3423 3679 if (jp->ps != &jp->ps0) … … 3433 3689 { 3434 3690 if (tcsetpgrp(fd, pgrp)) 3435 ash_msg_and_raise_error("can not set tty process group (%m)");3691 ash_msg_and_raise_error("can't set tty process group (%m)"); 3436 3692 } 3437 3693 … … 3451 3707 int pgrp; 3452 3708 3453 if (on == jobctl || rootshell == 0)3709 if (on == doing_jobctl || rootshell == 0) 3454 3710 return; 3455 3711 if (on) { … … 3461 3717 * Obviously, a workaround for bugs when someone 3462 3718 * failed to provide a controlling tty to bash! :) */ 3463 fd += 3; 3464 while (!isatty(fd) && --fd >= 0) 3465 ; 3719 fd = 2; 3720 while (!isatty(fd)) 3721 if (--fd < 0) 3722 goto out; 3466 3723 } 3467 3724 fd = fcntl(fd, F_DUPFD, 10); 3468 close(ofd); 3725 if (ofd >= 0) 3726 close(ofd); 3469 3727 if (fd < 0) 3470 3728 goto out; 3471 fcntl(fd, F_SETFD, FD_CLOEXEC); 3729 /* fd is a tty at this point */ 3730 close_on_exec_on(fd); 3472 3731 do { /* while we are in the background */ 3473 3732 pgrp = tcgetpgrp(fd); … … 3495 3754 pgrp = initialpgrp; 3496 3755 /* was xtcsetpgrp, but this can make exiting ash 3497 * with pty already deleted loop forever*/3756 * loop forever if pty is already deleted */ 3498 3757 tcsetpgrp(fd, pgrp); 3499 3758 setpgid(0, pgrp); … … 3502 3761 setsignal(SIGTTIN); 3503 3762 close: 3504 close(fd); 3763 if (fd >= 0) 3764 close(fd); 3505 3765 fd = -1; 3506 3766 } 3507 3767 ttyfd = fd; 3508 jobctl = on;3509 } 3510 3511 static int 3768 doing_jobctl = on; 3769 } 3770 3771 static int FAST_FUNC 3512 3772 killcmd(int argc, char **argv) 3513 3773 { 3774 int i = 1; 3514 3775 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3515 int i = 1;3516 3776 do { 3517 3777 if (argv[i][0] == '%') { 3518 3778 struct job *jp = getjob(argv[i], 0); 3519 unsigned pid = jp->ps[0].p id;3779 unsigned pid = jp->ps[0].ps_pid; 3520 3780 /* Enough space for ' -NNN<nul>' */ 3521 3781 argv[i] = alloca(sizeof(int)*3 + 3); … … 3531 3791 3532 3792 static void 3533 showpipe(struct job *jp , FILE *out)3534 { 3535 struct procstat * sp;3536 struct procstat * spend;3537 3538 spend = jp->ps + jp->nprocs;3539 for ( sp = jp->ps + 1; sp < spend; sp++)3540 fprintf(out, " | %s", sp->cmd);3541 outcslow('\n', out);3793 showpipe(struct job *jp /*, FILE *out*/) 3794 { 3795 struct procstat *ps; 3796 struct procstat *psend; 3797 3798 psend = jp->ps + jp->nprocs; 3799 for (ps = jp->ps + 1; ps < psend; ps++) 3800 printf(" | %s", ps->ps_cmd); 3801 outcslow('\n', stdout); 3542 3802 flush_stdout_stderr(); 3543 3803 } … … 3556 3816 goto out; 3557 3817 jp->state = JOBRUNNING; 3558 pgid = jp->ps ->pid;3818 pgid = jp->ps[0].ps_pid; 3559 3819 if (mode == FORK_FG) 3560 3820 xtcsetpgrp(ttyfd, pgid); … … 3563 3823 i = jp->nprocs; 3564 3824 do { 3565 if (WIFSTOPPED(ps-> status)) {3566 ps-> status = -1;3825 if (WIFSTOPPED(ps->ps_status)) { 3826 ps->ps_status = -1; 3567 3827 } 3568 3828 ps++; … … 3574 3834 } 3575 3835 3576 static int 3577 fg_bgcmd(int argc , char **argv)3836 static int FAST_FUNC 3837 fg_bgcmd(int argc UNUSED_PARAM, char **argv) 3578 3838 { 3579 3839 struct job *jp; 3580 FILE *out;3581 3840 int mode; 3582 3841 int retval; … … 3585 3844 nextopt(nullstr); 3586 3845 argv = argptr; 3587 out = stdout;3588 3846 do { 3589 3847 jp = getjob(*argv, 1); 3590 3848 if (mode == FORK_BG) { 3591 3849 set_curjob(jp, CUR_RUNNING); 3592 fprintf(out,"[%d] ", jobno(jp));3593 } 3594 out str(jp->ps->cmd, out);3595 showpipe(jp , out);3850 printf("[%d] ", jobno(jp)); 3851 } 3852 out1str(jp->ps[0].ps_cmd); 3853 showpipe(jp /*, stdout*/); 3596 3854 retval = restartjob(jp, mode); 3597 3855 } while (*argv && *++argv); … … 3638 3896 } 3639 3897 3640 /*3641 * Do a wait system call. If job control is compiled in, we accept3642 * stopped processes. If block is zero, we return a value of zero3643 * rather than blocking.3644 *3645 * System V doesn't have a non-blocking wait system call. It does3646 * have a SIGCLD signal that is sent to a process when one of it's3647 * children dies. The obvious way to use SIGCLD would be to install3648 * a handler for SIGCLD which simply bumped a counter when a SIGCLD3649 * was received, and have waitproc bump another counter when it got3650 * the status of a process. Waitproc would then know that a wait3651 * system call would not block if the two counters were different.3652 * This approach doesn't work because if a process has children that3653 * have not been waited for, System V will send it a SIGCLD when it3654 * installs a signal handler for SIGCLD. What this means is that when3655 * a child exits, the shell will be sent SIGCLD signals continuously3656 * until is runs out of stack space, unless it does a wait call before3657 * restoring the signal handler. The code below takes advantage of3658 * this (mis)feature by installing a signal handler for SIGCLD and3659 * then checking to see whether it was called. If there are any3660 * children to be waited for, it will be.3661 *3662 * If neither SYSV nor BSD is defined, we don't implement nonblocking3663 * waits at all. In this case, the user will not be informed when3664 * a background process until the next time she runs a real program3665 * (as opposed to running a builtin command or just typing return),3666 * and the jobs command may give out of date information.3667 */3668 3898 static int 3669 waitproc(int block, int *status) 3670 { 3671 int flags = 0; 3672 3673 #if JOBS 3674 if (jobctl) 3675 flags |= WUNTRACED; 3676 #endif 3677 if (block == 0) 3678 flags |= WNOHANG; 3679 return wait3(status, flags, (struct rusage *)NULL); 3680 } 3681 3682 /* 3683 * Wait for a process to terminate. 3684 */ 3685 static int 3686 dowait(int block, struct job *job) 3899 dowait(int wait_flags, struct job *job) 3687 3900 { 3688 3901 int pid; … … 3692 3905 int state; 3693 3906 3694 TRACE(("dowait(%d) called\n", block)); 3695 pid = waitproc(block, &status); 3696 TRACE(("wait returns pid %d, status=%d\n", pid, status)); 3907 TRACE(("dowait(0x%x) called\n", wait_flags)); 3908 3909 /* Do a wait system call. If job control is compiled in, we accept 3910 * stopped processes. wait_flags may have WNOHANG, preventing blocking. 3911 * NB: _not_ safe_waitpid, we need to detect EINTR */ 3912 if (doing_jobctl) 3913 wait_flags |= WUNTRACED; 3914 pid = waitpid(-1, &status, wait_flags); 3915 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 3916 pid, status, errno, strerror(errno))); 3697 3917 if (pid <= 0) 3698 3918 return pid; 3919 3699 3920 INT_OFF; 3700 3921 thisjob = NULL; 3701 3922 for (jp = curjob; jp; jp = jp->prev_job) { 3702 struct procstat * sp;3703 struct procstat * spend;3923 struct procstat *ps; 3924 struct procstat *psend; 3704 3925 if (jp->state == JOBDONE) 3705 3926 continue; 3706 3927 state = JOBDONE; 3707 spend = jp->ps + jp->nprocs;3708 sp = jp->ps;3928 ps = jp->ps; 3929 psend = ps + jp->nprocs; 3709 3930 do { 3710 if ( sp->pid == pid) {3931 if (ps->ps_pid == pid) { 3711 3932 TRACE(("Job %d: changing status of proc %d " 3712 3933 "from 0x%x to 0x%x\n", 3713 jobno(jp), pid, sp->status, status));3714 sp->status = status;3934 jobno(jp), pid, ps->ps_status, status)); 3935 ps->ps_status = status; 3715 3936 thisjob = jp; 3716 3937 } 3717 if ( sp->status == -1)3938 if (ps->ps_status == -1) 3718 3939 state = JOBRUNNING; 3719 3940 #if JOBS 3720 3941 if (state == JOBRUNNING) 3721 3942 continue; 3722 if (WIFSTOPPED( sp->status)) {3723 jp->stopstatus = sp->status;3943 if (WIFSTOPPED(ps->ps_status)) { 3944 jp->stopstatus = ps->ps_status; 3724 3945 state = JOBSTOPPED; 3725 3946 } 3726 3947 #endif 3727 } while (++ sp < spend);3948 } while (++ps < psend); 3728 3949 if (thisjob) 3729 3950 goto gotjob; … … 3732 3953 if (!WIFSTOPPED(status)) 3733 3954 #endif 3734 3735 3955 jobless--; 3736 3956 goto out; … … 3762 3982 if (len) { 3763 3983 s[len] = '\n'; 3764 s[len + 1] = 0;3984 s[len + 1] = '\0'; 3765 3985 out2str(s); 3766 3986 } 3767 3987 } 3988 return pid; 3989 } 3990 3991 static int 3992 blocking_wait_with_raise_on_sig(void) 3993 { 3994 pid_t pid = dowait(DOWAIT_BLOCK, NULL); 3995 if (pid <= 0 && pending_sig) 3996 raise_exception(EXSIG); 3768 3997 return pid; 3769 3998 } … … 3781 4010 ps = jp->ps; 3782 4011 3783 if (mode & SHOW_ PGID) {4012 if (mode & SHOW_ONLY_PGID) { /* jobs -p */ 3784 4013 /* just output process (group) id of pipeline */ 3785 fprintf(out, "%d\n", ps->p id);4014 fprintf(out, "%d\n", ps->ps_pid); 3786 4015 return; 3787 4016 } … … 3791 4020 3792 4021 if (jp == curjob) 3793 s[col - 2] = '+';4022 s[col - 3] = '+'; 3794 4023 else if (curjob && jp == curjob->prev_job) 3795 s[col - 2] = '-';3796 3797 if (mode & SHOW_PID )3798 col += fmtstr(s + col, 16, "%d ", ps->p id);4024 s[col - 3] = '-'; 4025 4026 if (mode & SHOW_PIDS) 4027 col += fmtstr(s + col, 16, "%d ", ps->ps_pid); 3799 4028 3800 4029 psend = ps + jp->nprocs; … … 3804 4033 col += sizeof("Running") - 1; 3805 4034 } else { 3806 int status = psend[-1]. status;4035 int status = psend[-1].ps_status; 3807 4036 if (jp->state == JOBSTOPPED) 3808 4037 status = jp->stopstatus; 3809 4038 col += sprint_status(s + col, status, 0); 3810 4039 } 3811 4040 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ 4041 4042 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line 4043 * or prints several "PID | <cmdN>" lines, 4044 * depending on SHOW_PIDS bit. 4045 * We do not print status of individual processes 4046 * between PID and <cmdN>. bash does it, but not very well: 4047 * first line shows overall job status, not process status, 4048 * making it impossible to know 1st process status. 4049 */ 3812 4050 goto start; 3813 3814 4051 do { 3815 4052 /* for each process */ 3816 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3; 4053 s[0] = '\0'; 4054 col = 33; 4055 if (mode & SHOW_PIDS) 4056 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; 3817 4057 start: 3818 fprintf(out, "%s%*c%s", 3819 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd 4058 fprintf(out, "%s%*c%s%s", 4059 s, 4060 33 - col >= 0 ? 33 - col : 0, ' ', 4061 ps == jp->ps ? "" : "| ", 4062 ps->ps_cmd 3820 4063 ); 3821 if (!(mode & SHOW_PID)) { 3822 showpipe(jp, out); 3823 break; 3824 } 3825 if (++ps == psend) { 3826 outcslow('\n', out); 3827 break; 3828 } 3829 } while (1); 4064 } while (++ps != psend); 4065 outcslow('\n', out); 3830 4066 3831 4067 jp->changed = 0; … … 3846 4082 struct job *jp; 3847 4083 3848 TRACE(("showjobs( %x) called\n", mode));3849 3850 /* If not even one one job changed, there is nothing to do*/3851 while (dowait(DOWAIT_NO RMAL, NULL) > 0)4084 TRACE(("showjobs(0x%x) called\n", mode)); 4085 4086 /* Handle all finished jobs */ 4087 while (dowait(DOWAIT_NONBLOCK, NULL) > 0) 3852 4088 continue; 3853 4089 … … 3859 4095 } 3860 4096 3861 static int 3862 jobscmd(int argc , char **argv)4097 static int FAST_FUNC 4098 jobscmd(int argc UNUSED_PARAM, char **argv) 3863 4099 { 3864 4100 int mode, m; 3865 4101 3866 4102 mode = 0; 3867 while ((m = nextopt("lp")) ) {4103 while ((m = nextopt("lp")) != '\0') { 3868 4104 if (m == 'l') 3869 mode = SHOW_PID;4105 mode |= SHOW_PIDS; 3870 4106 else 3871 mode = SHOW_PGID;4107 mode |= SHOW_ONLY_PGID; 3872 4108 } 3873 4109 … … 3875 4111 if (*argv) { 3876 4112 do 3877 showjob(stdout, getjob(*argv, 0), mode);4113 showjob(stdout, getjob(*argv, 0), mode); 3878 4114 while (*++argv); 3879 } else 4115 } else { 3880 4116 showjobs(stdout, mode); 4117 } 3881 4118 3882 4119 return 0; … … 3884 4121 #endif /* JOBS */ 3885 4122 4123 /* Called only on finished or stopped jobs (no members are running) */ 3886 4124 static int 3887 4125 getstatus(struct job *job) … … 3889 4127 int status; 3890 4128 int retval; 3891 3892 status = job->ps[job->nprocs - 1].status; 4129 struct procstat *ps; 4130 4131 /* Fetch last member's status */ 4132 ps = job->ps + job->nprocs - 1; 4133 status = ps->ps_status; 4134 if (pipefail) { 4135 /* "set -o pipefail" mode: use last _nonzero_ status */ 4136 while (status == 0 && --ps >= job->ps) 4137 status = ps->ps_status; 4138 } 4139 3893 4140 retval = WEXITSTATUS(status); 3894 4141 if (!WIFEXITED(status)) { … … 3907 4154 retval += 128; 3908 4155 } 3909 TRACE(("getstatus: job %d, nproc %d, status %x, retval%x\n",4156 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n", 3910 4157 jobno(job), job->nprocs, status, retval)); 3911 4158 return retval; 3912 4159 } 3913 4160 3914 static int 3915 waitcmd(int argc , char **argv)4161 static int FAST_FUNC 4162 waitcmd(int argc UNUSED_PARAM, char **argv) 3916 4163 { 3917 4164 struct job *job; … … 3919 4166 struct job *jp; 3920 4167 3921 EXSIGON; 4168 if (pending_sig) 4169 raise_exception(EXSIG); 3922 4170 3923 4171 nextopt(nullstr); … … 3930 4178 jp = curjob; 3931 4179 while (1) { 3932 if (!jp) { 3933 /* no running procs */ 3934 goto out; 3935 } 4180 if (!jp) /* no running procs */ 4181 goto ret; 3936 4182 if (jp->state == JOBRUNNING) 3937 4183 break; … … 3939 4185 jp = jp->prev_job; 3940 4186 } 3941 dowait(DOWAIT_BLOCK, 0); 4187 blocking_wait_with_raise_on_sig(); 4188 /* man bash: 4189 * "When bash is waiting for an asynchronous command via 4190 * the wait builtin, the reception of a signal for which a trap 4191 * has been set will cause the wait builtin to return immediately 4192 * with an exit status greater than 128, immediately after which 4193 * the trap is executed." 4194 * 4195 * blocking_wait_with_raise_on_sig raises signal handlers 4196 * if it gets no pid (pid < 0). However, 4197 * if child sends us a signal *and immediately exits*, 4198 * blocking_wait_with_raise_on_sig gets pid > 0 4199 * and does not handle pending_sig. Check this case: */ 4200 if (pending_sig) 4201 raise_exception(EXSIG); 3942 4202 } 3943 4203 } … … 3948 4208 pid_t pid = number(*argv); 3949 4209 job = curjob; 3950 goto start; 3951 do { 3952 if (job->ps[job->nprocs - 1].pid == pid) 4210 while (1) { 4211 if (!job) 4212 goto repeat; 4213 if (job->ps[job->nprocs - 1].ps_pid == pid) 3953 4214 break; 3954 4215 job = job->prev_job; 3955 start: 3956 if (!job) 3957 goto repeat; 3958 } while (1); 4216 } 3959 4217 } else 3960 4218 job = getjob(*argv, 0); 3961 4219 /* loop until process terminated or stopped */ 3962 4220 while (job->state == JOBRUNNING) 3963 dowait(DOWAIT_BLOCK, 0);4221 blocking_wait_with_raise_on_sig(); 3964 4222 job->waited = 1; 3965 4223 retval = getstatus(job); 3966 repeat: 3967 ; 4224 repeat: ; 3968 4225 } while (*++argv); 3969 4226 3970 out:4227 ret: 3971 4228 return retval; 3972 4229 } … … 4020 4277 */ 4021 4278 static struct job * 4022 makejob( union node *node,int nprocs)4279 makejob(/*union node *node,*/ int nprocs) 4023 4280 { 4024 4281 int i; … … 4035 4292 continue; 4036 4293 #if JOBS 4037 if ( jobctl)4294 if (doing_jobctl) 4038 4295 continue; 4039 4296 #endif … … 4045 4302 /* jp->jobctl is a bitfield. 4046 4303 * "jp->jobctl |= jobctl" likely to give awful code */ 4047 if ( jobctl)4304 if (doing_jobctl) 4048 4305 jp->jobctl = 1; 4049 4306 #endif … … 4055 4312 jp->ps = ckmalloc(nprocs * sizeof(struct procstat)); 4056 4313 } 4057 TRACE(("makejob( 0x%lx, %d) returns %%%d\n", (long)node, nprocs,4314 TRACE(("makejob(%d) returns %%%d\n", nprocs, 4058 4315 jobno(jp))); 4059 4316 return jp; … … 4070 4327 cmdputs(const char *s) 4071 4328 { 4072 const char *p, *str; 4073 char c, cc[2] = " "; 4074 char *nextc; 4075 int subtype = 0; 4076 int quoted = 0; 4077 static const char vstype[VSTYPE + 1][4] = { 4329 static const char vstype[VSTYPE + 1][3] = { 4078 4330 "", "}", "-", "+", "?", "=", 4079 4331 "%", "%%", "#", "##" 4332 IF_ASH_BASH_COMPAT(, ":", "/", "//") 4080 4333 }; 4081 4334 4335 const char *p, *str; 4336 char cc[2]; 4337 char *nextc; 4338 unsigned char c; 4339 unsigned char subtype = 0; 4340 int quoted = 0; 4341 4342 cc[1] = '\0'; 4082 4343 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); 4083 4344 p = s; 4084 while ((c = *p++) != 0) {4085 str = 0;4345 while ((c = *p++) != '\0') { 4346 str = NULL; 4086 4347 switch (c) { 4087 4348 case CTLESC: … … 4110 4371 str = "\"$(...)\""; 4111 4372 goto dostr; 4112 #if ENABLE_ ASH_MATH_SUPPORT4373 #if ENABLE_SH_MATH_SUPPORT 4113 4374 case CTLARI: 4114 4375 str = "$(("; … … 4150 4411 continue; 4151 4412 dostr: 4152 while ((c = *str++) ) {4413 while ((c = *str++) != '\0') { 4153 4414 USTPUTC(c, nextc); 4154 4415 } 4155 } 4416 } /* while *p++ not NUL */ 4417 4156 4418 if (quoted & 1) { 4157 4419 USTPUTC('"', nextc); … … 4182 4444 struct nodelist *lp; 4183 4445 const char *p; 4184 char s[2];4185 4446 4186 4447 if (!n) … … 4228 4489 cmdtxt(n->nif.test); 4229 4490 cmdputs("; then "); 4230 n = n->nif.ifpart;4231 4491 if (n->nif.elsepart) { 4232 cmdtxt(n );4492 cmdtxt(n->nif.ifpart); 4233 4493 cmdputs("; else "); 4234 4494 n = n->nif.elsepart; 4495 } else { 4496 n = n->nif.ifpart; 4235 4497 } 4236 4498 p = "; fi"; … … 4302 4564 p = ">>"; 4303 4565 goto redir; 4566 #if ENABLE_ASH_BASH_COMPAT 4567 case NTO2: 4568 #endif 4304 4569 case NTOFD: 4305 4570 p = ">&"; … … 4314 4579 p = "<>"; 4315 4580 redir: 4316 s[0] = n->nfile.fd + '0'; 4317 s[1] = '\0'; 4318 cmdputs(s); 4581 cmdputs(utoa(n->nfile.fd)); 4319 4582 cmdputs(p); 4320 4583 if (n->type == NTOFD || n->type == NFROMFD) { 4321 s[0] = n->ndup.dupfd + '0'; 4322 p = s; 4323 goto dotail2; 4584 cmdputs(utoa(n->ndup.dupfd)); 4585 break; 4324 4586 } 4325 4587 n = n->nfile.fname; … … 4367 4629 4368 4630 for (tp = trap; tp < &trap[NSIG]; tp++) { 4369 if (*tp && **tp) { /* trap not NULL or SIG_IGN*/4631 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ 4370 4632 INT_OFF; 4371 free(*tp); 4633 if (trap_ptr == trap) 4634 free(*tp); 4635 /* else: it "belongs" to trap_ptr vector, don't free */ 4372 4636 *tp = NULL; 4373 if ( tp != &trap[0])4637 if ((tp - trap) != 0) 4374 4638 setsignal(tp - trap); 4375 4639 INT_ON; 4376 4640 } 4377 4641 } 4642 may_have_traps = 0; 4378 4643 } 4379 4644 … … 4382 4647 4383 4648 /* Called after fork(), in child */ 4384 static void4649 static NOINLINE void 4385 4650 forkchild(struct job *jp, union node *n, int mode) 4386 4651 { … … 4391 4656 shlvl++; 4392 4657 4658 /* man bash: "Non-builtin commands run by bash have signal handlers 4659 * set to the values inherited by the shell from its parent". 4660 * Do we do it correctly? */ 4661 4393 4662 closescript(); 4663 4664 if (mode == FORK_NOJOB /* is it `xxx` ? */ 4665 && n && n->type == NCMD /* is it single cmd? */ 4666 /* && n->ncmd.args->type == NARG - always true? */ 4667 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0 4668 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ 4669 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ 4670 ) { 4671 TRACE(("Trap hack\n")); 4672 /* Awful hack for `trap` or $(trap). 4673 * 4674 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html 4675 * contains an example where "trap" is executed in a subshell: 4676 * 4677 * save_traps=$(trap) 4678 * ... 4679 * eval "$save_traps" 4680 * 4681 * Standard does not say that "trap" in subshell shall print 4682 * parent shell's traps. It only says that its output 4683 * must have suitable form, but then, in the above example 4684 * (which is not supposed to be normative), it implies that. 4685 * 4686 * bash (and probably other shell) does implement it 4687 * (traps are reset to defaults, but "trap" still shows them), 4688 * but as a result, "trap" logic is hopelessly messed up: 4689 * 4690 * # trap 4691 * trap -- 'echo Ho' SIGWINCH <--- we have a handler 4692 * # (trap) <--- trap is in subshell - no output (correct, traps are reset) 4693 * # true | trap <--- trap is in subshell - no output (ditto) 4694 * # echo `true | trap` <--- in subshell - output (but traps are reset!) 4695 * trap -- 'echo Ho' SIGWINCH 4696 * # echo `(trap)` <--- in subshell in subshell - output 4697 * trap -- 'echo Ho' SIGWINCH 4698 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! 4699 * trap -- 'echo Ho' SIGWINCH 4700 * 4701 * The rules when to forget and when to not forget traps 4702 * get really complex and nonsensical. 4703 * 4704 * Our solution: ONLY bare $(trap) or `trap` is special. 4705 */ 4706 /* Save trap handler strings for trap builtin to print */ 4707 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap)); 4708 /* Fall through into clearing traps */ 4709 } 4394 4710 clear_traps(); 4395 4711 #if JOBS 4396 4712 /* do job control only in root shell */ 4397 jobctl = 0;4713 doing_jobctl = 0; 4398 4714 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 4399 4715 pid_t pgrp; … … 4402 4718 pgrp = getpid(); 4403 4719 else 4404 pgrp = jp->ps[0].p id;4405 /* This can fail because we are doing it in the parent also */4406 (void)setpgid(0, pgrp);4720 pgrp = jp->ps[0].ps_pid; 4721 /* this can fail because we are doing it in the parent also */ 4722 setpgid(0, pgrp); 4407 4723 if (mode == FORK_FG) 4408 4724 xtcsetpgrp(ttyfd, pgrp); … … 4412 4728 #endif 4413 4729 if (mode == FORK_BG) { 4730 /* man bash: "When job control is not in effect, 4731 * asynchronous commands ignore SIGINT and SIGQUIT" */ 4414 4732 ignoresig(SIGINT); 4415 4733 ignoresig(SIGQUIT); … … 4417 4735 close(0); 4418 4736 if (open(bb_dev_null, O_RDONLY) != 0) 4419 ash_msg_and_raise_error("can't open %s", bb_dev_null); 4420 } 4421 } 4422 if (!oldlvl && iflag) { 4423 setsignal(SIGINT); 4737 ash_msg_and_raise_error("can't open '%s'", bb_dev_null); 4738 } 4739 } 4740 if (!oldlvl) { 4741 if (iflag) { /* why if iflag only? */ 4742 setsignal(SIGINT); 4743 setsignal(SIGTERM); 4744 } 4745 /* man bash: 4746 * "In all cases, bash ignores SIGQUIT. Non-builtin 4747 * commands run by bash have signal handlers 4748 * set to the values inherited by the shell 4749 * from its parent". 4750 * Take care of the second rule: */ 4424 4751 setsignal(SIGQUIT); 4425 setsignal(SIGTERM); 4426 } 4752 } 4753 #if JOBS 4754 if (n && n->type == NCMD 4755 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0 4756 ) { 4757 TRACE(("Job hack\n")); 4758 /* "jobs": we do not want to clear job list for it, 4759 * instead we remove only _its_ own_ job from job list. 4760 * This makes "jobs .... | cat" more useful. 4761 */ 4762 freejob(curjob); 4763 return; 4764 } 4765 #endif 4427 4766 for (jp = curjob; jp; jp = jp->prev_job) 4428 4767 freejob(jp); … … 4431 4770 4432 4771 /* Called after fork(), in parent */ 4772 #if !JOBS 4773 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 4774 #endif 4433 4775 static void 4434 4776 forkparent(struct job *jp, union node *n, int mode, pid_t pid) … … 4436 4778 TRACE(("In parent shell: child = %d\n", pid)); 4437 4779 if (!jp) { 4438 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0); 4780 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 4781 continue; 4439 4782 jobless++; 4440 4783 return; … … 4447 4790 pgrp = pid; 4448 4791 else 4449 pgrp = jp->ps[0].p id;4792 pgrp = jp->ps[0].ps_pid; 4450 4793 /* This can fail because we are doing it in the child also */ 4451 4794 setpgid(pid, pgrp); … … 4458 4801 if (jp) { 4459 4802 struct procstat *ps = &jp->ps[jp->nprocs++]; 4460 ps->p id = pid;4461 ps-> status = -1;4462 ps-> cmd = nullstr;4803 ps->ps_pid = pid; 4804 ps->ps_status = -1; 4805 ps->ps_cmd = nullstr; 4463 4806 #if JOBS 4464 if ( jobctl && n)4465 ps-> cmd = commandtext(n);4807 if (doing_jobctl && n) 4808 ps->ps_cmd = commandtext(n); 4466 4809 #endif 4467 4810 } … … 4479 4822 if (jp) 4480 4823 freejob(jp); 4481 ash_msg_and_raise_error("cannot fork"); 4482 } 4483 if (pid == 0) 4824 ash_msg_and_raise_error("can't fork"); 4825 } 4826 if (pid == 0) { 4827 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ 4484 4828 forkchild(jp, n, mode); 4485 else4829 } else { 4486 4830 forkparent(jp, n, mode, pid); 4831 } 4487 4832 return pid; 4488 4833 } … … 4491 4836 * Wait for job to finish. 4492 4837 * 4493 * Under job control we have the problem that while a child process is4494 * running interrupts generated by the user are sent to the child but not4495 * to the shell. This means that an infinite loop started by an inter-4496 * a ctive user may be hard to kill. With job control turned off, an4497 * interactive user may place an interactive program inside a loop. If4498 * the interactive program catches interrupts, the user doesn't want4838 * Under job control we have the problem that while a child process 4839 * is running interrupts generated by the user are sent to the child 4840 * but not to the shell. This means that an infinite loop started by 4841 * an interactive user may be hard to kill. With job control turned off, 4842 * an interactive user may place an interactive program inside a loop. 4843 * If the interactive program catches interrupts, the user doesn't want 4499 4844 * these interrupts to also abort the loop. The approach we take here 4500 4845 * is to have the shell ignore interrupt signals while waiting for a … … 4514 4859 4515 4860 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 4861 4862 INT_OFF; 4516 4863 while (jp->state == JOBRUNNING) { 4864 /* In non-interactive shells, we _can_ get 4865 * a keyboard signal here and be EINTRed, 4866 * but we just loop back, waiting for command to complete. 4867 * 4868 * man bash: 4869 * "If bash is waiting for a command to complete and receives 4870 * a signal for which a trap has been set, the trap 4871 * will not be executed until the command completes." 4872 * 4873 * Reality is that even if trap is not set, bash 4874 * will not act on the signal until command completes. 4875 * Try this. sleep5intoff.c: 4876 * #include <signal.h> 4877 * #include <unistd.h> 4878 * int main() { 4879 * sigset_t set; 4880 * sigemptyset(&set); 4881 * sigaddset(&set, SIGINT); 4882 * sigaddset(&set, SIGQUIT); 4883 * sigprocmask(SIG_BLOCK, &set, NULL); 4884 * sleep(5); 4885 * return 0; 4886 * } 4887 * $ bash -c './sleep5intoff; echo hi' 4888 * ^C^C^C^C <--- pressing ^C once a second 4889 * $ _ 4890 * $ bash -c './sleep5intoff; echo hi' 4891 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT) 4892 * $ _ 4893 */ 4517 4894 dowait(DOWAIT_BLOCK, jp); 4518 4895 } 4896 INT_ON; 4897 4519 4898 st = getstatus(jp); 4520 4899 #if JOBS … … 4529 4908 * occurred, and if so interrupt ourselves. Yuck. - mycroft 4530 4909 */ 4531 if (jp->sigint) 4532 raise(SIGINT); 4910 if (jp->sigint) /* TODO: do the same with all signals */ 4911 raise(SIGINT); /* ... by raise(jp->sig) instead? */ 4533 4912 } 4534 4913 if (jp->state == JOBDONE) … … 4567 4946 4568 4947 #define EMPTY -2 /* marks an unused slot in redirtab */ 4569 #ifndef PIPE_BUF 4570 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 4571 #else 4572 # define PIPESIZE PIPE_BUF 4573 #endif 4948 #define CLOSED -3 /* marks a slot of previously-closed fd */ 4574 4949 4575 4950 /* … … 4621 4996 * replaced, return the file descriptor. 4622 4997 */ 4623 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) 4624 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 4998 if (fstat(fd, &finfo2) == 0 4999 && !S_ISREG(finfo2.st_mode) 5000 && finfo.st_dev == finfo2.st_dev 5001 && finfo.st_ino == finfo2.st_ino 5002 ) { 4625 5003 return fd; 5004 } 4626 5005 4627 5006 /* The file has been replaced. badness. */ … … 4648 5027 if (redir->type == NHERE) { 4649 5028 len = strlen(redir->nhere.doc->narg.text); 4650 if (len <= PIPE SIZE) {5029 if (len <= PIPE_BUF) { 4651 5030 full_write(pip[1], redir->nhere.doc->narg.text, len); 4652 5031 goto out; … … 4654 5033 } 4655 5034 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5035 /* child */ 4656 5036 close(pip[0]); 4657 signal(SIGINT, SIG_IGN); 4658 signal(SIGQUIT, SIG_IGN); 4659 signal(SIGHUP, SIG_IGN); 4660 #ifdef SIGTSTP 4661 signal(SIGTSTP, SIG_IGN); 4662 #endif 5037 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); 5038 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); 5039 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); 5040 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); 4663 5041 signal(SIGPIPE, SIG_DFL); 4664 5042 if (redir->type == NHERE) 4665 5043 full_write(pip[1], redir->nhere.doc->narg.text, len); 4666 else 5044 else /* NXHERE */ 4667 5045 expandhere(redir->nhere.doc, pip[1]); 4668 _exit( 0);5046 _exit(EXIT_SUCCESS); 4669 5047 } 4670 5048 out: … … 4688 5066 case NFROMTO: 4689 5067 fname = redir->nfile.expfname; 4690 f = open(fname, O_RDWR|O_CREAT |O_TRUNC, 0666);5068 f = open(fname, O_RDWR|O_CREAT, 0666); 4691 5069 if (f < 0) 4692 5070 goto ecreate; 4693 5071 break; 4694 5072 case NTO: 5073 #if ENABLE_ASH_BASH_COMPAT 5074 case NTO2: 5075 #endif 4695 5076 /* Take care of noclobber mode. */ 4696 5077 if (Cflag) { … … 4719 5100 #endif 4720 5101 /* Fall through to eliminate warning. */ 4721 case NTOFD: 4722 case NFROMFD: 4723 f = -1; 4724 break; 5102 /* Our single caller does this itself */ 5103 // case NTOFD: 5104 // case NFROMFD: 5105 // f = -1; 5106 // break; 4725 5107 case NHERE: 4726 5108 case NXHERE: … … 4731 5113 return f; 4732 5114 ecreate: 4733 ash_msg_and_raise_error("can not create %s: %s", fname, errmsg(errno, "nonexistent directory"));5115 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory")); 4734 5116 eopen: 4735 ash_msg_and_raise_error("can not open %s: %s", fname, errmsg(errno, "no such file"));5117 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file")); 4736 5118 } 4737 5119 … … 4741 5123 * file descriptors left. 4742 5124 */ 5125 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). 5126 * old code was doing close(to) prior to copyfd() to achieve the same */ 5127 enum { 5128 COPYFD_EXACT = (int)~(INT_MAX), 5129 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1), 5130 }; 4743 5131 static int 4744 5132 copyfd(int from, int to) … … 4746 5134 int newfd; 4747 5135 4748 newfd = fcntl(from, F_DUPFD, to); 5136 if (to & COPYFD_EXACT) { 5137 to &= ~COPYFD_EXACT; 5138 /*if (from != to)*/ 5139 newfd = dup2(from, to); 5140 } else { 5141 newfd = fcntl(from, F_DUPFD, to); 5142 } 4749 5143 if (newfd < 0) { 4750 5144 if (errno == EMFILE) 4751 5145 return EMPTY; 5146 /* Happens when source fd is not open: try "echo >&99" */ 4752 5147 ash_msg_and_raise_error("%d: %m", from); 4753 5148 } … … 4755 5150 } 4756 5151 4757 static void 4758 dupredirect(union node *redir, int f) 4759 { 4760 int fd = redir->nfile.fd; 4761 4762 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 4763 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 4764 copyfd(redir->ndup.dupfd, fd); 4765 } 4766 return; 4767 } 4768 4769 if (f != fd) { 4770 copyfd(f, fd); 4771 close(f); 4772 } 5152 /* Struct def and variable are moved down to the first usage site */ 5153 struct two_fd_t { 5154 int orig, copy; 5155 }; 5156 struct redirtab { 5157 struct redirtab *next; 5158 int nullredirs; 5159 int pair_count; 5160 struct two_fd_t two_fd[]; 5161 }; 5162 #define redirlist (G_var.redirlist) 5163 5164 static int need_to_remember(struct redirtab *rp, int fd) 5165 { 5166 int i; 5167 5168 if (!rp) /* remembering was not requested */ 5169 return 0; 5170 5171 for (i = 0; i < rp->pair_count; i++) { 5172 if (rp->two_fd[i].orig == fd) { 5173 /* already remembered */ 5174 return 0; 5175 } 5176 } 5177 return 1; 5178 } 5179 5180 /* "hidden" fd is a fd used to read scripts, or a copy of such */ 5181 static int is_hidden_fd(struct redirtab *rp, int fd) 5182 { 5183 int i; 5184 struct parsefile *pf; 5185 5186 if (fd == -1) 5187 return 0; 5188 /* Check open scripts' fds */ 5189 pf = g_parsefile; 5190 while (pf) { 5191 /* We skip pf_fd == 0 case because of the following case: 5192 * $ ash # running ash interactively 5193 * $ . ./script.sh 5194 * and in script.sh: "exec 9>&0". 5195 * Even though top-level pf_fd _is_ 0, 5196 * it's still ok to use it: "read" builtin uses it, 5197 * why should we cripple "exec" builtin? 5198 */ 5199 if (pf->pf_fd > 0 && fd == pf->pf_fd) { 5200 return 1; 5201 } 5202 pf = pf->prev; 5203 } 5204 5205 if (!rp) 5206 return 0; 5207 /* Check saved fds of redirects */ 5208 fd |= COPYFD_RESTORE; 5209 for (i = 0; i < rp->pair_count; i++) { 5210 if (rp->two_fd[i].copy == fd) { 5211 return 1; 5212 } 5213 } 5214 return 0; 4773 5215 } 4774 5216 … … 4776 5218 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 4777 5219 * old file descriptors are stashed away so that the redirection can be 4778 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 4779 * standard output, and the standard error if it becomes a duplicate of 4780 * stdout, is saved in memory. 5220 * undone by calling popredir. 4781 5221 */ 4782 5222 /* flags passed to redirect */ … … 4786 5226 redirect(union node *redir, int flags) 4787 5227 { 4788 union node *n;4789 5228 struct redirtab *sv; 5229 int sv_pos; 4790 5230 int i; 4791 5231 int fd; 4792 5232 int newfd; 4793 int *p; 4794 nullredirs++; 5233 int copied_fd2 = -1; 5234 5235 g_nullredirs++; 4795 5236 if (!redir) { 4796 5237 return; 4797 5238 } 5239 4798 5240 sv = NULL; 5241 sv_pos = 0; 4799 5242 INT_OFF; 4800 5243 if (flags & REDIR_PUSH) { 4801 struct redirtab *q; 4802 q = ckmalloc(sizeof(struct redirtab)); 4803 q->next = redirlist; 4804 redirlist = q; 4805 q->nullredirs = nullredirs - 1; 4806 for (i = 0; i < 10; i++) 4807 q->renamed[i] = EMPTY; 4808 nullredirs = 0; 4809 sv = q; 4810 } 4811 n = redir; 5244 union node *tmp = redir; 5245 do { 5246 sv_pos++; 5247 #if ENABLE_ASH_BASH_COMPAT 5248 if (tmp->nfile.type == NTO2) 5249 sv_pos++; 5250 #endif 5251 tmp = tmp->nfile.next; 5252 } while (tmp); 5253 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0])); 5254 sv->next = redirlist; 5255 sv->pair_count = sv_pos; 5256 redirlist = sv; 5257 sv->nullredirs = g_nullredirs - 1; 5258 g_nullredirs = 0; 5259 while (sv_pos > 0) { 5260 sv_pos--; 5261 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY; 5262 } 5263 } 5264 4812 5265 do { 4813 fd = n->nfile.fd; 4814 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) 4815 && n->ndup.dupfd == fd) 4816 continue; /* redirect from/to same file descriptor */ 4817 4818 newfd = openredirect(n); 4819 if (fd == newfd) 4820 continue; 4821 if (sv && *(p = &sv->renamed[fd]) == EMPTY) { 4822 i = fcntl(fd, F_DUPFD, 10); 4823 5266 int right_fd = -1; 5267 fd = redir->nfile.fd; 5268 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 5269 right_fd = redir->ndup.dupfd; 5270 //bb_error_msg("doing %d > %d", fd, right_fd); 5271 /* redirect from/to same file descriptor? */ 5272 if (right_fd == fd) 5273 continue; 5274 /* "echo >&10" and 10 is a fd opened to a sh script? */ 5275 if (is_hidden_fd(sv, right_fd)) { 5276 errno = EBADF; /* as if it is closed */ 5277 ash_msg_and_raise_error("%d: %m", right_fd); 5278 } 5279 newfd = -1; 5280 } else { 5281 newfd = openredirect(redir); /* always >= 0 */ 5282 if (fd == newfd) { 5283 /* Descriptor wasn't open before redirect. 5284 * Mark it for close in the future */ 5285 if (need_to_remember(sv, fd)) { 5286 goto remember_to_close; 5287 } 5288 continue; 5289 } 5290 } 5291 #if ENABLE_ASH_BASH_COMPAT 5292 redirect_more: 5293 #endif 5294 if (need_to_remember(sv, fd)) { 5295 /* Copy old descriptor */ 5296 /* Careful to not accidentally "save" 5297 * to the same fd as right side fd in N>&M */ 5298 int minfd = right_fd < 10 ? 10 : right_fd + 1; 5299 i = fcntl(fd, F_DUPFD, minfd); 5300 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds 5301 * are closed in popredir() in the child, preventing them from leaking 5302 * into child. (popredir() also cleans up the mess in case of failures) 5303 */ 4824 5304 if (i == -1) { 4825 5305 i = errno; 4826 5306 if (i != EBADF) { 4827 close(newfd); 5307 /* Strange error (e.g. "too many files" EMFILE?) */ 5308 if (newfd >= 0) 5309 close(newfd); 4828 5310 errno = i; 4829 5311 ash_msg_and_raise_error("%d: %m", fd); 4830 5312 /* NOTREACHED */ 4831 5313 } 5314 /* EBADF: it is not open - good, remember to close it */ 5315 remember_to_close: 5316 i = CLOSED; 5317 } else { /* fd is open, save its copy */ 5318 /* "exec fd>&-" should not close fds 5319 * which point to script file(s). 5320 * Force them to be restored afterwards */ 5321 if (is_hidden_fd(sv, fd)) 5322 i |= COPYFD_RESTORE; 5323 } 5324 if (fd == 2) 5325 copied_fd2 = i; 5326 sv->two_fd[sv_pos].orig = fd; 5327 sv->two_fd[sv_pos].copy = i; 5328 sv_pos++; 5329 } 5330 if (newfd < 0) { 5331 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */ 5332 if (redir->ndup.dupfd < 0) { /* "fd>&-" */ 5333 /* Don't want to trigger debugging */ 5334 if (fd != -1) 5335 close(fd); 4832 5336 } else { 4833 *p = i; 4834 close(fd); 5337 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); 4835 5338 } 4836 } else { 4837 close(fd); 4838 } 4839 dupredirect(n, newfd); 4840 } while ((n = n->nfile.next)); 5339 } else if (fd != newfd) { /* move newfd to fd */ 5340 copyfd(newfd, fd | COPYFD_EXACT); 5341 #if ENABLE_ASH_BASH_COMPAT 5342 if (!(redir->nfile.type == NTO2 && fd == 2)) 5343 #endif 5344 close(newfd); 5345 } 5346 #if ENABLE_ASH_BASH_COMPAT 5347 if (redir->nfile.type == NTO2 && fd == 1) { 5348 /* We already redirected it to fd 1, now copy it to 2 */ 5349 newfd = 1; 5350 fd = 2; 5351 goto redirect_more; 5352 } 5353 #endif 5354 } while ((redir = redir->nfile.next) != NULL); 5355 4841 5356 INT_ON; 4842 if ( flags & REDIR_SAVEFD2 && sv && sv->renamed[2]>= 0)4843 preverrout_fd = sv->renamed[2];5357 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0) 5358 preverrout_fd = copied_fd2; 4844 5359 } 4845 5360 … … 4848 5363 */ 4849 5364 static void 4850 popredir(int drop )5365 popredir(int drop, int restore) 4851 5366 { 4852 5367 struct redirtab *rp; 4853 5368 int i; 4854 5369 4855 if (-- nullredirs >= 0)5370 if (--g_nullredirs >= 0) 4856 5371 return; 4857 5372 INT_OFF; 4858 5373 rp = redirlist; 4859 for (i = 0; i < 10; i++) { 4860 if (rp->renamed[i] != EMPTY) { 4861 if (!drop) { 4862 close(i); 4863 copyfd(rp->renamed[i], i); 5374 for (i = 0; i < rp->pair_count; i++) { 5375 int fd = rp->two_fd[i].orig; 5376 int copy = rp->two_fd[i].copy; 5377 if (copy == CLOSED) { 5378 if (!drop) 5379 close(fd); 5380 continue; 5381 } 5382 if (copy != EMPTY) { 5383 if (!drop || (restore && (copy & COPYFD_RESTORE))) { 5384 copy &= ~COPYFD_RESTORE; 5385 /*close(fd);*/ 5386 copyfd(copy, fd | COPYFD_EXACT); 4864 5387 } 4865 close( rp->renamed[i]);5388 close(copy & ~COPYFD_RESTORE); 4866 5389 } 4867 5390 } 4868 5391 redirlist = rp->next; 4869 nullredirs = rp->nullredirs;5392 g_nullredirs = rp->nullredirs; 4870 5393 free(rp); 4871 5394 INT_ON; … … 4883 5406 { 4884 5407 for (;;) { 4885 nullredirs = 0;5408 g_nullredirs = 0; 4886 5409 if (!redirlist) 4887 5410 break; 4888 popredir(drop );5411 popredir(drop, /*restore:*/ 0); 4889 5412 } 4890 5413 } … … 4899 5422 4900 5423 SAVE_INT(saveint); 4901 err = setjmp(jmploc.loc) * 2; 5424 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */ 5425 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2; 4902 5426 if (!err) { 4903 5427 exception_handler = &jmploc; … … 4905 5429 } 4906 5430 exception_handler = savehandler; 4907 if (err && exception != EXERROR)5431 if (err && exception_type != EXERROR) 4908 5432 longjmp(exception_handler->loc, 1); 4909 5433 RESTORE_INT(saveint); … … 4916 5440 * We have to deal with backquotes, shell variables, and file metacharacters. 4917 5441 */ 5442 5443 #if ENABLE_SH_MATH_SUPPORT 5444 static arith_t 5445 ash_arith(const char *s) 5446 { 5447 arith_state_t math_state; 5448 arith_t result; 5449 5450 math_state.lookupvar = lookupvar; 5451 math_state.setvar = setvar2; 5452 //math_state.endofname = endofname; 5453 5454 INT_OFF; 5455 result = arith(&math_state, s); 5456 if (math_state.errmsg) 5457 ash_msg_and_raise_error(math_state.errmsg); 5458 INT_ON; 5459 5460 return result; 5461 } 5462 #endif 4918 5463 4919 5464 /* … … 4930 5475 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ 4931 5476 /* 4932 * _rmescape() flags5477 * rmescape() flags 4933 5478 */ 4934 5479 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ … … 4968 5513 * Our own itoa(). 4969 5514 */ 5515 #if !ENABLE_SH_MATH_SUPPORT 5516 /* cvtnum() is used even if math support is off (to prepare $? values and such) */ 5517 typedef long arith_t; 5518 # define ARITH_FMT "%ld" 5519 #endif 4970 5520 static int 4971 5521 cvtnum(arith_t num) … … 4974 5524 4975 5525 expdest = makestrspace(32, expdest); 4976 #if ENABLE_ASH_MATH_SUPPORT_64 4977 len = fmtstr(expdest, 32, "%lld", (long long) num); 4978 #else 4979 len = fmtstr(expdest, 32, "%ld", num); 4980 #endif 5526 len = fmtstr(expdest, 32, ARITH_FMT, num); 4981 5527 STADJUST(len, expdest); 4982 5528 return len; … … 4988 5534 size_t esc = 0; 4989 5535 4990 while (p > start && *--p == CTLESC) {5536 while (p > start && (unsigned char)*--p == CTLESC) { 4991 5537 esc++; 4992 5538 } … … 4998 5544 */ 4999 5545 static char * 5000 _rmescapes(char *str, int flag)5546 rmescapes(char *str, int flag) 5001 5547 { 5002 5548 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; … … 5004 5550 char *p, *q, *r; 5005 5551 unsigned inquotes; 5006 int notescaped;5007 intglobbing;5552 unsigned protect_against_glob; 5553 unsigned globbing; 5008 5554 5009 5555 p = strpbrk(str, qchars); 5010 if (!p) {5556 if (!p) 5011 5557 return str; 5012 } 5558 5013 5559 q = p; 5014 5560 r = str; … … 5018 5564 5019 5565 if (flag & RMESCAPE_GROW) { 5566 int strloc = str - (char *)stackblock(); 5020 5567 r = makestrspace(fulllen, expdest); 5568 /* p and str may be invalidated by makestrspace */ 5569 str = (char *)stackblock() + strloc; 5570 p = str + len; 5021 5571 } else if (flag & RMESCAPE_HEAP) { 5022 5572 r = ckmalloc(fulllen); … … 5026 5576 q = r; 5027 5577 if (len > 0) { 5028 q = memcpy(q, str, len) + len; 5029 } 5030 } 5578 q = (char *)memcpy(q, str, len) + len; 5579 } 5580 } 5581 5031 5582 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5032 5583 globbing = flag & RMESCAPE_GLOB; 5033 notescaped= globbing;5584 protect_against_glob = globbing; 5034 5585 while (*p) { 5035 if (*p == CTLQUOTEMARK) { 5586 if ((unsigned char)*p == CTLQUOTEMARK) { 5587 // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 5588 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? 5589 // Note: both inquotes and protect_against_glob only affect whether 5590 // CTLESC,<ch> gets converted to <ch> or to \<ch> 5036 5591 inquotes = ~inquotes; 5037 5592 p++; 5038 notescaped= globbing;5593 protect_against_glob = globbing; 5039 5594 continue; 5040 5595 } 5041 5596 if (*p == '\\') { 5042 5597 /* naked back slash */ 5043 notescaped= 0;5598 protect_against_glob = 0; 5044 5599 goto copy; 5045 5600 } 5046 if ( *p == CTLESC) {5601 if ((unsigned char)*p == CTLESC) { 5047 5602 p++; 5048 if ( notescaped&& inquotes && *p != '/') {5603 if (protect_against_glob && inquotes && *p != '/') { 5049 5604 *q++ = '\\'; 5050 5605 } 5051 5606 } 5052 notescaped= globbing;5607 protect_against_glob = globbing; 5053 5608 copy: 5054 5609 *q++ = *p++; … … 5061 5616 return r; 5062 5617 } 5063 #define rmescapes(p) _rmescapes((p), 0)5064 5065 5618 #define pmatch(a, b) !fnmatch((a), (b), 0) 5066 5619 … … 5077 5630 flag |= RMESCAPE_QUOTED; 5078 5631 } 5079 return _rmescapes((char *)pattern, flag);5632 return rmescapes((char *)pattern, flag); 5080 5633 } 5081 5634 … … 5088 5641 char *q = expdest; 5089 5642 5090 q = makestrspace( len * 2, q);5643 q = makestrspace(quotes ? len * 2 : len, q); 5091 5644 5092 5645 while (len--) { 5093 int c = signed_char2int(*p++);5094 if ( !c)5646 unsigned char c = *p++; 5647 if (c == '\0') 5095 5648 continue; 5096 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5097 USTPUTC(CTLESC, q); 5649 if (quotes) { 5650 int n = SIT(c, syntax); 5651 if (n == CCTL || n == CBACK) 5652 USTPUTC(CTLESC, q); 5653 } 5098 5654 USTPUTC(c, q); 5099 5655 } … … 5121 5677 } else { 5122 5678 INT_OFF; 5123 ifsp = ck malloc(sizeof(*ifsp));5124 ifsp->next = NULL;5679 ifsp = ckzalloc(sizeof(*ifsp)); 5680 /*ifsp->next = NULL; - ckzalloc did it */ 5125 5681 ifslastp->next = ifsp; 5126 5682 INT_ON; … … 5139 5695 5140 5696 if (ifsfirst.endoff > endoff) { 5141 while (ifsfirst.next != NULL) {5697 while (ifsfirst.next) { 5142 5698 struct ifsregion *ifsp; 5143 5699 INT_OFF; … … 5147 5703 INT_ON; 5148 5704 } 5149 if (ifsfirst.begoff > endoff) 5705 if (ifsfirst.begoff > endoff) { 5150 5706 ifslastp = NULL; 5151 else {5707 } else { 5152 5708 ifslastp = &ifsfirst; 5153 5709 ifsfirst.endoff = endoff; … … 5158 5714 ifslastp = &ifsfirst; 5159 5715 while (ifslastp->next && ifslastp->next->begoff < endoff) 5160 ifslastp =ifslastp->next;5161 while (ifslastp->next != NULL) {5716 ifslastp = ifslastp->next; 5717 while (ifslastp->next) { 5162 5718 struct ifsregion *ifsp; 5163 5719 INT_OFF; … … 5172 5728 5173 5729 static char * 5174 exptilde(char *startp, char *p, int flag )5175 { 5176 char c;5730 exptilde(char *startp, char *p, int flags) 5731 { 5732 unsigned char c; 5177 5733 char *name; 5178 5734 struct passwd *pw; 5179 5735 const char *home; 5180 int quotes = flag & (EXP_FULL | EXP_CASE);5736 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); 5181 5737 int startloc; 5182 5738 … … 5190 5746 return startp; 5191 5747 case ':': 5192 if (flag & EXP_VARTILDE)5748 if (flags & EXP_VARTILDE) 5193 5749 goto done; 5194 5750 break; … … 5201 5757 *p = '\0'; 5202 5758 if (*name == '\0') { 5203 home = lookupvar( homestr);5759 home = lookupvar("HOME"); 5204 5760 } else { 5205 5761 pw = getpwnam(name); … … 5228 5784 struct backcmd { /* result of evalbackcmd */ 5229 5785 int fd; /* file descriptor to read from */ 5786 int nleft; /* number of chars in buffer */ 5230 5787 char *buf; /* buffer */ 5231 int nleft; /* number of chars in buffer */5232 5788 struct job *jp; /* job structure for command */ 5233 5789 }; 5234 5790 5235 5791 /* These forward decls are needed to use "eval" code for backticks handling: */ 5236 static int back_exitstatus; /* exit status of backquoted command */5792 static uint8_t back_exitstatus; /* exit status of backquoted command */ 5237 5793 #define EV_EXIT 01 /* exit after evaluating tree */ 5238 5794 static void evaltree(union node *, int); 5239 5795 5240 static void 5796 static void FAST_FUNC 5241 5797 evalbackcmd(union node *n, struct backcmd *result) 5242 5798 { … … 5247 5803 result->nleft = 0; 5248 5804 result->jp = NULL; 5249 if (n == NULL) {5805 if (n == NULL) 5250 5806 goto out; 5251 }5252 5807 5253 5808 saveherefd = herefd; … … 5260 5815 if (pipe(pip) < 0) 5261 5816 ash_msg_and_raise_error("pipe call failed"); 5262 jp = makejob( n,1);5817 jp = makejob(/*n,*/ 1); 5263 5818 if (forkshell(jp, n, FORK_NOJOB) == 0) { 5264 5819 FORCE_INT_ON; 5265 5820 close(pip[0]); 5266 5821 if (pip[1] != 1) { 5267 close(1);5268 copyfd(pip[1], 1 );5822 /*close(1);*/ 5823 copyfd(pip[1], 1 | COPYFD_EXACT); 5269 5824 close(pip[1]); 5270 5825 } … … 5295 5850 char *dest; 5296 5851 int startloc; 5297 int syntax = quoted ? DQSYNTAX : BASESYNTAX;5852 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 5298 5853 struct stackmark smark; 5299 5854 … … 5315 5870 if (in.fd < 0) 5316 5871 break; 5317 i = safe_read(in.fd, buf, sizeof(buf));5872 i = nonblock_safe_read(in.fd, buf, sizeof(buf)); 5318 5873 TRACE(("expbackq: read returns %d\n", i)); 5319 5874 if (i <= 0) … … 5322 5877 } 5323 5878 5324 if (in.buf) 5325 free(in.buf); 5879 free(in.buf); 5326 5880 if (in.fd >= 0) { 5327 5881 close(in.fd); … … 5338 5892 if (quoted == 0) 5339 5893 recordregion(startloc, dest - (char *)stackblock(), 0); 5340 TRACE(("evalbackq: size =%d: \"%.*s\"\n",5341 ( dest - (char *)stackblock()) - startloc,5342 ( dest - (char *)stackblock()) - startloc,5894 TRACE(("evalbackq: size:%d:'%.*s'\n", 5895 (int)((dest - (char *)stackblock()) - startloc), 5896 (int)((dest - (char *)stackblock()) - startloc), 5343 5897 stackblock() + startloc)); 5344 5898 } 5345 5899 5346 #if ENABLE_ ASH_MATH_SUPPORT5900 #if ENABLE_SH_MATH_SUPPORT 5347 5901 /* 5348 5902 * Expand arithmetic expression. Backup to start of expression, … … 5357 5911 int len; 5358 5912 5359 /* 5913 /* ifsfree(); */ 5360 5914 5361 5915 /* … … 5371 5925 int esc; 5372 5926 5373 while ( *p != CTLARI) {5927 while ((unsigned char)*p != CTLARI) { 5374 5928 p--; 5375 5929 #if DEBUG … … 5397 5951 5398 5952 if (quotes) 5399 rmescapes(p + 2 );5400 5401 len = cvtnum( dash_arith(p + 2));5953 rmescapes(p + 2, 0); 5954 5955 len = cvtnum(ash_arith(p + 2)); 5402 5956 5403 5957 if (flag != '"') … … 5407 5961 5408 5962 /* argstr needs it */ 5409 static char *evalvar(char *p, int flag );5963 static char *evalvar(char *p, int flags, struct strlist *var_str_list); 5410 5964 5411 5965 /* … … 5413 5967 * characters to allow for further processing. Otherwise treat 5414 5968 * $@ like $* since no splitting will be performed. 5969 * 5970 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence 5971 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it 5972 * for correct expansion of "B=$A" word. 5415 5973 */ 5416 5974 static void 5417 argstr(char *p, int flag )5975 argstr(char *p, int flags, struct strlist *var_str_list) 5418 5976 { 5419 5977 static const char spclchars[] ALIGN1 = { … … 5426 5984 CTLBACKQ, 5427 5985 CTLBACKQ | CTLQUOTE, 5428 #if ENABLE_ ASH_MATH_SUPPORT5986 #if ENABLE_SH_MATH_SUPPORT 5429 5987 CTLENDARI, 5430 5988 #endif 5431 05989 '\0' 5432 5990 }; 5433 5991 const char *reject = spclchars; 5434 int c; 5435 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 5436 int breakall = flag & EXP_WORD; 5992 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ 5993 int breakall = flags & EXP_WORD; 5437 5994 int inquotes; 5438 5995 size_t length; 5439 5996 int startloc; 5440 5997 5441 if (!(flag & EXP_VARTILDE)) {5998 if (!(flags & EXP_VARTILDE)) { 5442 5999 reject += 2; 5443 } else if (flag & EXP_VARTILDE2) {6000 } else if (flags & EXP_VARTILDE2) { 5444 6001 reject++; 5445 6002 } 5446 6003 inquotes = 0; 5447 6004 length = 0; 5448 if (flag & EXP_TILDE) {6005 if (flags & EXP_TILDE) { 5449 6006 char *q; 5450 6007 5451 flag &= ~EXP_TILDE;6008 flags &= ~EXP_TILDE; 5452 6009 tilde: 5453 6010 q = p; 5454 if ( *q == CTLESC && (flag& EXP_QWORD))6011 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) 5455 6012 q++; 5456 6013 if (*q == '~') 5457 p = exptilde(p, q, flag );6014 p = exptilde(p, q, flags); 5458 6015 } 5459 6016 start: 5460 6017 startloc = expdest - (char *)stackblock(); 5461 6018 for (;;) { 6019 unsigned char c; 6020 5462 6021 length += strcspn(p + length, reject); 5463 6022 c = p[length]; 5464 if (c && (!(c & 0x80)5465 #if ENABLE_ASH_MATH_SUPPORT 5466 || c == CTLENDARI5467 #endif 5468 )) {5469 /* c == '=' || c == ':' || c == CTLENDARI */5470 length++;6023 if (c) { 6024 if (!(c & 0x80) 6025 IF_SH_MATH_SUPPORT(|| c == CTLENDARI) 6026 ) { 6027 /* c == '=' || c == ':' || c == CTLENDARI */ 6028 length++; 6029 } 5471 6030 } 5472 6031 if (length > 0) { … … 5486 6045 goto breakloop; 5487 6046 case '=': 5488 if (flag & EXP_VARTILDE2) {6047 if (flags & EXP_VARTILDE2) { 5489 6048 p--; 5490 6049 continue; 5491 6050 } 5492 flag |= EXP_VARTILDE2;6051 flags |= EXP_VARTILDE2; 5493 6052 reject++; 5494 6053 /* fall through */ … … 5509 6068 case CTLQUOTEMARK: 5510 6069 /* "$@" syntax adherence hack */ 5511 if ( 5512 !inquotes && 5513 !memcmp(p, dolatstr, 4) && 5514 (p[4] == CTLQUOTEMARK || ( 5515 p[4] == CTLENDVAR && 5516 p[5] == CTLQUOTEMARK 5517 )) 6070 if (!inquotes 6071 && memcmp(p, dolatstr, 4) == 0 6072 && ( p[4] == (char)CTLQUOTEMARK 6073 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) 6074 ) 5518 6075 ) { 5519 p = evalvar(p + 1, flag ) + 1;6076 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; 5520 6077 goto start; 5521 6078 } … … 5533 6090 goto addquote; 5534 6091 case CTLVAR: 5535 p = evalvar(p, flag );6092 p = evalvar(p, flags, var_str_list); 5536 6093 goto start; 5537 6094 case CTLBACKQ: 5538 c = 0;6095 c = '\0'; 5539 6096 case CTLBACKQ|CTLQUOTE: 5540 6097 expbackq(argbackq->n, c, quotes); 5541 6098 argbackq = argbackq->next; 5542 6099 goto start; 5543 #if ENABLE_ ASH_MATH_SUPPORT6100 #if ENABLE_SH_MATH_SUPPORT 5544 6101 case CTLENDARI: 5545 6102 p--; … … 5549 6106 } 5550 6107 } 5551 breakloop: 5552 ; 6108 breakloop: ; 5553 6109 } 5554 6110 5555 6111 static char * 5556 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5557 int zero) 5558 { 5559 char *loc; 5560 char *loc2; 6112 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, 6113 char *pattern, int quotes, int zero) 6114 { 6115 char *loc, *loc2; 5561 6116 char c; 5562 6117 … … 5566 6121 int match; 5567 6122 const char *s = loc2; 6123 5568 6124 c = *loc2; 5569 6125 if (zero) { … … 5571 6127 s = rmesc; 5572 6128 } 5573 match = pmatch(str, s); 6129 match = pmatch(pattern, s); 6130 5574 6131 *loc2 = c; 5575 6132 if (match) 5576 6133 return loc; 5577 if (quotes && *loc == CTLESC)6134 if (quotes && (unsigned char)*loc == CTLESC) 5578 6135 loc++; 5579 6136 loc++; 5580 6137 loc2++; 5581 6138 } while (c); 5582 return 0;6139 return NULL; 5583 6140 } 5584 6141 5585 6142 static char * 5586 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5587 int zero) 5588 { 6143 scanright(char *startp, char *rmesc, char *rmescend, 6144 char *pattern, int quotes, int match_at_start) 6145 { 6146 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE 6147 int try2optimize = match_at_start; 6148 #endif 5589 6149 int esc = 0; 5590 6150 char *loc; 5591 6151 char *loc2; 5592 6152 5593 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 6153 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}": 6154 * startp="escaped_value_of_v" rmesc="raw_value_of_v" 6155 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1 6156 * Logic: 6157 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc, 6158 * and on each iteration they go back two/one char until they reach the beginning. 6159 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc. 6160 */ 6161 /* TODO: document in what other circumstances we are called. */ 6162 6163 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) { 5594 6164 int match; 5595 6165 char c = *loc2; 5596 6166 const char *s = loc2; 5597 if ( zero) {6167 if (match_at_start) { 5598 6168 *loc2 = '\0'; 5599 6169 s = rmesc; 5600 6170 } 5601 match = pmatch(str, s); 6171 match = pmatch(pattern, s); 6172 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match); 5602 6173 *loc2 = c; 5603 6174 if (match) 5604 6175 return loc; 6176 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE 6177 if (try2optimize) { 6178 /* Maybe we can optimize this: 6179 * if pattern ends with unescaped *, we can avoid checking 6180 * shorter strings: if "foo*" doesnt match "raw_value_of_v", 6181 * it wont match truncated "raw_value_of_" strings too. 6182 */ 6183 unsigned plen = strlen(pattern); 6184 /* Does it end with "*"? */ 6185 if (plen != 0 && pattern[--plen] == '*') { 6186 /* "xxxx*" is not escaped */ 6187 /* "xxx\*" is escaped */ 6188 /* "xx\\*" is not escaped */ 6189 /* "x\\\*" is escaped */ 6190 int slashes = 0; 6191 while (plen != 0 && pattern[--plen] == '\\') 6192 slashes++; 6193 if (!(slashes & 1)) 6194 break; /* ends with unescaped "*" */ 6195 } 6196 try2optimize = 0; 6197 } 6198 #endif 5605 6199 loc--; 5606 6200 if (quotes) { … … 5614 6208 } 5615 6209 } 5616 return 0;5617 } 5618 5619 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;6210 return NULL; 6211 } 6212 6213 static void varunset(const char *, const char *, const char *, int) NORETURN; 5620 6214 static void 5621 6215 varunset(const char *end, const char *var, const char *umsg, int varflags) … … 5627 6221 msg = "parameter not set"; 5628 6222 if (umsg) { 5629 if ( *end == CTLENDVAR) {6223 if ((unsigned char)*end == CTLENDVAR) { 5630 6224 if (varflags & VSNUL) 5631 6225 tail = " or null"; 5632 } else 6226 } else { 5633 6227 msg = umsg; 5634 } 5635 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5636 } 6228 } 6229 } 6230 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); 6231 } 6232 6233 #if ENABLE_ASH_BASH_COMPAT 6234 static char * 6235 parse_sub_pattern(char *arg, int varflags) 6236 { 6237 char *idx, *repl = NULL; 6238 unsigned char c; 6239 6240 //char *org_arg = arg; 6241 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); 6242 idx = arg; 6243 while (1) { 6244 c = *arg; 6245 if (!c) 6246 break; 6247 if (c == '/') { 6248 /* Only the first '/' seen is our separator */ 6249 if (!repl) { 6250 repl = idx + 1; 6251 c = '\0'; 6252 } 6253 } 6254 *idx++ = c; 6255 arg++; 6256 /* 6257 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} 6258 * The result is a_\_z_c (not a\_\_z_c)! 6259 * 6260 * Enable debug prints in this function and you'll see: 6261 * ash: arg:'\\b/_\\_z_' varflags:d 6262 * ash: pattern:'\\b' repl:'_\_z_' 6263 * That is, \\b is interpreted as \\b, but \\_ as \_! 6264 * IOW: search pattern and replace string treat backslashes 6265 * differently! That is the reason why we check repl below: 6266 */ 6267 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) 6268 arg++; /* skip both '\', not just first one */ 6269 } 6270 *idx = c; /* NUL */ 6271 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); 6272 6273 return repl; 6274 } 6275 #endif /* ENABLE_ASH_BASH_COMPAT */ 5637 6276 5638 6277 static const char * 5639 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5640 { 6278 subevalvar(char *p, char *varname, int strloc, int subtype, 6279 int startloc, int varflags, int quotes, struct strlist *var_str_list) 6280 { 6281 struct nodelist *saveargbackq = argbackq; 5641 6282 char *startp; 5642 6283 char *loc; 6284 char *rmesc, *rmescend; 6285 char *str; 6286 IF_ASH_BASH_COMPAT(const char *repl = NULL;) 6287 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 5643 6288 int saveherefd = herefd; 5644 struct nodelist *saveargbackq = argbackq; 5645 int amount; 5646 char *rmesc, *rmescend; 6289 int amount, workloc, resetloc; 5647 6290 int zero; 5648 char *(*scan)(char *, char *, char *, char *, int , int); 6291 char *(*scan)(char*, char*, char*, char*, int, int); 6292 6293 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", 6294 // p, varname, strloc, subtype, startloc, varflags, quotes); 5649 6295 5650 6296 herefd = -1; 5651 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 6297 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, 6298 var_str_list); 5652 6299 STPUTC('\0', expdest); 5653 6300 herefd = saveherefd; 5654 6301 argbackq = saveargbackq; 5655 startp = stackblock() + startloc;6302 startp = (char *)stackblock() + startloc; 5656 6303 5657 6304 switch (subtype) { 5658 6305 case VSASSIGN: 5659 setvar( str, startp, 0);6306 setvar(varname, startp, 0); 5660 6307 amount = startp - expdest; 5661 6308 STADJUST(amount, expdest); … … 5663 6310 5664 6311 case VSQUESTION: 5665 varunset(p, str, startp, varflags);6312 varunset(p, varname, startp, varflags); 5666 6313 /* NOTREACHED */ 5667 } 6314 6315 #if ENABLE_ASH_BASH_COMPAT 6316 case VSSUBSTR: 6317 loc = str = stackblock() + strloc; 6318 /* Read POS in ${var:POS:LEN} */ 6319 pos = atoi(loc); /* number(loc) errors out on "1:4" */ 6320 len = str - startp - 1; 6321 6322 /* *loc != '\0', guaranteed by parser */ 6323 if (quotes) { 6324 char *ptr; 6325 6326 /* Adjust the length by the number of escapes */ 6327 for (ptr = startp; ptr < (str - 1); ptr++) { 6328 if ((unsigned char)*ptr == CTLESC) { 6329 len--; 6330 ptr++; 6331 } 6332 } 6333 } 6334 orig_len = len; 6335 6336 if (*loc++ == ':') { 6337 /* ${var::LEN} */ 6338 len = number(loc); 6339 } else { 6340 /* Skip POS in ${var:POS:LEN} */ 6341 len = orig_len; 6342 while (*loc && *loc != ':') { 6343 /* TODO? 6344 * bash complains on: var=qwe; echo ${var:1a:123} 6345 if (!isdigit(*loc)) 6346 ash_msg_and_raise_error(msg_illnum, str); 6347 */ 6348 loc++; 6349 } 6350 if (*loc++ == ':') { 6351 len = number(loc); 6352 } 6353 } 6354 if (pos >= orig_len) { 6355 pos = 0; 6356 len = 0; 6357 } 6358 if (len > (orig_len - pos)) 6359 len = orig_len - pos; 6360 6361 for (str = startp; pos; str++, pos--) { 6362 if (quotes && (unsigned char)*str == CTLESC) 6363 str++; 6364 } 6365 for (loc = startp; len; len--) { 6366 if (quotes && (unsigned char)*str == CTLESC) 6367 *loc++ = *str++; 6368 *loc++ = *str++; 6369 } 6370 *loc = '\0'; 6371 amount = loc - expdest; 6372 STADJUST(amount, expdest); 6373 return loc; 6374 #endif 6375 } 6376 6377 resetloc = expdest - (char *)stackblock(); 6378 6379 /* We'll comeback here if we grow the stack while handling 6380 * a VSREPLACE or VSREPLACEALL, since our pointers into the 6381 * stack will need rebasing, and we'll need to remove our work 6382 * areas each time 6383 */ 6384 IF_ASH_BASH_COMPAT(restart:) 6385 6386 amount = expdest - ((char *)stackblock() + resetloc); 6387 STADJUST(-amount, expdest); 6388 startp = (char *)stackblock() + startloc; 6389 6390 rmesc = startp; 6391 rmescend = (char *)stackblock() + strloc; 6392 if (quotes) { 6393 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 6394 if (rmesc != startp) { 6395 rmescend = expdest; 6396 startp = (char *)stackblock() + startloc; 6397 } 6398 } 6399 rmescend--; 6400 str = (char *)stackblock() + strloc; 6401 preglob(str, varflags & VSQUOTE, 0); 6402 workloc = expdest - (char *)stackblock(); 6403 6404 #if ENABLE_ASH_BASH_COMPAT 6405 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 6406 char *idx, *end; 6407 6408 if (!repl) { 6409 repl = parse_sub_pattern(str, varflags); 6410 //bb_error_msg("repl:'%s'", repl); 6411 if (!repl) 6412 repl = nullstr; 6413 } 6414 6415 /* If there's no pattern to match, return the expansion unmolested */ 6416 if (str[0] == '\0') 6417 return NULL; 6418 6419 len = 0; 6420 idx = startp; 6421 end = str - 1; 6422 while (idx < end) { 6423 try_to_match: 6424 loc = scanright(idx, rmesc, rmescend, str, quotes, 1); 6425 //bb_error_msg("scanright('%s'):'%s'", str, loc); 6426 if (!loc) { 6427 /* No match, advance */ 6428 char *restart_detect = stackblock(); 6429 skip_matching: 6430 STPUTC(*idx, expdest); 6431 if (quotes && (unsigned char)*idx == CTLESC) { 6432 idx++; 6433 len++; 6434 STPUTC(*idx, expdest); 6435 } 6436 if (stackblock() != restart_detect) 6437 goto restart; 6438 idx++; 6439 len++; 6440 rmesc++; 6441 /* continue; - prone to quadratic behavior, smarter code: */ 6442 if (idx >= end) 6443 break; 6444 if (str[0] == '*') { 6445 /* Pattern is "*foo". If "*foo" does not match "long_string", 6446 * it would never match "ong_string" etc, no point in trying. 6447 */ 6448 goto skip_matching; 6449 } 6450 goto try_to_match; 6451 } 6452 6453 if (subtype == VSREPLACEALL) { 6454 while (idx < loc) { 6455 if (quotes && (unsigned char)*idx == CTLESC) 6456 idx++; 6457 idx++; 6458 rmesc++; 6459 } 6460 } else { 6461 idx = loc; 6462 } 6463 6464 //bb_error_msg("repl:'%s'", repl); 6465 for (loc = (char*)repl; *loc; loc++) { 6466 char *restart_detect = stackblock(); 6467 if (quotes && *loc == '\\') { 6468 STPUTC(CTLESC, expdest); 6469 len++; 6470 } 6471 STPUTC(*loc, expdest); 6472 if (stackblock() != restart_detect) 6473 goto restart; 6474 len++; 6475 } 6476 6477 if (subtype == VSREPLACE) { 6478 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes); 6479 while (*idx) { 6480 char *restart_detect = stackblock(); 6481 STPUTC(*idx, expdest); 6482 if (stackblock() != restart_detect) 6483 goto restart; 6484 len++; 6485 idx++; 6486 } 6487 break; 6488 } 6489 } 6490 6491 /* We've put the replaced text into a buffer at workloc, now 6492 * move it to the right place and adjust the stack. 6493 */ 6494 STPUTC('\0', expdest); 6495 startp = (char *)stackblock() + startloc; 6496 memmove(startp, (char *)stackblock() + workloc, len + 1); 6497 //bb_error_msg("startp:'%s'", startp); 6498 amount = expdest - (startp + len); 6499 STADJUST(-amount, expdest); 6500 return startp; 6501 } 6502 #endif /* ENABLE_ASH_BASH_COMPAT */ 5668 6503 5669 6504 subtype -= VSTRIMRIGHT; 5670 6505 #if DEBUG 5671 if (subtype < 0 || subtype > 3)6506 if (subtype < 0 || subtype > 7) 5672 6507 abort(); 5673 6508 #endif 5674 5675 rmesc = startp; 5676 rmescend = stackblock() + strloc; 5677 if (quotes) { 5678 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5679 if (rmesc != startp) { 5680 rmescend = expdest; 5681 startp = stackblock() + startloc; 5682 } 5683 } 5684 rmescend--; 5685 str = stackblock() + strloc; 5686 preglob(str, varflags & VSQUOTE, 0); 5687 5688 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 6509 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */ 5689 6510 zero = subtype >> 1; 5690 6511 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ … … 5706 6527 /* 5707 6528 * Add the value of a specialized variable to the stack string. 5708 */ 5709 static ssize_t 5710 varvalue(char *name, int varflags, int flags) 5711 { 6529 * name parameter (examples): 6530 * ash -c 'echo $1' name:'1=' 6531 * ash -c 'echo $qwe' name:'qwe=' 6532 * ash -c 'echo $$' name:'$=' 6533 * ash -c 'echo ${$}' name:'$=' 6534 * ash -c 'echo ${$##q}' name:'$=q' 6535 * ash -c 'echo ${#$}' name:'$=' 6536 * note: examples with bad shell syntax: 6537 * ash -c 'echo ${#$1}' name:'$=1' 6538 * ash -c 'echo ${#1#}' name:'1=#' 6539 */ 6540 static NOINLINE ssize_t 6541 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) 6542 { 6543 const char *p; 5712 6544 int num; 5713 char *p;5714 6545 int i; 5715 int sep = 0;5716 6546 int sepq = 0; 5717 6547 ssize_t len = 0; 5718 char **ap;5719 int syntax;6548 int subtype = varflags & VSTYPE; 6549 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); 5720 6550 int quoted = varflags & VSQUOTE; 5721 int subtype = varflags & VSTYPE; 5722 int quotes = flags & (EXP_FULL | EXP_CASE); 5723 5724 if (quoted && (flags & EXP_FULL)) 5725 sep = 1 << CHAR_BIT; 5726 5727 syntax = quoted ? DQSYNTAX : BASESYNTAX; 6551 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 6552 5728 6553 switch (*name) { 5729 6554 case '$': … … 5742 6567 numvar: 5743 6568 len = cvtnum(num); 5744 break;6569 goto check_1char_name; 5745 6570 case '-': 5746 p= makestrspace(NOPTS, expdest);6571 expdest = makestrspace(NOPTS, expdest); 5747 6572 for (i = NOPTS - 1; i >= 0; i--) { 5748 6573 if (optlist[i]) { 5749 USTPUTC(optletters(i), p);6574 USTPUTC(optletters(i), expdest); 5750 6575 len++; 5751 6576 } 5752 6577 } 5753 expdest = p; 6578 check_1char_name: 6579 #if 0 6580 /* handles cases similar to ${#$1} */ 6581 if (name[2] != '\0') 6582 raise_error_syntax("bad substitution"); 6583 #endif 5754 6584 break; 5755 case '@': 5756 if (sep) 6585 case '@': { 6586 char **ap; 6587 int sep; 6588 6589 if (quoted && (flags & EXP_FULL)) { 6590 /* note: this is not meant as PEOF value */ 6591 sep = 1 << CHAR_BIT; 5757 6592 goto param; 6593 } 5758 6594 /* fall through */ 5759 6595 case '*': 5760 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' '; 5761 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 6596 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; 6597 i = SIT(sep, syntax); 6598 if (quotes && (i == CCTL || i == CBACK)) 5762 6599 sepq = 1; 5763 6600 param: … … 5765 6602 if (!ap) 5766 6603 return -1; 5767 while ((p = *ap++) ) {6604 while ((p = *ap++) != NULL) { 5768 6605 size_t partlen; 5769 6606 … … 5784 6621 if (sepq) 5785 6622 STPUTC(CTLESC, q); 6623 /* note: may put NUL despite sep != 0 6624 * (see sep = 1 << CHAR_BIT above) */ 5786 6625 STPUTC(sep, q); 5787 6626 expdest = q; … … 5789 6628 } 5790 6629 return len; 6630 } /* case '@' and '*' */ 5791 6631 case '0': 5792 6632 case '1': … … 5799 6639 case '8': 5800 6640 case '9': 5801 num = atoi(name); 6641 num = atoi(name); /* number(name) fails on ${N#str} etc */ 5802 6642 if (num < 0 || num > shellparam.nparam) 5803 6643 return -1; … … 5805 6645 goto value; 5806 6646 default: 6647 /* NB: name has form "VAR=..." */ 6648 6649 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings 6650 * which should be considered before we check variables. */ 6651 if (var_str_list) { 6652 unsigned name_len = (strchrnul(name, '=') - name) + 1; 6653 p = NULL; 6654 do { 6655 char *str, *eq; 6656 str = var_str_list->text; 6657 eq = strchr(str, '='); 6658 if (!eq) /* stop at first non-assignment */ 6659 break; 6660 eq++; 6661 if (name_len == (unsigned)(eq - str) 6662 && strncmp(str, name, name_len) == 0 6663 ) { 6664 p = eq; 6665 /* goto value; - WRONG! */ 6666 /* think "A=1 A=2 B=$A" */ 6667 } 6668 var_str_list = var_str_list->next; 6669 } while (var_str_list); 6670 if (p) 6671 goto value; 6672 } 5807 6673 p = lookupvar(name); 5808 6674 value: … … 5826 6692 */ 5827 6693 static char * 5828 evalvar(char *p, int flag) 5829 { 5830 int subtype; 5831 int varflags; 6694 evalvar(char *p, int flags, struct strlist *var_str_list) 6695 { 6696 char varflags; 6697 char subtype; 6698 char quoted; 6699 char easy; 5832 6700 char *var; 5833 6701 int patloc; 5834 int c;5835 6702 int startloc; 5836 6703 ssize_t varlen; 5837 int easy; 5838 int quotes; 5839 int quoted; 5840 5841 quotes = flag & (EXP_FULL | EXP_CASE); 5842 varflags = *p++; 6704 6705 varflags = (unsigned char) *p++; 5843 6706 subtype = varflags & VSTYPE; 5844 6707 quoted = varflags & VSQUOTE; … … 5846 6709 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5847 6710 startloc = expdest - (char *)stackblock(); 5848 p = strchr(p, '=') + 1; 6711 p = strchr(p, '=') + 1; //TODO: use var_end(p)? 5849 6712 5850 6713 again: 5851 varlen = varvalue(var, varflags, flag );6714 varlen = varvalue(var, varflags, flags, var_str_list); 5852 6715 if (varflags & VSNUL) 5853 6716 varlen--; … … 5862 6725 if (varlen < 0) { 5863 6726 argstr( 5864 p, flag | EXP_TILDE | 5865 (quoted ? EXP_QWORD : EXP_WORD) 6727 p, 6728 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), 6729 var_str_list 5866 6730 ); 5867 6731 goto end; … … 5874 6738 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5875 6739 if (varlen < 0) { 5876 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { 6740 if (subevalvar(p, var, /* strloc: */ 0, 6741 subtype, startloc, varflags, 6742 /* quotes: */ 0, 6743 var_str_list) 6744 ) { 5877 6745 varflags &= ~VSNUL; 5878 6746 /* … … 5899 6767 5900 6768 if (subtype == VSNORMAL) { 5901 if (!easy) 5902 goto end; 5903 record: 5904 recordregion(startloc, expdest - (char *)stackblock(), quoted); 6769 if (easy) 6770 goto record; 5905 6771 goto end; 5906 6772 } … … 5912 6778 case VSTRIMRIGHT: 5913 6779 case VSTRIMRIGHTMAX: 6780 #if ENABLE_ASH_BASH_COMPAT 6781 case VSSUBSTR: 6782 case VSREPLACE: 6783 case VSREPLACEALL: 6784 #endif 5914 6785 break; 5915 6786 default: … … 5925 6796 STPUTC('\0', expdest); 5926 6797 patloc = expdest - (char *)stackblock(); 5927 if (subevalvar(p, NULL, patloc, subtype, 5928 startloc, varflags, quotes) == 0) { 6798 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6799 startloc, varflags, 6800 //TODO: | EXP_REDIR too? All other such places do it too 6801 /* quotes: */ flags & (EXP_FULL | EXP_CASE), 6802 var_str_list) 6803 ) { 5929 6804 int amount = expdest - ( 5930 6805 (char *)stackblock() + patloc - 1 … … 5934 6809 /* Remove any recorded regions beyond start of variable */ 5935 6810 removerecordregions(startloc); 5936 goto record; 6811 record: 6812 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5937 6813 } 5938 6814 … … 5941 6817 int nesting = 1; 5942 6818 for (;;) { 5943 c = *p++;6819 unsigned char c = *p++; 5944 6820 if (c == CTLESC) 5945 6821 p++; … … 5989 6865 while (p < string + ifsp->endoff) { 5990 6866 q = p; 5991 if ( *p == CTLESC)6867 if ((unsigned char)*p == CTLESC) 5992 6868 p++; 5993 6869 if (!strchr(ifs, *p)) { … … 6004 6880 } 6005 6881 *q = '\0'; 6006 sp = st alloc(sizeof(*sp));6882 sp = stzalloc(sizeof(*sp)); 6007 6883 sp->text = start; 6008 6884 *arglist->lastp = sp; … … 6015 6891 } 6016 6892 q = p; 6017 if ( *p == CTLESC)6893 if ((unsigned char)*p == CTLESC) 6018 6894 p++; 6019 if (strchr(ifs, *p) == NULL 6895 if (strchr(ifs, *p) == NULL) { 6020 6896 p = q; 6021 6897 break; 6022 } else if (strchr(defifs, *p) == NULL) { 6898 } 6899 if (strchr(defifs, *p) == NULL) { 6023 6900 if (ifsspc) { 6024 6901 p++; … … 6044 6921 6045 6922 add: 6046 sp = st alloc(sizeof(*sp));6923 sp = stzalloc(sizeof(*sp)); 6047 6924 sp->text = start; 6048 6925 *arglist->lastp = sp; … … 6076 6953 struct strlist *sp; 6077 6954 6078 sp = st alloc(sizeof(*sp));6955 sp = stzalloc(sizeof(*sp)); 6079 6956 sp->text = ststrdup(name); 6080 6957 *exparg.lastp = sp; … … 6082 6959 } 6083 6960 6084 static char *expdir;6085 6086 6961 /* 6087 6962 * Do metacharacter (i.e. *, ?, [...]) expansion. 6088 6963 */ 6089 6964 static void 6090 expmeta(char *e nddir, char *name)6965 expmeta(char *expdir, char *enddir, char *name) 6091 6966 { 6092 6967 char *p; … … 6176 7051 if (*p == '.') 6177 7052 matchdot++; 6178 while (! intpending&& (dp = readdir(dirp)) != NULL) {6179 if (dp->d_name[0] == '.' && ! 7053 while (!pending_int && (dp = readdir(dirp)) != NULL) { 7054 if (dp->d_name[0] == '.' && !matchdot) 6180 7055 continue; 6181 7056 if (pmatch(start, dp->d_name)) { … … 6187 7062 continue; 6188 7063 p[-1] = '/'; 6189 expmeta( p, endname);7064 expmeta(expdir, p, endname); 6190 7065 } 6191 7066 } 6192 7067 } 6193 7068 closedir(dirp); 6194 if (! 7069 if (!atend) 6195 7070 endname[-1] = '/'; 6196 7071 } … … 6208 7083 half = len >> 1; 6209 7084 p = list; 6210 for (n = half; --n >= 0; 7085 for (n = half; --n >= 0;) { 6211 7086 q = p; 6212 7087 p = p->next; … … 6261 7136 6262 7137 static void 6263 expandmeta(struct strlist *str , int flag)7138 expandmeta(struct strlist *str /*, int flag*/) 6264 7139 { 6265 7140 static const char metachars[] ALIGN1 = { … … 6269 7144 6270 7145 while (str) { 7146 char *expdir; 6271 7147 struct strlist **savelastp; 6272 7148 struct strlist *sp; … … 6285 7161 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 6286 7162 } 6287 6288 expmeta(expdir, p); 7163 expmeta(expdir, expdir, p); 6289 7164 free(expdir); 6290 7165 if (p != str->text) … … 6297 7172 nometa: 6298 7173 *exparg.lastp = str; 6299 rmescapes(str->text );7174 rmescapes(str->text, 0); 6300 7175 exparg.lastp = &str->next; 6301 7176 } else { … … 6326 7201 ifsfirst.next = NULL; 6327 7202 ifslastp = NULL; 6328 argstr(arg->narg.text, flag); 7203 argstr(arg->narg.text, flag, 7204 /* var_str_list: */ arglist ? arglist->list : NULL); 6329 7205 p = _STPUTC('\0', expdest); 6330 7206 expdest = p - 1; … … 6341 7217 *exparg.lastp = NULL; 6342 7218 exparg.lastp = &exparg.list; 6343 expandmeta(exparg.list , flag);7219 expandmeta(exparg.list /*, flag*/); 6344 7220 } else { 6345 7221 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 6346 rmescapes(p );6347 sp = st alloc(sizeof(*sp));7222 rmescapes(p, 0); 7223 sp = stzalloc(sizeof(*sp)); 6348 7224 sp->text = p; 6349 7225 *exparg.lastp = sp; … … 6392 7268 STARTSTACKSTR(expdest); 6393 7269 ifslastp = NULL; 6394 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 7270 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, 7271 /* var_str_list: */ NULL); 6395 7272 STACKSTRNUL(expdest); 6396 7273 result = patmatch(stackblock(), val); … … 6404 7281 struct builtincmd { 6405 7282 const char *name; 6406 int (*builtin)(int, char **) ;7283 int (*builtin)(int, char **) FAST_FUNC; 6407 7284 /* unsigned flags; */ 6408 7285 }; 6409 7286 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1) 7287 /* "regular" builtins always take precedence over commands, 7288 * regardless of PATH=....%builtin... position */ 6410 7289 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2) 6411 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)7290 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4) 6412 7291 6413 7292 struct cmdentry { 6414 int cmdtype;7293 smallint cmdtype; /* CMDxxx */ 6415 7294 union param { 6416 7295 int index; 7296 /* index >= 0 for commands without path (slashes) */ 7297 /* (TODO: what exactly does the value mean? PATH position?) */ 7298 /* index == -1 for commands with slashes */ 7299 /* index == (-2 - applet_no) for NOFORK applets */ 6417 7300 const struct builtincmd *cmd; 6418 7301 struct funcnode *func; … … 6446 7329 */ 6447 7330 6448 #define CMDTABLESIZE 31 /* should be prime */6449 #define ARB 1 /* actual size determined at run time */6450 6451 7331 struct tblentry { 6452 7332 struct tblentry *next; /* next entry in hash chain */ 6453 7333 union param param; /* definition of builtin function */ 6454 s hort cmdtype; /* index identifying command*/7334 smallint cmdtype; /* CMDxxx */ 6455 7335 char rehash; /* if set, cd done since entry created */ 6456 char cmdname[ ARB];/* name of command */7336 char cmdname[1]; /* name of command */ 6457 7337 }; 6458 7338 6459 static struct tblentry *cmdtable[CMDTABLESIZE]; 6460 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 7339 static struct tblentry **cmdtable; 7340 #define INIT_G_cmdtable() do { \ 7341 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \ 7342 } while (0) 7343 7344 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 7345 6461 7346 6462 7347 static void 6463 tryexec( char *cmd, char **argv, char **envp)7348 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) 6464 7349 { 6465 7350 int repeated = 0; 6466 7351 6467 7352 #if ENABLE_FEATURE_SH_STANDALONE 6468 if (strchr(cmd, '/') == NULL) { 6469 const struct bb_applet *a; 6470 6471 a = find_applet_by_name(cmd); 6472 if (a) { 6473 if (a->noexec) { 6474 current_applet = a; 6475 run_current_applet_and_exit(argv); 6476 } 6477 /* re-exec ourselves with the new arguments */ 6478 execve(bb_busybox_exec_path, argv, envp); 6479 /* If they called chroot or otherwise made the binary no longer 6480 * executable, fall through */ 6481 } 7353 if (applet_no >= 0) { 7354 if (APPLET_IS_NOEXEC(applet_no)) { 7355 clearenv(); 7356 while (*envp) 7357 putenv(*envp++); 7358 run_applet_no_and_exit(applet_no, argv); 7359 } 7360 /* re-exec ourselves with the new arguments */ 7361 execve(bb_busybox_exec_path, argv, envp); 7362 /* If they called chroot or otherwise made the binary no longer 7363 * executable, fall through */ 6482 7364 } 6483 7365 #endif … … 6491 7373 execve(cmd, argv, envp); 6492 7374 #endif 6493 if (repeated ++) {7375 if (repeated) { 6494 7376 free(argv); 6495 } else if (errno == ENOEXEC) { 7377 return; 7378 } 7379 if (errno == ENOEXEC) { 6496 7380 char **ap; 6497 7381 char **new; 6498 7382 6499 7383 for (ap = argv; *ap; ap++) 6500 ;6501 ap = new = ckmalloc((ap - argv + 2) * sizeof( char *));7384 continue; 7385 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); 6502 7386 ap[1] = cmd; 6503 7387 ap[0] = cmd = (char *)DEFAULT_SHELL; 6504 7388 ap += 2; 6505 7389 argv++; 6506 while ((*ap++ = *argv++) )6507 ;7390 while ((*ap++ = *argv++) != NULL) 7391 continue; 6508 7392 argv = new; 7393 repeated++; 6509 7394 goto repeat; 6510 7395 } … … 6515 7400 * have to change the find_command routine as well. 6516 7401 */ 6517 #define environment() listvars(VEXPORT, VUNSET, 0) 6518 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 7402 static void shellexec(char **, const char *, int) NORETURN; 6519 7403 static void 6520 7404 shellexec(char **argv, const char *path, int idx) … … 6524 7408 char **envp; 6525 7409 int exerrno; 6526 6527 clearredir(1);6528 envp = environment();6529 if (strchr(argv[0], '/')6530 7410 #if ENABLE_FEATURE_SH_STANDALONE 6531 || find_applet_by_name(argv[0]) 7411 int applet_no = -1; 7412 #endif 7413 7414 clearredir(/*drop:*/ 1); 7415 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7416 if (strchr(argv[0], '/') != NULL 7417 #if ENABLE_FEATURE_SH_STANDALONE 7418 || (applet_no = find_applet_by_name(argv[0])) >= 0 6532 7419 #endif 6533 7420 ) { 6534 tryexec( argv[0], argv, envp);7421 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); 6535 7422 e = errno; 6536 7423 } else { 6537 7424 e = ENOENT; 6538 while ((cmdname = pa dvance(&path, argv[0])) != NULL) {7425 while ((cmdname = path_advance(&path, argv[0])) != NULL) { 6539 7426 if (--idx < 0 && pathopt == NULL) { 6540 tryexec( cmdname, argv, envp);7427 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); 6541 7428 if (errno != ENOENT && errno != ENOTDIR) 6542 7429 e = errno; … … 6559 7446 } 6560 7447 exitstatus = exerrno; 6561 TRACE(("shellexec failed for %s, errno %d, suppress int %d\n",6562 argv[0], e, suppress int));7448 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", 7449 argv[0], e, suppress_int)); 6563 7450 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); 6564 7451 /* NOTREACHED */ … … 6575 7462 path = pathval(); 6576 7463 do { 6577 name = pa dvance(&path, cmdp->cmdname);7464 name = path_advance(&path, cmdp->cmdname); 6578 7465 stunalloc(name); 6579 7466 } while (--idx >= 0); … … 6642 7529 } 6643 7530 if (add && cmdp == NULL) { 6644 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB 6645 + strlen(name) + 1); 6646 cmdp->next = NULL; 7531 cmdp = *pp = ckzalloc(sizeof(struct tblentry) 7532 + strlen(name) 7533 /* + 1 - already done because 7534 * tblentry::cmdname is char[1] */); 7535 /*cmdp->next = NULL; - ckzalloc did it */ 6647 7536 cmdp->cmdtype = CMDUNKNOWN; 6648 7537 strcpy(cmdp->cmdname, name); … … 6687 7576 } 6688 7577 6689 static int 6690 hashcmd(int argc , char **argv)7578 static int FAST_FUNC 7579 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 6691 7580 { 6692 7581 struct tblentry **pp; … … 6696 7585 char *name; 6697 7586 6698 while ((c = nextopt("r")) != '\0') {7587 if (nextopt("r") != '\0') { 6699 7588 clearcmdentry(0); 6700 7589 return 0; 6701 7590 } 7591 6702 7592 if (*argptr == NULL) { 6703 7593 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { … … 6709 7599 return 0; 6710 7600 } 7601 6711 7602 c = 0; 6712 7603 while ((name = *argptr) != NULL) { … … 6714 7605 if (cmdp != NULL 6715 7606 && (cmdp->cmdtype == CMDNORMAL 6716 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 7607 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) 7608 ) { 6717 7609 delete_cmd_entry(); 7610 } 6718 7611 find_command(name, &entry, DO_ERR, pathval()); 6719 7612 if (entry.cmdtype == CMDUNKNOWN) … … 6736 7629 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6737 7630 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6738 if (cmdp->cmdtype == CMDNORMAL || (6739 cmdp->cmdtype == CMDBUILTIN &&6740 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&6741 builtinloc > 06742 ) )7631 if (cmdp->cmdtype == CMDNORMAL 7632 || (cmdp->cmdtype == CMDBUILTIN 7633 && !IS_BUILTIN_REGULAR(cmdp->param.cmd) 7634 && builtinloc > 0) 7635 ) { 6743 7636 cmdp->rehash = 1; 7637 } 6744 7638 } 6745 7639 } … … 6752 7646 * Called with interrupts off. 6753 7647 */ 6754 static void 6755 changepath(const char *newval) 6756 { 6757 const char *old, *new; 7648 static void FAST_FUNC 7649 changepath(const char *new) 7650 { 7651 const char *old; 7652 int firstchange; 6758 7653 int idx; 6759 int firstchange;6760 7654 int idx_bltin; 6761 7655 6762 7656 old = pathval(); 6763 new = newval;6764 7657 firstchange = 9999; /* assume no change */ 6765 7658 idx = 0; … … 6769 7662 firstchange = idx; 6770 7663 if ((*old == '\0' && *new == ':') 6771 || (*old == ':' && *new == '\0')) 7664 || (*old == ':' && *new == '\0') 7665 ) { 6772 7666 firstchange++; 7667 } 6773 7668 old = new; /* ignore subsequent differences */ 6774 7669 } … … 6777 7672 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 6778 7673 idx_bltin = idx; 6779 if (*new == ':') {7674 if (*new == ':') 6780 7675 idx++; 6781 }6782 new++,old++;7676 new++; 7677 old++; 6783 7678 } 6784 7679 if (builtinloc < 0 && idx_bltin >= 0) … … 6819 7714 #define TBEGIN 27 6820 7715 #define TEND 28 7716 typedef smallint token_id_t; 6821 7717 6822 7718 /* first char is indicating which tokens mark the end of a list */ … … 6855 7751 }; 6856 7752 6857 static const char *6858 tokname(int tok)6859 {6860 static char buf[16];6861 6862 //try this:6863 //if (tok < TSEMI) return tokname_array[tok] + 1;6864 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);6865 //return buf;6866 6867 if (tok >= TSEMI)6868 buf[0] = '"';6869 sprintf(buf + (tok >= TSEMI), "%s%c",6870 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));6871 return buf;6872 }6873 6874 7753 /* Wrapper around strcmp for qsort/bsearch/... */ 6875 7754 static int … … 6937 7816 int j = entry.u.index; 6938 7817 char *p; 6939 if (j == -1) {7818 if (j < 0) { 6940 7819 p = command; 6941 7820 } else { 6942 7821 do { 6943 p = pa dvance(&path, command);7822 p = path_advance(&path, command); 6944 7823 stunalloc(p); 6945 7824 } while (--j >= 0); … … 6981 7860 } 6982 7861 out: 6983 out str("\n", stdout);7862 out1str("\n"); 6984 7863 return 0; 6985 7864 } 6986 7865 6987 static int 6988 typecmd(int argc , char **argv)7866 static int FAST_FUNC 7867 typecmd(int argc UNUSED_PARAM, char **argv) 6989 7868 { 6990 7869 int i = 1; … … 6997 7876 verbose = 0; 6998 7877 } 6999 while ( i < argc) {7878 while (argv[i]) { 7000 7879 err |= describe_command(argv[i++], verbose); 7001 7880 } … … 7004 7883 7005 7884 #if ENABLE_ASH_CMDCMD 7006 static int 7007 commandcmd(int argc , char **argv)7885 static int FAST_FUNC 7886 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 7008 7887 { 7009 7888 int c; … … 7022 7901 abort(); 7023 7902 #endif 7024 if (verify) 7903 /* Mimic bash: just "command -v" doesn't complain, it's a nop */ 7904 if (verify && (*argptr != NULL)) { 7025 7905 return describe_command(*argptr, verify - VERIFY_BRIEF); 7906 } 7026 7907 7027 7908 return 0; … … 7032 7913 /* ============ eval.c */ 7033 7914 7034 static int funcblocksize; 7035 static int funcstringsize; 7036 static void *funcblock; 7037 static char *funcstring; 7915 static int funcblocksize; /* size of structures in function */ 7916 static int funcstringsize; /* size of strings in node */ 7917 static void *funcblock; /* block to allocate function from */ 7918 static char *funcstring; /* block to allocate strings from */ 7038 7919 7039 7920 /* flags in argument to evaltree */ 7040 #define EV_EXIT 01/* exit after evaluating tree */7041 #define EV_TESTED 02/* exit status is checked; ignore -e flag */7921 #define EV_EXIT 01 /* exit after evaluating tree */ 7922 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 7042 7923 #define EV_BACKCMD 04 /* command executing within back quotes */ 7043 7924 7044 static const short nodesize[26] = { 7045 SHELL_ALIGN(sizeof(struct ncmd)), 7046 SHELL_ALIGN(sizeof(struct npipe)), 7047 SHELL_ALIGN(sizeof(struct nredir)), 7048 SHELL_ALIGN(sizeof(struct nredir)), 7049 SHELL_ALIGN(sizeof(struct nredir)), 7050 SHELL_ALIGN(sizeof(struct nbinary)), 7051 SHELL_ALIGN(sizeof(struct nbinary)), 7052 SHELL_ALIGN(sizeof(struct nbinary)), 7053 SHELL_ALIGN(sizeof(struct nif)), 7054 SHELL_ALIGN(sizeof(struct nbinary)), 7055 SHELL_ALIGN(sizeof(struct nbinary)), 7056 SHELL_ALIGN(sizeof(struct nfor)), 7057 SHELL_ALIGN(sizeof(struct ncase)), 7058 SHELL_ALIGN(sizeof(struct nclist)), 7059 SHELL_ALIGN(sizeof(struct narg)), 7060 SHELL_ALIGN(sizeof(struct narg)), 7061 SHELL_ALIGN(sizeof(struct nfile)), 7062 SHELL_ALIGN(sizeof(struct nfile)), 7063 SHELL_ALIGN(sizeof(struct nfile)), 7064 SHELL_ALIGN(sizeof(struct nfile)), 7065 SHELL_ALIGN(sizeof(struct nfile)), 7066 SHELL_ALIGN(sizeof(struct ndup)), 7067 SHELL_ALIGN(sizeof(struct ndup)), 7068 SHELL_ALIGN(sizeof(struct nhere)), 7069 SHELL_ALIGN(sizeof(struct nhere)), 7070 SHELL_ALIGN(sizeof(struct nnot)), 7925 static const uint8_t nodesize[N_NUMBER] = { 7926 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 7927 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)), 7928 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)), 7929 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)), 7930 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)), 7931 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)), 7932 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)), 7933 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)), 7934 [NIF ] = SHELL_ALIGN(sizeof(struct nif)), 7935 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)), 7936 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)), 7937 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)), 7938 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)), 7939 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)), 7940 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)), 7941 [NARG ] = SHELL_ALIGN(sizeof(struct narg)), 7942 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)), 7943 #if ENABLE_ASH_BASH_COMPAT 7944 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)), 7945 #endif 7946 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)), 7947 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)), 7948 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)), 7949 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)), 7950 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)), 7951 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)), 7952 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)), 7953 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)), 7954 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 7071 7955 }; 7072 7956 … … 7138 8022 break; 7139 8023 case NTO: 8024 #if ENABLE_ASH_BASH_COMPAT 8025 case NTO2: 8026 #endif 7140 8027 case NCLOBBER: 7141 8028 case NFROM: … … 7209 8096 case NPIPE: 7210 8097 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 7211 new->npipe. backgnd = n->npipe.backgnd;8098 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 7212 8099 break; 7213 8100 case NREDIR: … … 7251 8138 break; 7252 8139 case NTO: 8140 #if ENABLE_ASH_BASH_COMPAT 8141 case NTO2: 8142 #endif 7253 8143 case NCLOBBER: 7254 8144 case NFROM: … … 7316 8206 } 7317 8207 7318 static int evalskip; /* set if we are skipping commands */ 7319 /* reasons for skipping commands (see comment on breakcmd routine) */ 8208 /* Reasons for skipping commands (see comment on breakcmd routine) */ 7320 8209 #define SKIPBREAK (1 << 0) 7321 8210 #define SKIPCONT (1 << 1) … … 7323 8212 #define SKIPFILE (1 << 3) 7324 8213 #define SKIPEVAL (1 << 4) 8214 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 7325 8215 static int skipcount; /* number of levels to skip */ 7326 8216 static int funcnest; /* depth of function calls */ 7327 7328 /* forward decl way out to parsing code - dotrap needs it */ 8217 static int loopnest; /* current loop nesting level */ 8218 8219 /* Forward decl way out to parsing code - dotrap needs it */ 7329 8220 static int evalstring(char *s, int mask); 7330 8221 7331 /* 7332 * Called to execute a trap. Perhaps we should avoid entering new trap 7333 * handlers while we are executing a trap handler. 8222 /* Called to execute a trap. 8223 * Single callsite - at the end of evaltree(). 8224 * If we return non-zero, evaltree raises EXEXIT exception. 8225 * 8226 * Perhaps we should avoid entering new trap handlers 8227 * while we are executing a trap handler. [is it a TODO?] 7334 8228 */ 7335 8229 static int 7336 8230 dotrap(void) 7337 8231 { 7338 char *p; 7339 char *q; 7340 int i; 7341 int savestatus; 7342 int skip = 0; 8232 uint8_t *g; 8233 int sig; 8234 uint8_t savestatus; 7343 8235 7344 8236 savestatus = exitstatus; 7345 pending sig = 0;8237 pending_sig = 0; 7346 8238 xbarrier(); 7347 8239 7348 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 7349 if (!*q) 8240 TRACE(("dotrap entered\n")); 8241 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) { 8242 int want_exexit; 8243 char *t; 8244 8245 if (*g == 0) 7350 8246 continue; 7351 *q = '\0';7352 7353 p = trap[i + 1];7354 if ( !p)8247 t = trap[sig]; 8248 /* non-trapped SIGINT is handled separately by raise_interrupt, 8249 * don't upset it by resetting gotsig[SIGINT-1] */ 8250 if (sig == SIGINT && !t) 7355 8251 continue; 7356 skip = evalstring(p, SKIPEVAL); 8252 8253 TRACE(("sig %d is active, will run handler '%s'\n", sig, t)); 8254 *g = 0; 8255 if (!t) 8256 continue; 8257 want_exexit = evalstring(t, SKIPEVAL); 7357 8258 exitstatus = savestatus; 7358 if (skip) 7359 break; 7360 } 7361 7362 return skip; 8259 if (want_exexit) { 8260 TRACE(("dotrap returns %d\n", want_exexit)); 8261 return want_exexit; 8262 } 8263 } 8264 8265 TRACE(("dotrap returns 0\n")); 8266 return 0; 7363 8267 } 7364 8268 … … 7381 8285 evaltree(union node *n, int flags) 7382 8286 { 8287 struct jmploc *volatile savehandler = exception_handler; 8288 struct jmploc jmploc; 7383 8289 int checkexit = 0; 7384 8290 void (*evalfn)(union node *, int); 7385 unsigned isor;7386 8291 int status; 8292 int int_level; 8293 8294 SAVE_INT(int_level); 8295 7387 8296 if (n == NULL) { 7388 8297 TRACE(("evaltree(NULL) called\n")); 7389 goto out; 7390 } 7391 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 7392 getpid(), n, n->type, flags)); 8298 goto out1; 8299 } 8300 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags)); 8301 8302 exception_handler = &jmploc; 8303 { 8304 int err = setjmp(jmploc.loc); 8305 if (err) { 8306 /* if it was a signal, check for trap handlers */ 8307 if (exception_type == EXSIG) { 8308 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", 8309 exception_type, err)); 8310 goto out; 8311 } 8312 /* continue on the way out */ 8313 TRACE(("exception %d in evaltree, propagating err=%d\n", 8314 exception_type, err)); 8315 exception_handler = savehandler; 8316 longjmp(exception_handler->loc, err); 8317 } 8318 } 8319 7393 8320 switch (n->type) { 7394 8321 default: 7395 8322 #if DEBUG 7396 8323 out1fmt("Node type = %d\n", n->type); 7397 fflush (stdout);8324 fflush_all(); 7398 8325 break; 7399 8326 #endif … … 7409 8336 status = exitstatus; 7410 8337 } 7411 popredir( 0);8338 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */); 7412 8339 goto setstatus; 7413 8340 case NCMD: … … 7436 8363 case NAND: 7437 8364 case NOR: 7438 case NSEMI: 8365 case NSEMI: { 8366 7439 8367 #if NAND + 1 != NOR 7440 8368 #error NAND + 1 != NOR … … 7443 8371 #error NOR + 1 != NSEMI 7444 8372 #endif 7445 isor = n->type - NAND;8373 unsigned is_or = n->type - NAND; 7446 8374 evaltree( 7447 8375 n->nbinary.ch1, 7448 (flags | ((is or >> 1) - 1)) & EV_TESTED8376 (flags | ((is_or >> 1) - 1)) & EV_TESTED 7449 8377 ); 7450 if (!exitstatus == is or)8378 if (!exitstatus == is_or) 7451 8379 break; 7452 8380 if (!evalskip) { … … 7459 8387 } 7460 8388 break; 8389 } 7461 8390 case NIF: 7462 8391 evaltree(n->nif.test, EV_TESTED); … … 7466 8395 n = n->nif.ifpart; 7467 8396 goto evaln; 7468 } else if (n->nif.elsepart) { 8397 } 8398 if (n->nif.elsepart) { 7469 8399 n = n->nif.elsepart; 7470 8400 goto evaln; … … 7479 8409 break; 7480 8410 } 8411 7481 8412 out: 7482 if ((checkexit & exitstatus)) 8413 exception_handler = savehandler; 8414 8415 out1: 8416 /* Order of checks below is important: 8417 * signal handlers trigger before exit caused by "set -e". 8418 */ 8419 if (pending_sig && dotrap()) 8420 goto exexit; 8421 if (checkexit & exitstatus) 7483 8422 evalskip |= SKIPEVAL; 7484 else if (pendingsig && dotrap())7485 goto exexit;7486 8423 7487 8424 if (flags & EV_EXIT) { … … 7489 8426 raise_exception(EXEXIT); 7490 8427 } 8428 8429 RESTORE_INT(int_level); 8430 TRACE(("leaving evaltree (no interrupts)\n")); 7491 8431 } 7492 8432 … … 7495 8435 #endif 7496 8436 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 7497 7498 static int loopnest; /* current loop nesting level */7499 8437 7500 8438 static void … … 7543 8481 7544 8482 setstackmark(&smark); 8483 arglist.list = NULL; 7545 8484 arglist.lastp = &arglist.list; 7546 8485 for (argp = n->nfor.args; argp; argp = argp->narg.next) { … … 7582 8521 7583 8522 setstackmark(&smark); 8523 arglist.list = NULL; 7584 8524 arglist.lastp = &arglist.list; 7585 8525 expandarg(n->ncase.expr, &arglist, EXP_TILDE); … … 7610 8550 7611 8551 expredir(n->nredir.redirect); 7612 if (!backgnd && flags & EV_EXIT && !trap[0])8552 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) 7613 8553 goto nofork; 7614 8554 INT_OFF; 7615 jp = makejob( n,1);8555 jp = makejob(/*n,*/ 1); 7616 8556 if (forkshell(jp, n, backgnd) == 0) { 8557 /* child */ 7617 8558 INT_ON; 7618 8559 flags |= EV_EXIT; 7619 8560 if (backgnd) 7620 flags &= ~EV_TESTED;8561 flags &= ~EV_TESTED; 7621 8562 nofork: 7622 8563 redirect(n->nredir.redirect, 0); … … 7625 8566 } 7626 8567 status = 0; 7627 if (! 8568 if (!backgnd) 7628 8569 status = waitforjob(jp); 7629 8570 exitstatus = status; … … 7643 8584 struct arglist fn; 7644 8585 7645 memset(&fn, 0, sizeof(fn));8586 fn.list = NULL; 7646 8587 fn.lastp = &fn.list; 7647 8588 switch (redir->type) { … … 7649 8590 case NFROM: 7650 8591 case NTO: 8592 #if ENABLE_ASH_BASH_COMPAT 8593 case NTO2: 8594 #endif 7651 8595 case NCLOBBER: 7652 8596 case NAPPEND: 7653 8597 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 8598 #if ENABLE_ASH_BASH_COMPAT 8599 store_expfname: 8600 #endif 7654 8601 redir->nfile.expfname = fn.list->text; 7655 8602 break; 7656 8603 case NFROMFD: 7657 case NTOFD: 8604 case NTOFD: /* >& */ 7658 8605 if (redir->ndup.vname) { 7659 8606 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 7660 8607 if (fn.list == NULL) 7661 8608 ash_msg_and_raise_error("redir error"); 8609 #if ENABLE_ASH_BASH_COMPAT 8610 //FIXME: we used expandarg with different args! 8611 if (!isdigit_str9(fn.list->text)) { 8612 /* >&file, not >&fd */ 8613 if (redir->nfile.fd != 1) /* 123>&file - BAD */ 8614 ash_msg_and_raise_error("redir error"); 8615 redir->type = NTO2; 8616 goto store_expfname; 8617 } 8618 #endif 7662 8619 fixredir(redir, fn.list->text, 1); 7663 8620 } … … 7688 8645 flags |= EV_EXIT; 7689 8646 INT_OFF; 7690 jp = makejob( n,pipelen);8647 jp = makejob(/*n,*/ pipelen); 7691 8648 prevfd = -1; 7692 8649 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { … … 7699 8656 } 7700 8657 } 7701 if (forkshell(jp, lp->n, n->npipe. backgnd) == 0) {8658 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 7702 8659 INT_ON; 7703 8660 if (pip[1] >= 0) { … … 7718 8675 close(prevfd); 7719 8676 prevfd = pip[0]; 7720 close(pip[1]); 7721 } 7722 if (n->npipe.backgnd == 0) { 8677 /* Don't want to trigger debugging */ 8678 if (pip[1] != -1) 8679 close(pip[1]); 8680 } 8681 if (n->npipe.pipe_backgnd == 0) { 7723 8682 exitstatus = waitforjob(jp); 7724 8683 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); … … 7733 8692 setinteractive(int on) 7734 8693 { 7735 static int is_interactive;8694 static smallint is_interactive; 7736 8695 7737 8696 if (++on == is_interactive) … … 7747 8706 7748 8707 if (!did_banner) { 7749 out1fmt( 7750 "\n\n" 7751 "%s built-in shell (ash)\n" 8708 /* note: ash and hush share this string */ 8709 out1fmt("\n\n%s %s\n" 7752 8710 "Enter 'help' for a list of built-in commands." 7753 8711 "\n\n", 7754 bb_banner); 8712 bb_banner, 8713 "built-in shell (ash)" 8714 ); 7755 8715 did_banner = 1; 7756 8716 } … … 7758 8718 #endif 7759 8719 } 7760 7761 #if ENABLE_FEATURE_EDITING_VI7762 #define setvimode(on) do { \7763 if (on) line_input_state->flags |= VI_MODE; \7764 else line_input_state->flags &= ~VI_MODE; \7765 } while (0)7766 #else7767 #define setvimode(on) viflag = 0 /* forcibly keep the option off */7768 #endif7769 8720 7770 8721 static void … … 7776 8727 setinteractive(iflag); 7777 8728 setjobctl(mflag); 7778 setvimode(viflag); 8729 #if ENABLE_FEATURE_EDITING_VI 8730 if (viflag) 8731 line_input_state->flags |= VI_MODE; 8732 else 8733 line_input_state->flags &= ~VI_MODE; 8734 #else 8735 viflag = 0; /* forcibly keep the option off */ 8736 #endif 7779 8737 } 7780 8738 … … 7794 8752 localvars = lvp->next; 7795 8753 vp = lvp->vp; 7796 TRACE(("poplocalvar %s ", vp ? vp->text : "-"));8754 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-")); 7797 8755 if (vp == NULL) { /* $- saved */ 7798 8756 memcpy(optlist, lvp->text, sizeof(optlist)); … … 7800 8758 optschanged(); 7801 8759 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 7802 unsetvar(vp-> text);8760 unsetvar(vp->var_text); 7803 8761 } else { 7804 if (vp-> func)7805 (*vp->func)(strchrnul(lvp->text, '=') + 1);8762 if (vp->var_func) 8763 vp->var_func(var_end(lvp->text)); 7806 8764 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 7807 free((char*)vp-> text);8765 free((char*)vp->var_text); 7808 8766 vp->flags = lvp->flags; 7809 vp-> text = lvp->text;8767 vp->var_text = lvp->text; 7810 8768 } 7811 8769 free(lvp); … … 7832 8790 exception_handler = &jmploc; 7833 8791 localvars = NULL; 7834 shellparam.malloc = 0;8792 shellparam.malloced = 0; 7835 8793 func->count++; 7836 8794 funcnest++; … … 7843 8801 #endif 7844 8802 evaltree(&func->n, flags & EV_TESTED); 7845 funcdone:8803 funcdone: 7846 8804 INT_OFF; 7847 8805 funcnest--; … … 7906 8864 7907 8865 INT_OFF; 7908 lvp = ck malloc(sizeof(struct localvar));8866 lvp = ckzalloc(sizeof(struct localvar)); 7909 8867 if (LONE_DASH(name)) { 7910 8868 char *p; … … 7926 8884 lvp->flags = VUNSET; 7927 8885 } else { 7928 lvp->text = vp-> text;8886 lvp->text = vp->var_text; 7929 8887 lvp->flags = vp->flags; 7930 8888 vp->flags |= VSTRFIXED|VTEXTFIXED; … … 7942 8900 * The "local" command. 7943 8901 */ 7944 static int 7945 localcmd(int argc , char **argv)8902 static int FAST_FUNC 8903 localcmd(int argc UNUSED_PARAM, char **argv) 7946 8904 { 7947 8905 char *name; … … 7954 8912 } 7955 8913 7956 static int 7957 falsecmd(int argc , char **argv)8914 static int FAST_FUNC 8915 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 7958 8916 { 7959 8917 return 1; 7960 8918 } 7961 8919 7962 static int 7963 truecmd(int argc , char **argv)8920 static int FAST_FUNC 8921 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 7964 8922 { 7965 8923 return 0; 7966 8924 } 7967 8925 7968 static int 7969 execcmd(int argc , char **argv)7970 { 7971 if (arg c > 1) {8926 static int FAST_FUNC 8927 execcmd(int argc UNUSED_PARAM, char **argv) 8928 { 8929 if (argv[1]) { 7972 8930 iflag = 0; /* exit on error */ 7973 8931 mflag = 0; … … 7981 8939 * The return command. 7982 8940 */ 7983 static int 7984 returncmd(int argc , char **argv)8941 static int FAST_FUNC 8942 returncmd(int argc UNUSED_PARAM, char **argv) 7985 8943 { 7986 8944 /* … … 7993 8951 7994 8952 /* Forward declarations for builtintab[] */ 7995 static int breakcmd(int, char **); 7996 static int dotcmd(int, char **); 7997 static int evalcmd(int, char **); 7998 #if ENABLE_ASH_BUILTIN_ECHO 7999 static int echocmd(int, char **); 8000 #endif 8001 #if ENABLE_ASH_BUILTIN_TEST 8002 static int testcmd(int, char **); 8003 #endif 8004 static int exitcmd(int, char **); 8005 static int exportcmd(int, char **); 8953 static int breakcmd(int, char **) FAST_FUNC; 8954 static int dotcmd(int, char **) FAST_FUNC; 8955 static int evalcmd(int, char **) FAST_FUNC; 8956 static int exitcmd(int, char **) FAST_FUNC; 8957 static int exportcmd(int, char **) FAST_FUNC; 8006 8958 #if ENABLE_ASH_GETOPTS 8007 static int getoptscmd(int, char **) ;8959 static int getoptscmd(int, char **) FAST_FUNC; 8008 8960 #endif 8009 8961 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8010 static int helpcmd(int argc, char **argv);8011 #endif 8012 #if ENABLE_ ASH_MATH_SUPPORT8013 static int letcmd(int, char **) ;8014 #endif 8015 static int readcmd(int, char **) ;8016 static int setcmd(int, char **) ;8017 static int shiftcmd(int, char **) ;8018 static int timescmd(int, char **) ;8019 static int trapcmd(int, char **) ;8020 static int umaskcmd(int, char **) ;8021 static int unsetcmd(int, char **) ;8022 static int ulimitcmd(int, char **) ;8962 static int helpcmd(int, char **) FAST_FUNC; 8963 #endif 8964 #if ENABLE_SH_MATH_SUPPORT 8965 static int letcmd(int, char **) FAST_FUNC; 8966 #endif 8967 static int readcmd(int, char **) FAST_FUNC; 8968 static int setcmd(int, char **) FAST_FUNC; 8969 static int shiftcmd(int, char **) FAST_FUNC; 8970 static int timescmd(int, char **) FAST_FUNC; 8971 static int trapcmd(int, char **) FAST_FUNC; 8972 static int umaskcmd(int, char **) FAST_FUNC; 8973 static int unsetcmd(int, char **) FAST_FUNC; 8974 static int ulimitcmd(int, char **) FAST_FUNC; 8023 8975 8024 8976 #define BUILTIN_NOSPEC "0" … … 8031 8983 #define BUILTIN_SPEC_REG_ASSG "7" 8032 8984 8033 /* make sure to keep these in proper order since it is searched via bsearch() */ 8985 /* Stubs for calling non-FAST_FUNC's */ 8986 #if ENABLE_ASH_BUILTIN_ECHO 8987 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); } 8988 #endif 8989 #if ENABLE_ASH_BUILTIN_PRINTF 8990 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } 8991 #endif 8992 #if ENABLE_ASH_BUILTIN_TEST 8993 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } 8994 #endif 8995 8996 /* Keep these in proper order since it is searched via bsearch() */ 8034 8997 static const struct builtincmd builtintab[] = { 8035 { BUILTIN_SPEC_REG "." , dotcmd},8036 { BUILTIN_SPEC_REG ":" , truecmd},8998 { BUILTIN_SPEC_REG "." , dotcmd }, 8999 { BUILTIN_SPEC_REG ":" , truecmd }, 8037 9000 #if ENABLE_ASH_BUILTIN_TEST 8038 { BUILTIN_REGULAR "[", testcmd }, 8039 { BUILTIN_REGULAR "[[", testcmd }, 9001 { BUILTIN_REGULAR "[" , testcmd }, 9002 #if ENABLE_ASH_BASH_COMPAT 9003 { BUILTIN_REGULAR "[[" , testcmd }, 9004 #endif 8040 9005 #endif 8041 9006 #if ENABLE_ASH_ALIAS 8042 { BUILTIN_REG_ASSG "alias" , aliascmd},9007 { BUILTIN_REG_ASSG "alias" , aliascmd }, 8043 9008 #endif 8044 9009 #if JOBS 8045 { BUILTIN_REGULAR "bg" , fg_bgcmd},8046 #endif 8047 { BUILTIN_SPEC_REG "break" , breakcmd},8048 { BUILTIN_REGULAR "cd" , cdcmd},8049 { BUILTIN_NOSPEC "chdir" , cdcmd},9010 { BUILTIN_REGULAR "bg" , fg_bgcmd }, 9011 #endif 9012 { BUILTIN_SPEC_REG "break" , breakcmd }, 9013 { BUILTIN_REGULAR "cd" , cdcmd }, 9014 { BUILTIN_NOSPEC "chdir" , cdcmd }, 8050 9015 #if ENABLE_ASH_CMDCMD 8051 { BUILTIN_REGULAR "command" , commandcmd },8052 #endif 8053 { BUILTIN_SPEC_REG "continue", breakcmd },9016 { BUILTIN_REGULAR "command" , commandcmd }, 9017 #endif 9018 { BUILTIN_SPEC_REG "continue", breakcmd }, 8054 9019 #if ENABLE_ASH_BUILTIN_ECHO 8055 { BUILTIN_REGULAR "echo" , echocmd},8056 #endif 8057 { BUILTIN_SPEC_REG "eval" , evalcmd},8058 { BUILTIN_SPEC_REG "exec" , execcmd},8059 { BUILTIN_SPEC_REG "exit" , exitcmd},8060 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd},8061 { BUILTIN_REGULAR "false" , falsecmd},9020 { BUILTIN_REGULAR "echo" , echocmd }, 9021 #endif 9022 { BUILTIN_SPEC_REG "eval" , evalcmd }, 9023 { BUILTIN_SPEC_REG "exec" , execcmd }, 9024 { BUILTIN_SPEC_REG "exit" , exitcmd }, 9025 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd }, 9026 { BUILTIN_REGULAR "false" , falsecmd }, 8062 9027 #if JOBS 8063 { BUILTIN_REGULAR "fg" , fg_bgcmd},9028 { BUILTIN_REGULAR "fg" , fg_bgcmd }, 8064 9029 #endif 8065 9030 #if ENABLE_ASH_GETOPTS 8066 { BUILTIN_REGULAR "getopts" , getoptscmd },8067 #endif 8068 { BUILTIN_NOSPEC "hash" , hashcmd},9031 { BUILTIN_REGULAR "getopts" , getoptscmd }, 9032 #endif 9033 { BUILTIN_NOSPEC "hash" , hashcmd }, 8069 9034 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8070 { BUILTIN_NOSPEC "help" , helpcmd},9035 { BUILTIN_NOSPEC "help" , helpcmd }, 8071 9036 #endif 8072 9037 #if JOBS 8073 { BUILTIN_REGULAR "jobs", jobscmd }, 8074 { BUILTIN_REGULAR "kill", killcmd }, 8075 #endif 8076 #if ENABLE_ASH_MATH_SUPPORT 8077 { BUILTIN_NOSPEC "let", letcmd }, 8078 #endif 8079 { BUILTIN_ASSIGN "local", localcmd }, 8080 { BUILTIN_NOSPEC "pwd", pwdcmd }, 8081 { BUILTIN_REGULAR "read", readcmd }, 8082 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 8083 { BUILTIN_SPEC_REG "return", returncmd }, 8084 { BUILTIN_SPEC_REG "set", setcmd }, 8085 { BUILTIN_SPEC_REG "shift", shiftcmd }, 8086 { BUILTIN_SPEC_REG "source", dotcmd }, 9038 { BUILTIN_REGULAR "jobs" , jobscmd }, 9039 { BUILTIN_REGULAR "kill" , killcmd }, 9040 #endif 9041 #if ENABLE_SH_MATH_SUPPORT 9042 { BUILTIN_NOSPEC "let" , letcmd }, 9043 #endif 9044 { BUILTIN_ASSIGN "local" , localcmd }, 9045 #if ENABLE_ASH_BUILTIN_PRINTF 9046 { BUILTIN_REGULAR "printf" , printfcmd }, 9047 #endif 9048 { BUILTIN_NOSPEC "pwd" , pwdcmd }, 9049 { BUILTIN_REGULAR "read" , readcmd }, 9050 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 9051 { BUILTIN_SPEC_REG "return" , returncmd }, 9052 { BUILTIN_SPEC_REG "set" , setcmd }, 9053 { BUILTIN_SPEC_REG "shift" , shiftcmd }, 9054 #if ENABLE_ASH_BASH_COMPAT 9055 { BUILTIN_SPEC_REG "source" , dotcmd }, 9056 #endif 8087 9057 #if ENABLE_ASH_BUILTIN_TEST 8088 { BUILTIN_REGULAR "test", testcmd},8089 #endif 8090 { BUILTIN_SPEC_REG "times" , timescmd},8091 { BUILTIN_SPEC_REG "trap" , trapcmd},8092 { BUILTIN_REGULAR "true" , truecmd},8093 { BUILTIN_NOSPEC "type" , typecmd},8094 { BUILTIN_NOSPEC "ulimit" , ulimitcmd},8095 { BUILTIN_REGULAR "umask" , umaskcmd},9058 { BUILTIN_REGULAR "test" , testcmd }, 9059 #endif 9060 { BUILTIN_SPEC_REG "times" , timescmd }, 9061 { BUILTIN_SPEC_REG "trap" , trapcmd }, 9062 { BUILTIN_REGULAR "true" , truecmd }, 9063 { BUILTIN_NOSPEC "type" , typecmd }, 9064 { BUILTIN_NOSPEC "ulimit" , ulimitcmd }, 9065 { BUILTIN_REGULAR "umask" , umaskcmd }, 8096 9066 #if ENABLE_ASH_ALIAS 8097 { BUILTIN_REGULAR "unalias" , unaliascmd },8098 #endif 8099 { BUILTIN_SPEC_REG "unset" , unsetcmd},8100 { BUILTIN_REGULAR "wait" , waitcmd},9067 { BUILTIN_REGULAR "unalias" , unaliascmd }, 9068 #endif 9069 { BUILTIN_SPEC_REG "unset" , unsetcmd }, 9070 { BUILTIN_REGULAR "wait" , waitcmd }, 8101 9071 }; 8102 9072 8103 8104 #define COMMANDCMD (builtintab + 5 + \ 8105 2 * ENABLE_ASH_BUILTIN_TEST + \ 8106 ENABLE_ASH_ALIAS + \ 8107 ENABLE_ASH_JOB_CONTROL) 8108 #define EXECCMD (builtintab + 7 + \ 8109 2 * ENABLE_ASH_BUILTIN_TEST + \ 8110 ENABLE_ASH_ALIAS + \ 8111 ENABLE_ASH_JOB_CONTROL + \ 8112 ENABLE_ASH_CMDCMD + \ 8113 ENABLE_ASH_BUILTIN_ECHO) 9073 /* Should match the above table! */ 9074 #define COMMANDCMD (builtintab + \ 9075 2 + \ 9076 1 * ENABLE_ASH_BUILTIN_TEST + \ 9077 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ 9078 1 * ENABLE_ASH_ALIAS + \ 9079 1 * ENABLE_ASH_JOB_CONTROL + \ 9080 3) 9081 #define EXECCMD (builtintab + \ 9082 2 + \ 9083 1 * ENABLE_ASH_BUILTIN_TEST + \ 9084 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ 9085 1 * ENABLE_ASH_ALIAS + \ 9086 1 * ENABLE_ASH_JOB_CONTROL + \ 9087 3 + \ 9088 1 * ENABLE_ASH_CMDCMD + \ 9089 1 + \ 9090 ENABLE_ASH_BUILTIN_ECHO + \ 9091 1) 8114 9092 8115 9093 /* … … 8131 9109 * Execute a simple command. 8132 9110 */ 8133 static int back_exitstatus; /* exit status of backquoted command */8134 9111 static int 8135 9112 isassignment(const char *p) … … 8140 9117 return *q == '='; 8141 9118 } 8142 static int 8143 bltincmd(int argc , char **argv)9119 static int FAST_FUNC 9120 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 8144 9121 { 8145 9122 /* Preserve exitstatus of a previous possible redirection … … 8150 9127 evalcommand(union node *cmd, int flags) 8151 9128 { 8152 static const struct builtincmd bltin = {8153 "\0\0", bltincmd 9129 static const struct builtincmd null_bltin = { 9130 "\0\0", bltincmd /* why three NULs? */ 8154 9131 }; 8155 9132 struct stackmark smark; … … 8165 9142 const char *path; 8166 9143 int spclbltin; 8167 int cmd_is_exec;8168 9144 int status; 8169 9145 char **nargv; 8170 9146 struct builtincmd *bcmd; 8171 int pseudovarflag = 0; 9147 smallint cmd_is_exec; 9148 smallint pseudovarflag = 0; 8172 9149 8173 9150 /* First expand the arguments. */ … … 8177 9154 8178 9155 cmdentry.cmdtype = CMDBUILTIN; 8179 cmdentry.u.cmd = & bltin;9156 cmdentry.u.cmd = &null_bltin; 8180 9157 varlist.lastp = &varlist.list; 8181 9158 *varlist.lastp = NULL; … … 8217 9194 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 8218 9195 8219 path = vpath. text;9196 path = vpath.var_text; 8220 9197 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 8221 9198 struct strlist **spp; … … 8230 9207 */ 8231 9208 p = (*spp)->text; 8232 if (var equal(p, path))9209 if (varcmp(p, path) == 0) 8233 9210 path = p; 8234 9211 } … … 8237 9214 if (xflag) { 8238 9215 int n; 8239 const char *p = " %s"; 8240 8241 p++; 8242 dprintf(preverrout_fd, p, expandstr(ps4val())); 8243 9216 const char *p = " %s" + 1; 9217 9218 fdprintf(preverrout_fd, p, expandstr(ps4val())); 8244 9219 sp = varlist.list; 8245 9220 for (n = 0; n < 2; n++) { 8246 9221 while (sp) { 8247 dprintf(preverrout_fd, p, sp->text);9222 fdprintf(preverrout_fd, p, sp->text); 8248 9223 sp = sp->next; 8249 if (*p == '%') { 8250 p--; 8251 } 9224 p = " %s"; 8252 9225 } 8253 9226 sp = arglist.list; 8254 9227 } 8255 full_write(preverrout_fd, "\n", 1);9228 safe_write(preverrout_fd, "\n", 1); 8256 9229 } 8257 9230 … … 8269 9242 find_command(argv[0], &cmdentry, cmd_flag, path); 8270 9243 if (cmdentry.cmdtype == CMDUNKNOWN) { 9244 flush_stdout_stderr(); 8271 9245 status = 127; 8272 flush_stderr();8273 9246 goto bail; 8274 9247 } … … 8280 9253 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 8281 9254 if (cmdentry.u.cmd == EXECCMD) 8282 cmd_is_exec ++;9255 cmd_is_exec = 1; 8283 9256 #if ENABLE_ASH_CMDCMD 8284 9257 if (cmdentry.u.cmd == COMMANDCMD) { … … 8307 9280 /* Execute the command. */ 8308 9281 switch (cmdentry.cmdtype) { 8309 default: 8310 /* Fork off a child process if necessary. */ 8311 if (!(flags & EV_EXIT) || trap[0]) { 9282 default: { 9283 9284 #if ENABLE_FEATURE_SH_NOFORK 9285 /* (1) BUG: if variables are set, we need to fork, or save/restore them 9286 * around run_nofork_applet() call. 9287 * (2) Should this check also be done in forkshell()? 9288 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...) 9289 */ 9290 /* find_command() encodes applet_no as (-2 - applet_no) */ 9291 int applet_no = (- cmdentry.u.index - 2); 9292 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { 9293 listsetvar(varlist.list, VEXPORT|VSTACK); 9294 /* run <applet>_main() */ 9295 exitstatus = run_nofork_applet(applet_no, argv); 9296 break; 9297 } 9298 #endif 9299 /* Can we avoid forking off? For example, very last command 9300 * in a script or a subshell does not need forking, 9301 * we can just exec it. 9302 */ 9303 if (!(flags & EV_EXIT) || may_have_traps) { 9304 /* No, forking off a child is necessary */ 8312 9305 INT_OFF; 8313 jp = makejob( cmd,1);9306 jp = makejob(/*cmd,*/ 1); 8314 9307 if (forkshell(jp, cmd, FORK_FG) != 0) { 9308 /* parent */ 8315 9309 exitstatus = waitforjob(jp); 8316 9310 INT_ON; 9311 TRACE(("forked child exited with %d\n", exitstatus)); 8317 9312 break; 8318 9313 } 9314 /* child */ 8319 9315 FORCE_INT_ON; 9316 /* fall through to exec'ing external program */ 8320 9317 } 8321 9318 listsetvar(varlist.list, VEXPORT|VSTACK); 8322 9319 shellexec(argv, path, cmdentry.u.index); 8323 9320 /* NOTREACHED */ 8324 9321 } /* default */ 8325 9322 case CMDBUILTIN: 8326 9323 cmdenviron = varlist.list; … … 8335 9332 listsetvar(list, i); 8336 9333 } 9334 /* Tight loop with builtins only: 9335 * "while kill -0 $child; do true; done" 9336 * will never exit even if $child died, unless we do this 9337 * to reap the zombie and make kill detect that it's gone: */ 9338 dowait(DOWAIT_NONBLOCK, NULL); 9339 8337 9340 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 8338 9341 int exit_status; 8339 int i, j; 8340 8341 i = exception; 9342 int i = exception_type; 8342 9343 if (i == EXEXIT) 8343 9344 goto raise; 8344 8345 9345 exit_status = 2; 8346 j = 0;8347 9346 if (i == EXINT) 8348 j =SIGINT;9347 exit_status = 128 + SIGINT; 8349 9348 if (i == EXSIG) 8350 j = pendingsig; 8351 if (j) 8352 exit_status = j + 128; 9349 exit_status = 128 + pending_sig; 8353 9350 exitstatus = exit_status; 8354 8355 9351 if (i == EXINT || spclbltin > 0) { 8356 9352 raise: … … 8363 9359 case CMDFUNCTION: 8364 9360 listsetvar(varlist.list, 0); 9361 /* See above for the rationale */ 9362 dowait(DOWAIT_NONBLOCK, NULL); 8365 9363 if (evalfun(cmdentry.u.func, argc, argv, flags)) 8366 9364 goto raise; 8367 9365 break; 8368 } 9366 9367 } /* switch */ 8369 9368 8370 9369 out: 8371 popredir( cmd_is_exec);8372 if (lastarg) 9370 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec); 9371 if (lastarg) { 8373 9372 /* dsl: I think this is intended to be used to support 8374 9373 * '_' in 'vi' command mode during line editing... … … 8376 9375 */ 8377 9376 setvar("_", lastarg, 0); 9377 } 8378 9378 popstackmark(&smark); 8379 9379 } … … 8402 9402 clearerr(stdout); 8403 9403 commandname = savecmdname; 8404 exsig = 0;8405 9404 exception_handler = savehandler; 8406 9405 … … 8411 9410 goodname(const char *p) 8412 9411 { 8413 return !*endofname(p);9412 return endofname(p)[0] == '\0'; 8414 9413 } 8415 9414 … … 8447 9446 * in the standard shell so we don't make it one here. 8448 9447 */ 8449 static int 8450 breakcmd(int argc , char **argv)8451 { 8452 int n = arg c > 1? number(argv[1]) : 1;9448 static int FAST_FUNC 9449 breakcmd(int argc UNUSED_PARAM, char **argv) 9450 { 9451 int n = argv[1] ? number(argv[1]) : 1; 8453 9452 8454 9453 if (n <= 0) 8455 ash_msg_and_raise_error( illnum, argv[1]);9454 ash_msg_and_raise_error(msg_illnum, argv[1]); 8456 9455 if (n > loopnest) 8457 9456 n = loopnest; … … 8469 9468 */ 8470 9469 8471 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */8472 8473 9470 enum { 8474 9471 INPUT_PUSH_FILE = 1, … … 8476 9473 }; 8477 9474 8478 /* 8479 * NEOF is returned by parsecmd when it encounters an end of file. It 8480 * must be distinct from NULL, so we use the address of a variable that 8481 * happens to be handy. 8482 */ 8483 static int plinno = 1; /* input line number */ 8484 /* number of characters left in input buffer */ 8485 static int parsenleft; /* copy of parsefile->nleft */ 8486 static int parselleft; /* copy of parsefile->lleft */ 8487 /* next character in input buffer */ 8488 static char *parsenextc; /* copy of parsefile->nextc */ 8489 8490 static int checkkwd; 9475 static smallint checkkwd; 8491 9476 /* values of checkkwd variable */ 8492 9477 #define CHKALIAS 0x1 … … 8494 9479 #define CHKNL 0x4 8495 9480 9481 /* 9482 * Push a string back onto the input at this current parsefile level. 9483 * We handle aliases this way. 9484 */ 9485 #if !ENABLE_ASH_ALIAS 9486 #define pushstring(s, ap) pushstring(s) 9487 #endif 9488 static void 9489 pushstring(char *s, struct alias *ap) 9490 { 9491 struct strpush *sp; 9492 int len; 9493 9494 len = strlen(s); 9495 INT_OFF; 9496 if (g_parsefile->strpush) { 9497 sp = ckzalloc(sizeof(*sp)); 9498 sp->prev = g_parsefile->strpush; 9499 } else { 9500 sp = &(g_parsefile->basestrpush); 9501 } 9502 g_parsefile->strpush = sp; 9503 sp->prev_string = g_parsefile->next_to_pgetc; 9504 sp->prev_left_in_line = g_parsefile->left_in_line; 9505 #if ENABLE_ASH_ALIAS 9506 sp->ap = ap; 9507 if (ap) { 9508 ap->flag |= ALIASINUSE; 9509 sp->string = s; 9510 } 9511 #endif 9512 g_parsefile->next_to_pgetc = s; 9513 g_parsefile->left_in_line = len; 9514 INT_ON; 9515 } 9516 8496 9517 static void 8497 9518 popstring(void) 8498 9519 { 8499 struct strpush *sp = parsefile->strpush;9520 struct strpush *sp = g_parsefile->strpush; 8500 9521 8501 9522 INT_OFF; 8502 9523 #if ENABLE_ASH_ALIAS 8503 9524 if (sp->ap) { 8504 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 9525 if (g_parsefile->next_to_pgetc[-1] == ' ' 9526 || g_parsefile->next_to_pgetc[-1] == '\t' 9527 ) { 8505 9528 checkkwd |= CHKALIAS; 8506 9529 } … … 8514 9537 } 8515 9538 #endif 8516 parsenextc = sp->prevstring; 8517 parsenleft = sp->prevnleft; 8518 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 8519 parsefile->strpush = sp->prev; 8520 if (sp != &(parsefile->basestrpush)) 9539 g_parsefile->next_to_pgetc = sp->prev_string; 9540 g_parsefile->left_in_line = sp->prev_left_in_line; 9541 g_parsefile->strpush = sp->prev; 9542 if (sp != &(g_parsefile->basestrpush)) 8521 9543 free(sp); 8522 9544 INT_ON; 8523 9545 } 8524 9546 9547 //FIXME: BASH_COMPAT with "...&" does TWO pungetc(): 9548 //it peeks whether it is &>, and then pushes back both chars. 9549 //This function needs to save last *next_to_pgetc to buf[0] 9550 //to make two pungetc() reliable. Currently, 9551 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work... 8525 9552 static int 8526 9553 preadfd(void) 8527 9554 { 8528 9555 int nr; 8529 char *buf = parsefile->buf; 8530 parsenextc = buf; 8531 9556 char *buf = g_parsefile->buf; 9557 9558 g_parsefile->next_to_pgetc = buf; 9559 #if ENABLE_FEATURE_EDITING 8532 9560 retry: 8533 #if ENABLE_FEATURE_EDITING 8534 if (!iflag || parsefile->fd) 8535 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 9561 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 9562 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 8536 9563 else { 8537 9564 #if ENABLE_FEATURE_TAB_COMPLETION 8538 9565 line_input_state->path_lookup = pathval(); 8539 9566 #endif 8540 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);9567 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); 8541 9568 if (nr == 0) { 8542 9569 /* Ctrl+C pressed */ … … 8550 9577 } 8551 9578 if (nr < 0 && errno == 0) { 8552 /* Ctrl+D pres end */9579 /* Ctrl+D pressed */ 8553 9580 nr = 0; 8554 9581 } 8555 9582 } 8556 9583 #else 8557 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8558 #endif 8559 9584 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 9585 #endif 9586 9587 #if 0 9588 /* nonblock_safe_read() handles this problem */ 8560 9589 if (nr < 0) { 8561 9590 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 8562 9591 int flags = fcntl(0, F_GETFL); 8563 if (flags >= 0 && flags & O_NONBLOCK) {8564 flags &= ~O_NONBLOCK;9592 if (flags >= 0 && (flags & O_NONBLOCK)) { 9593 flags &= ~O_NONBLOCK; 8565 9594 if (fcntl(0, F_SETFL, flags) >= 0) { 8566 9595 out2str("sh: turning off NDELAY mode\n"); … … 8570 9599 } 8571 9600 } 9601 #endif 8572 9602 return nr; 8573 9603 } … … 8577 9607 * 8578 9608 * 1) If a string was pushed back on the input, pop it; 8579 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 8580 * from a string so we can't refill the buffer, return EOF. 8581 * 3) If the is more stuff in this buffer, use it else call read to fill it. 9609 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM) 9610 * or we are reading from a string so we can't refill the buffer, 9611 * return EOF. 9612 * 3) If there is more stuff in this buffer, use it else call read to fill it. 8582 9613 * 4) Process input up to the next newline, deleting nul characters. 8583 9614 */ 9615 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) 9616 #define pgetc_debug(...) ((void)0) 8584 9617 static int 8585 9618 preadbuffer(void) … … 8587 9620 char *q; 8588 9621 int more; 8589 char savec; 8590 8591 while (parsefile->strpush) { 9622 9623 while (g_parsefile->strpush) { 8592 9624 #if ENABLE_ASH_ALIAS 8593 if (parsenleft == -1 && parsefile->strpush->ap && 8594 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 9625 if (g_parsefile->left_in_line == -1 9626 && g_parsefile->strpush->ap 9627 && g_parsefile->next_to_pgetc[-1] != ' ' 9628 && g_parsefile->next_to_pgetc[-1] != '\t' 9629 ) { 9630 pgetc_debug("preadbuffer PEOA"); 8595 9631 return PEOA; 8596 9632 } 8597 9633 #endif 8598 9634 popstring(); 8599 if (--parsenleft >= 0) 8600 return signed_char2int(*parsenextc++); 8601 } 8602 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 9635 /* try "pgetc" now: */ 9636 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'", 9637 g_parsefile->left_in_line, 9638 g_parsefile->next_to_pgetc, 9639 g_parsefile->next_to_pgetc); 9640 if (--g_parsefile->left_in_line >= 0) 9641 return (unsigned char)(*g_parsefile->next_to_pgetc++); 9642 } 9643 /* on both branches above g_parsefile->left_in_line < 0. 9644 * "pgetc" needs refilling. 9645 */ 9646 9647 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read", 9648 * pungetc() may increment it a few times. 9649 * Assuming it won't increment it to less than -90. 9650 */ 9651 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) { 9652 pgetc_debug("preadbuffer PEOF1"); 9653 /* even in failure keep left_in_line and next_to_pgetc 9654 * in lock step, for correct multi-layer pungetc. 9655 * left_in_line was decremented before preadbuffer(), 9656 * must inc next_to_pgetc: */ 9657 g_parsefile->next_to_pgetc++; 8603 9658 return PEOF; 8604 flush_stdout_stderr();8605 8606 more = parselleft;9659 } 9660 9661 more = g_parsefile->left_in_buffer; 8607 9662 if (more <= 0) { 9663 flush_stdout_stderr(); 8608 9664 again: 8609 9665 more = preadfd(); 8610 9666 if (more <= 0) { 8611 parselleft = parsenleft = EOF_NLEFT; 9667 /* don't try reading again */ 9668 g_parsefile->left_in_line = -99; 9669 pgetc_debug("preadbuffer PEOF2"); 9670 g_parsefile->next_to_pgetc++; 8612 9671 return PEOF; 8613 9672 } 8614 9673 } 8615 9674 8616 q = parsenextc; 8617 8618 /* delete nul characters */ 9675 /* Find out where's the end of line. 9676 * Set g_parsefile->left_in_line 9677 * and g_parsefile->left_in_buffer acordingly. 9678 * NUL chars are deleted. 9679 */ 9680 q = g_parsefile->next_to_pgetc; 8619 9681 for (;;) { 8620 intc;9682 char c; 8621 9683 8622 9684 more--; 9685 8623 9686 c = *q; 8624 8625 if (!c) 9687 if (c == '\0') { 8626 9688 memmove(q, q + 1, more); 8627 else {9689 } else { 8628 9690 q++; 8629 9691 if (c == '\n') { 8630 parsenleft = q - parsenextc - 1;9692 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1; 8631 9693 break; 8632 9694 } … … 8634 9696 8635 9697 if (more <= 0) { 8636 parsenleft = q - parsenextc - 1;8637 if ( parsenleft< 0)9698 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1; 9699 if (g_parsefile->left_in_line < 0) 8638 9700 goto again; 8639 9701 break; 8640 9702 } 8641 9703 } 8642 parselleft = more; 8643 8644 savec = *q; 8645 *q = '\0'; 9704 g_parsefile->left_in_buffer = more; 8646 9705 8647 9706 if (vflag) { 8648 out2str(parsenextc); 8649 } 8650 8651 *q = savec; 8652 8653 return signed_char2int(*parsenextc++); 8654 } 8655 8656 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer()) 9707 char save = *q; 9708 *q = '\0'; 9709 out2str(g_parsefile->next_to_pgetc); 9710 *q = save; 9711 } 9712 9713 pgetc_debug("preadbuffer at %d:%p'%s'", 9714 g_parsefile->left_in_line, 9715 g_parsefile->next_to_pgetc, 9716 g_parsefile->next_to_pgetc); 9717 return (unsigned char)*g_parsefile->next_to_pgetc++; 9718 } 9719 9720 #define pgetc_as_macro() \ 9721 (--g_parsefile->left_in_line >= 0 \ 9722 ? (unsigned char)*g_parsefile->next_to_pgetc++ \ 9723 : preadbuffer() \ 9724 ) 9725 8657 9726 static int 8658 9727 pgetc(void) 8659 9728 { 9729 pgetc_debug("pgetc_fast at %d:%p'%s'", 9730 g_parsefile->left_in_line, 9731 g_parsefile->next_to_pgetc, 9732 g_parsefile->next_to_pgetc); 8660 9733 return pgetc_as_macro(); 8661 9734 } 8662 9735 8663 9736 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 8664 # define pgetc_macro() pgetc()9737 # define pgetc_fast() pgetc() 8665 9738 #else 8666 #define pgetc_macro() pgetc_as_macro() 8667 #endif 8668 8669 /* 8670 * Same as pgetc(), but ignores PEOA. 8671 */ 9739 # define pgetc_fast() pgetc_as_macro() 9740 #endif 9741 8672 9742 #if ENABLE_ASH_ALIAS 8673 9743 static int 8674 pgetc 2(void)9744 pgetc_without_PEOA(void) 8675 9745 { 8676 9746 int c; 8677 8678 9747 do { 8679 c = pgetc_macro(); 9748 pgetc_debug("pgetc_fast at %d:%p'%s'", 9749 g_parsefile->left_in_line, 9750 g_parsefile->next_to_pgetc, 9751 g_parsefile->next_to_pgetc); 9752 c = pgetc_fast(); 8680 9753 } while (c == PEOA); 8681 9754 return c; 8682 9755 } 8683 9756 #else 8684 static int 8685 pgetc2(void) 8686 { 8687 return pgetc_macro(); 8688 } 9757 # define pgetc_without_PEOA() pgetc() 8689 9758 #endif 8690 9759 … … 8700 9769 8701 9770 while (--nleft > 0) { 8702 c = pgetc 2();9771 c = pgetc_without_PEOA(); 8703 9772 if (c == PEOF) { 8704 9773 if (p == line) … … 8721 9790 pungetc(void) 8722 9791 { 8723 parsenleft++; 8724 parsenextc--; 8725 } 8726 8727 /* 8728 * Push a string back onto the input at this current parsefile level. 8729 * We handle aliases this way. 8730 */ 8731 static void 8732 pushstring(char *s, void *ap) 8733 { 8734 struct strpush *sp; 8735 size_t len; 8736 8737 len = strlen(s); 8738 INT_OFF; 8739 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 8740 if (parsefile->strpush) { 8741 sp = ckmalloc(sizeof(struct strpush)); 8742 sp->prev = parsefile->strpush; 8743 parsefile->strpush = sp; 8744 } else 8745 sp = parsefile->strpush = &(parsefile->basestrpush); 8746 sp->prevstring = parsenextc; 8747 sp->prevnleft = parsenleft; 8748 #if ENABLE_ASH_ALIAS 8749 sp->ap = (struct alias *)ap; 8750 if (ap) { 8751 ((struct alias *)ap)->flag |= ALIASINUSE; 8752 sp->string = s; 8753 } 8754 #endif 8755 parsenextc = s; 8756 parsenleft = len; 8757 INT_ON; 9792 g_parsefile->left_in_line++; 9793 g_parsefile->next_to_pgetc--; 9794 pgetc_debug("pushed back to %d:%p'%s'", 9795 g_parsefile->left_in_line, 9796 g_parsefile->next_to_pgetc, 9797 g_parsefile->next_to_pgetc); 8758 9798 } 8759 9799 … … 8767 9807 struct parsefile *pf; 8768 9808 8769 parsefile->nleft = parsenleft; 8770 parsefile->lleft = parselleft; 8771 parsefile->nextc = parsenextc; 8772 parsefile->linno = plinno; 8773 pf = ckmalloc(sizeof(*pf)); 8774 pf->prev = parsefile; 8775 pf->fd = -1; 8776 pf->strpush = NULL; 8777 pf->basestrpush.prev = NULL; 8778 parsefile = pf; 9809 pf = ckzalloc(sizeof(*pf)); 9810 pf->prev = g_parsefile; 9811 pf->pf_fd = -1; 9812 /*pf->strpush = NULL; - ckzalloc did it */ 9813 /*pf->basestrpush.prev = NULL;*/ 9814 g_parsefile = pf; 8779 9815 } 8780 9816 … … 8782 9818 popfile(void) 8783 9819 { 8784 struct parsefile *pf = parsefile;9820 struct parsefile *pf = g_parsefile; 8785 9821 8786 9822 INT_OFF; 8787 if (pf->fd >= 0) 8788 close(pf->fd); 8789 if (pf->buf) 8790 free(pf->buf); 9823 if (pf->pf_fd >= 0) 9824 close(pf->pf_fd); 9825 free(pf->buf); 8791 9826 while (pf->strpush) 8792 9827 popstring(); 8793 parsefile = pf->prev;9828 g_parsefile = pf->prev; 8794 9829 free(pf); 8795 parsenleft = parsefile->nleft;8796 parselleft = parsefile->lleft;8797 parsenextc = parsefile->nextc;8798 plinno = parsefile->linno;8799 9830 INT_ON; 8800 9831 } … … 8806 9837 popallfiles(void) 8807 9838 { 8808 while ( parsefile != &basepf)9839 while (g_parsefile != &basepf) 8809 9840 popfile(); 8810 9841 } … … 8818 9849 { 8819 9850 popallfiles(); 8820 if ( parsefile->fd > 0) {8821 close( parsefile->fd);8822 parsefile->fd = 0;9851 if (g_parsefile->pf_fd > 0) { 9852 close(g_parsefile->pf_fd); 9853 g_parsefile->pf_fd = 0; 8823 9854 } 8824 9855 } … … 8831 9862 setinputfd(int fd, int push) 8832 9863 { 8833 fcntl(fd, F_SETFD, FD_CLOEXEC);9864 close_on_exec_on(fd); 8834 9865 if (push) { 8835 9866 pushfile(); 8836 parsefile->buf = 0; 8837 } 8838 parsefile->fd = fd; 8839 if (parsefile->buf == NULL) 8840 parsefile->buf = ckmalloc(IBUFSIZ); 8841 parselleft = parsenleft = 0; 8842 plinno = 1; 9867 g_parsefile->buf = NULL; 9868 } 9869 g_parsefile->pf_fd = fd; 9870 if (g_parsefile->buf == NULL) 9871 g_parsefile->buf = ckmalloc(IBUFSIZ); 9872 g_parsefile->left_in_buffer = 0; 9873 g_parsefile->left_in_line = 0; 9874 g_parsefile->linno = 1; 8843 9875 } 8844 9876 … … 8858 9890 if (flags & INPUT_NOFILE_OK) 8859 9891 goto out; 8860 ash_msg_and_raise_error("can't open %s", fname);9892 ash_msg_and_raise_error("can't open '%s'", fname); 8861 9893 } 8862 9894 if (fd < 10) { … … 8881 9913 INT_OFF; 8882 9914 pushfile(); 8883 parsenextc = string;8884 parsenleft= strlen(string);8885 parsefile->buf = NULL;8886 plinno = 1;9915 g_parsefile->next_to_pgetc = string; 9916 g_parsefile->left_in_line = strlen(string); 9917 g_parsefile->buf = NULL; 9918 g_parsefile->linno = 1; 8887 9919 INT_ON; 8888 9920 } … … 8901 9933 static time_t mailtime[MAXMBOXES]; 8902 9934 /* Set if MAIL or MAILPATH is changed. */ 8903 static int mail_var_path_changed;9935 static smallint mail_var_path_changed; 8904 9936 8905 9937 /* … … 8922 9954 mpath = mpathset() ? mpathval() : mailval(); 8923 9955 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { 8924 p = pa dvance(&mpath, nullstr);9956 p = path_advance(&mpath, nullstr); 8925 9957 if (p == NULL) 8926 9958 break; 8927 9959 if (*p == '\0') 8928 9960 continue; 8929 for (q = p; *q; q++); 9961 for (q = p; *q; q++) 9962 continue; 8930 9963 #if DEBUG 8931 9964 if (q[-1] != '/') … … 8939 9972 if (!mail_var_path_changed && statb.st_mtime != *mtp) { 8940 9973 fprintf( 8941 stderr, snlfmt,9974 stderr, "%s\n", 8942 9975 pathopt ? pathopt : "you have mail" 8943 9976 ); … … 8949 9982 } 8950 9983 8951 static void 8952 changemail(const char *val )8953 { 8954 mail_var_path_changed ++;9984 static void FAST_FUNC 9985 changemail(const char *val UNUSED_PARAM) 9986 { 9987 mail_var_path_changed = 1; 8955 9988 } 8956 9989 … … 8970 10003 int nparam; 8971 10004 8972 for (nparam = 0; argv[nparam]; nparam++); 10005 for (nparam = 0; argv[nparam]; nparam++) 10006 continue; 8973 10007 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); 8974 10008 while (*argv) { … … 8977 10011 *ap = NULL; 8978 10012 freeparam(&shellparam); 8979 shellparam.malloc = 1;10013 shellparam.malloced = 1; 8980 10014 shellparam.nparam = nparam; 8981 10015 shellparam.p = newparam; … … 8989 10023 * Process shell options. The global variable argptr contains a pointer 8990 10024 * to the argument list; we advance it past the options. 8991 */ 8992 static void 8993 minus_o(char *name, int val) 10025 * 10026 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says: 10027 * For a non-interactive shell, an error condition encountered 10028 * by a special built-in ... shall cause the shell to write a diagnostic message 10029 * to standard error and exit as shown in the following table: 10030 * Error Special Built-In 10031 * ... 10032 * Utility syntax error (option or operand error) Shall exit 10033 * ... 10034 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142) 10035 * we see that bash does not do that (set "finishes" with error code 1 instead, 10036 * and shell continues), and people rely on this behavior! 10037 * Testcase: 10038 * set -o barfoo 2>/dev/null 10039 * echo $? 10040 * 10041 * Oh well. Let's mimic that. 10042 */ 10043 static int 10044 plus_minus_o(char *name, int val) 8994 10045 { 8995 10046 int i; … … 8999 10050 if (strcmp(name, optnames(i)) == 0) { 9000 10051 optlist[i] = val; 9001 return ;10052 return 0; 9002 10053 } 9003 10054 } 9004 ash_msg_and_raise_error("illegal option -o %s", name); 9005 } 9006 out1str("Current option settings\n"); 9007 for (i = 0; i < NOPTS; i++) 9008 out1fmt("%-16s%s\n", optnames(i), 9009 optlist[i] ? "on" : "off"); 10055 ash_msg("illegal option %co %s", val ? '-' : '+', name); 10056 return 1; 10057 } 10058 for (i = 0; i < NOPTS; i++) { 10059 if (val) { 10060 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off"); 10061 } else { 10062 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i)); 10063 } 10064 } 10065 return 0; 9010 10066 } 9011 10067 static void … … 9020 10076 } 9021 10077 } 9022 ash_msg_and_raise_error("illegal option -%c", flag);10078 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag); 9023 10079 /* NOTREACHED */ 9024 10080 } 9025 static void10081 static int 9026 10082 options(int cmdline) 9027 10083 { … … 9058 10114 minusc = p; /* command is after shell args */ 9059 10115 } else if (c == 'o') { 9060 minus_o(*argptr, val); 10116 if (plus_minus_o(*argptr, val)) { 10117 /* it already printed err message */ 10118 return 1; /* error */ 10119 } 9061 10120 if (*argptr) 9062 10121 argptr++; … … 9073 10132 } 9074 10133 } 10134 return 0; 9075 10135 } 9076 10136 … … 9078 10138 * The shift builtin command. 9079 10139 */ 9080 static int 9081 shiftcmd(int argc , char **argv)10140 static int FAST_FUNC 10141 shiftcmd(int argc UNUSED_PARAM, char **argv) 9082 10142 { 9083 10143 int n; … … 9085 10145 9086 10146 n = 1; 9087 if (arg c > 1)10147 if (argv[1]) 9088 10148 n = number(argv[1]); 9089 10149 if (n > shellparam.nparam) 9090 ash_msg_and_raise_error("can't shift that many");10150 n = 0; /* bash compat, was = shellparam.nparam; */ 9091 10151 INT_OFF; 9092 10152 shellparam.nparam -= n; 9093 10153 for (ap1 = shellparam.p; --n >= 0; ap1++) { 9094 if (shellparam.malloc )10154 if (shellparam.malloced) 9095 10155 free(*ap1); 9096 10156 } 9097 10157 ap2 = shellparam.p; 9098 while ((*ap2++ = *ap1++) != NULL); 10158 while ((*ap2++ = *ap1++) != NULL) 10159 continue; 9099 10160 #if ENABLE_ASH_GETOPTS 9100 10161 shellparam.optind = 1; … … 9139 10200 * The set command builtin. 9140 10201 */ 9141 static int 9142 setcmd(int argc, char **argv) 9143 { 9144 if (argc == 1) 10202 static int FAST_FUNC 10203 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 10204 { 10205 int retval; 10206 10207 if (!argv[1]) 9145 10208 return showvars(nullstr, 0, VUNSET); 9146 10209 INT_OFF; 9147 options(0); 9148 optschanged(); 9149 if (*argptr != NULL) { 9150 setparam(argptr); 10210 retval = 1; 10211 if (!options(0)) { /* if no parse error... */ 10212 retval = 0; 10213 optschanged(); 10214 if (*argptr != NULL) { 10215 setparam(argptr); 10216 } 9151 10217 } 9152 10218 INT_ON; 9153 return 0;10219 return retval; 9154 10220 } 9155 10221 9156 10222 #if ENABLE_ASH_RANDOM_SUPPORT 9157 /* Roughly copied from bash.. */ 9158 static void 10223 static void FAST_FUNC 9159 10224 change_random(const char *value) 9160 10225 { 10226 uint32_t t; 10227 9161 10228 if (value == NULL) { 9162 10229 /* "get", generate */ 9163 char buf[16]; 9164 9165 rseed = rseed * 1103515245 + 12345; 9166 sprintf(buf, "%d", (unsigned int)((rseed & 32767))); 10230 t = next_random(&random_gen); 9167 10231 /* set without recursion */ 9168 setvar(vrandom. text, buf, VNOFUNC);10232 setvar(vrandom.var_text, utoa(t), VNOFUNC); 9169 10233 vrandom.flags &= ~VNOFUNC; 9170 10234 } else { 9171 10235 /* set/reset */ 9172 rseed = strtoul(value, (char **)NULL, 10); 10236 t = strtoul(value, NULL, 10); 10237 INIT_RANDOM_T(&random_gen, (t ? t : 1), t); 9173 10238 } 9174 10239 } … … 9190 10255 optnext = optfirst + *param_optind - 1; 9191 10256 9192 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)10257 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff) 9193 10258 p = NULL; 9194 10259 else … … 9209 10274 9210 10275 c = *p++; 9211 for (q = optstr; *q != c; 10276 for (q = optstr; *q != c;) { 9212 10277 if (*q == '\0') { 9213 10278 if (optstr[0] == ':') { … … 9270 10335 * then it's the first time getopts has been called. 9271 10336 */ 9272 static int 10337 static int FAST_FUNC 9273 10338 getoptscmd(int argc, char **argv) 9274 10339 { … … 9299 10364 /* ============ Shell parser */ 9300 10365 9301 static int tokpushback; /* last token pushed back */ 9302 #define NEOF ((union node *)&tokpushback) 9303 static int parsebackquote; /* nonzero if we are inside backquotes */ 9304 static int lasttoken; /* last token read */ 10366 struct heredoc { 10367 struct heredoc *next; /* next here document in list */ 10368 union node *here; /* redirection node */ 10369 char *eofmark; /* string indicating end of input */ 10370 smallint striptabs; /* if set, strip leading tabs */ 10371 }; 10372 10373 static smallint tokpushback; /* last token pushed back */ 10374 static smallint parsebackquote; /* nonzero if we are inside backquotes */ 10375 static smallint quoteflag; /* set if (part of) last token was quoted */ 10376 static token_id_t lasttoken; /* last token read (integer id Txxx) */ 10377 static struct heredoc *heredoclist; /* list of here documents to read */ 9305 10378 static char *wordtext; /* text of last word returned by readtoken */ 9306 10379 static struct nodelist *backquotelist; 9307 10380 static union node *redirnode; 9308 10381 static struct heredoc *heredoc; 9309 static int quoteflag; /* set if (part of) last token was quoted */ 9310 9311 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; 9312 static void 9313 raise_error_syntax(const char *msg)9314 { 9315 ash_msg_and_raise_error("syntax error: %s", msg);9316 /* NOTREACHED */9317 } 9318 9319 /* 10382 10383 static const char * 10384 tokname(char *buf, int tok) 10385 { 10386 if (tok < TSEMI) 10387 return tokname_array[tok] + 1; 10388 sprintf(buf, "\"%s\"", tokname_array[tok] + 1); 10389 return buf; 10390 } 10391 10392 /* raise_error_unexpected_syntax: 9320 10393 * Called when an unexpected token is read during the parse. The argument 9321 10394 * is the token that is expected, or -1 if more than one type of token can 9322 10395 * occur at this point. 9323 10396 */ 9324 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;10397 static void raise_error_unexpected_syntax(int) NORETURN; 9325 10398 static void 9326 10399 raise_error_unexpected_syntax(int token) 9327 10400 { 9328 10401 char msg[64]; 10402 char buf[16]; 9329 10403 int l; 9330 10404 9331 l = sprintf(msg, " %s unexpected", tokname(lasttoken));10405 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken)); 9332 10406 if (token >= 0) 9333 sprintf(msg + l, " (expecting %s)", tokname( token));10407 sprintf(msg + l, " (expecting %s)", tokname(buf, token)); 9334 10408 raise_error_syntax(msg); 9335 10409 /* NOTREACHED */ … … 9337 10411 9338 10412 #define EOFMARKLEN 79 9339 9340 struct heredoc {9341 struct heredoc *next; /* next here document in list */9342 union node *here; /* redirection node */9343 char *eofmark; /* string indicating end of input */9344 int striptabs; /* if set, strip leading tabs */9345 };9346 9347 static struct heredoc *heredoclist; /* list of here documents to read */9348 10413 9349 10414 /* parsing is heavily cross-recursive, need these forward decls */ … … 9370 10435 if (tok == TBACKGND) { 9371 10436 if (n2->type == NPIPE) { 9372 n2->npipe. backgnd = 1;10437 n2->npipe.pipe_backgnd = 1; 9373 10438 } else { 9374 10439 if (n2->type != NREDIR) { 9375 n3 = st alloc(sizeof(struct nredir));10440 n3 = stzalloc(sizeof(struct nredir)); 9376 10441 n3->nredir.n = n2; 9377 n3->nredir.redirect = NULL;10442 /*n3->nredir.redirect = NULL; - stzalloc did it */ 9378 10443 n2 = n3; 9379 10444 } … … 9384 10449 n1 = n2; 9385 10450 } else { 9386 n3 = st alloc(sizeof(struct nbinary));10451 n3 = stzalloc(sizeof(struct nbinary)); 9387 10452 n3->type = NSEMI; 9388 10453 n3->nbinary.ch1 = n1; … … 9401 10466 return n1; 9402 10467 } else { 9403 tokpushback ++;10468 tokpushback = 1; 9404 10469 } 9405 10470 checkkwd = CHKNL | CHKKWD | CHKALIAS; … … 9416 10481 if (nlflag == 1) 9417 10482 raise_error_unexpected_syntax(-1); 9418 tokpushback ++;10483 tokpushback = 1; 9419 10484 return n1; 9420 10485 } … … 9436 10501 t = NOR; 9437 10502 } else { 9438 tokpushback ++;10503 tokpushback = 1; 9439 10504 return n1; 9440 10505 } 9441 10506 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9442 10507 n2 = pipeline(); 9443 n3 = st alloc(sizeof(struct nbinary));10508 n3 = stzalloc(sizeof(struct nbinary)); 9444 10509 n3->type = t; 9445 10510 n3->nbinary.ch1 = n1; … … 9462 10527 checkkwd = CHKKWD | CHKALIAS; 9463 10528 } else 9464 tokpushback ++;10529 tokpushback = 1; 9465 10530 n1 = parse_command(); 9466 10531 if (readtoken() == TPIPE) { 9467 pipenode = st alloc(sizeof(struct npipe));10532 pipenode = stzalloc(sizeof(struct npipe)); 9468 10533 pipenode->type = NPIPE; 9469 pipenode->npipe.backgnd = 0;9470 lp = st alloc(sizeof(struct nodelist));10534 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */ 10535 lp = stzalloc(sizeof(struct nodelist)); 9471 10536 pipenode->npipe.cmdlist = lp; 9472 10537 lp->n = n1; 9473 10538 do { 9474 10539 prev = lp; 9475 lp = st alloc(sizeof(struct nodelist));10540 lp = stzalloc(sizeof(struct nodelist)); 9476 10541 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9477 10542 lp->n = parse_command(); … … 9481 10546 n1 = pipenode; 9482 10547 } 9483 tokpushback ++;10548 tokpushback = 1; 9484 10549 if (negate) { 9485 n2 = st alloc(sizeof(struct nnot));10550 n2 = stzalloc(sizeof(struct nnot)); 9486 10551 n2->type = NNOT; 9487 10552 n2->nnot.com = n1; … … 9496 10561 union node *n; 9497 10562 9498 n = st alloc(sizeof(struct narg));10563 n = stzalloc(sizeof(struct narg)); 9499 10564 n->type = NARG; 9500 n->narg.next = NULL;10565 /*n->narg.next = NULL; - stzalloc did it */ 9501 10566 n->narg.text = wordtext; 9502 10567 n->narg.backquote = backquotelist; … … 9507 10572 fixredir(union node *n, const char *text, int err) 9508 10573 { 10574 int fd; 10575 9509 10576 TRACE(("Fix redir %s %d\n", text, err)); 9510 10577 if (!err) 9511 10578 n->ndup.vname = NULL; 9512 10579 9513 if (isdigit(text[0]) && text[1] == '\0') 9514 n->ndup.dupfd = text[0] - '0'; 10580 fd = bb_strtou(text, NULL, 10); 10581 if (!errno && fd >= 0) 10582 n->ndup.dupfd = fd; 9515 10583 else if (LONE_DASH(text)) 9516 10584 n->ndup.dupfd = -1; 9517 10585 else { 9518 10586 if (err) 9519 raise_error_syntax(" Bad fd number");10587 raise_error_syntax("bad fd number"); 9520 10588 n->ndup.vname = makename(); 9521 10589 } … … 9527 10595 */ 9528 10596 static int 9529 noexpand(char *text) 9530 { 9531 char *p; 9532 char c; 9533 9534 p = text; 9535 while ((c = *p++) != '\0') { 10597 noexpand(const char *text) 10598 { 10599 unsigned char c; 10600 10601 while ((c = *text++) != '\0') { 9536 10602 if (c == CTLQUOTEMARK) 9537 10603 continue; 9538 10604 if (c == CTLESC) 9539 p++;10605 text++; 9540 10606 else if (SIT(c, BASESYNTAX) == CCTL) 9541 10607 return 0; … … 9560 10626 TRACE(("Here document %d\n", n->type)); 9561 10627 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9562 raise_error_syntax(" Illegal eof marker for << redirection");9563 rmescapes(wordtext );10628 raise_error_syntax("illegal eof marker for << redirection"); 10629 rmescapes(wordtext, 0); 9564 10630 here->eofmark = wordtext; 9565 10631 here->next = NULL; … … 9567 10633 heredoclist = here; 9568 10634 else { 9569 for (p = heredoclist; p->next; p = p->next); 10635 for (p = heredoclist; p->next; p = p->next) 10636 continue; 9570 10637 p->next = here; 9571 10638 } … … 9585 10652 union node **rpp, *redir; 9586 10653 int savecheckkwd; 10654 #if ENABLE_ASH_BASH_COMPAT 10655 smallint double_brackets_flag = 0; 10656 #endif 9587 10657 9588 10658 args = NULL; … … 9595 10665 savecheckkwd = CHKALIAS; 9596 10666 for (;;) { 10667 int t; 9597 10668 checkkwd = savecheckkwd; 9598 switch (readtoken()) { 10669 t = readtoken(); 10670 switch (t) { 10671 #if ENABLE_ASH_BASH_COMPAT 10672 case TAND: /* "&&" */ 10673 case TOR: /* "||" */ 10674 if (!double_brackets_flag) { 10675 tokpushback = 1; 10676 goto out; 10677 } 10678 wordtext = (char *) (t == TAND ? "-a" : "-o"); 10679 #endif 9599 10680 case TWORD: 9600 n = st alloc(sizeof(struct narg));10681 n = stzalloc(sizeof(struct narg)); 9601 10682 n->type = NARG; 10683 /*n->narg.next = NULL; - stzalloc did it */ 9602 10684 n->narg.text = wordtext; 10685 #if ENABLE_ASH_BASH_COMPAT 10686 if (strcmp("[[", wordtext) == 0) 10687 double_brackets_flag = 1; 10688 else if (strcmp("]]", wordtext) == 0) 10689 double_brackets_flag = 0; 10690 #endif 9603 10691 n->narg.backquote = backquotelist; 9604 10692 if (savecheckkwd && isassignment(wordtext)) { … … 9630 10718 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) 9631 10719 ) { 9632 raise_error_syntax(" Bad function name");10720 raise_error_syntax("bad function name"); 9633 10721 } 9634 10722 n->type = NDEFUN; … … 9639 10727 /* fall through */ 9640 10728 default: 9641 tokpushback ++;10729 tokpushback = 1; 9642 10730 goto out; 9643 10731 } … … 9647 10735 *vpp = NULL; 9648 10736 *rpp = NULL; 9649 n = st alloc(sizeof(struct ncmd));10737 n = stzalloc(sizeof(struct ncmd)); 9650 10738 n->type = NCMD; 9651 10739 n->ncmd.args = args; … … 9673 10761 /* NOTREACHED */ 9674 10762 case TIF: 9675 n1 = st alloc(sizeof(struct nif));10763 n1 = stzalloc(sizeof(struct nif)); 9676 10764 n1->type = NIF; 9677 10765 n1->nif.test = list(0); … … 9681 10769 n2 = n1; 9682 10770 while (readtoken() == TELIF) { 9683 n2->nif.elsepart = st alloc(sizeof(struct nif));10771 n2->nif.elsepart = stzalloc(sizeof(struct nif)); 9684 10772 n2 = n2->nif.elsepart; 9685 10773 n2->type = NIF; … … 9693 10781 else { 9694 10782 n2->nif.elsepart = NULL; 9695 tokpushback ++;10783 tokpushback = 1; 9696 10784 } 9697 10785 t = TFI; … … 9700 10788 case TUNTIL: { 9701 10789 int got; 9702 n1 = st alloc(sizeof(struct nbinary));10790 n1 = stzalloc(sizeof(struct nbinary)); 9703 10791 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL; 9704 10792 n1->nbinary.ch1 = list(0); 9705 10793 got = readtoken(); 9706 10794 if (got != TDO) { 9707 TRACE(("expecting DO got %s %s\n", tokname(got),10795 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1, 9708 10796 got == TWORD ? wordtext : "")); 9709 10797 raise_error_unexpected_syntax(TDO); … … 9714 10802 } 9715 10803 case TFOR: 9716 if (readtoken() != TWORD || quoteflag || ! 9717 raise_error_syntax(" Bad for loop variable");9718 n1 = st alloc(sizeof(struct nfor));10804 if (readtoken() != TWORD || quoteflag || !goodname(wordtext)) 10805 raise_error_syntax("bad for loop variable"); 10806 n1 = stzalloc(sizeof(struct nfor)); 9719 10807 n1->type = NFOR; 9720 10808 n1->nfor.var = wordtext; … … 9723 10811 app = ≈ 9724 10812 while (readtoken() == TWORD) { 9725 n2 = st alloc(sizeof(struct narg));10813 n2 = stzalloc(sizeof(struct narg)); 9726 10814 n2->type = NARG; 10815 /*n2->narg.next = NULL; - stzalloc did it */ 9727 10816 n2->narg.text = wordtext; 9728 10817 n2->narg.backquote = backquotelist; … … 9735 10824 raise_error_unexpected_syntax(-1); 9736 10825 } else { 9737 n2 = st alloc(sizeof(struct narg));10826 n2 = stzalloc(sizeof(struct narg)); 9738 10827 n2->type = NARG; 10828 /*n2->narg.next = NULL; - stzalloc did it */ 9739 10829 n2->narg.text = (char *)dolatstr; 9740 n2->narg.backquote = NULL; 9741 n2->narg.next = NULL; 10830 /*n2->narg.backquote = NULL;*/ 9742 10831 n1->nfor.args = n2; 9743 10832 /* … … 9746 10835 */ 9747 10836 if (lasttoken != TNL && lasttoken != TSEMI) 9748 tokpushback ++;10837 tokpushback = 1; 9749 10838 } 9750 10839 checkkwd = CHKNL | CHKKWD | CHKALIAS; … … 9755 10844 break; 9756 10845 case TCASE: 9757 n1 = st alloc(sizeof(struct ncase));10846 n1 = stzalloc(sizeof(struct ncase)); 9758 10847 n1->type = NCASE; 9759 10848 if (readtoken() != TWORD) 9760 10849 raise_error_unexpected_syntax(TWORD); 9761 n1->ncase.expr = n2 = st alloc(sizeof(struct narg));10850 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); 9762 10851 n2->type = NARG; 10852 /*n2->narg.next = NULL; - stzalloc did it */ 9763 10853 n2->narg.text = wordtext; 9764 10854 n2->narg.backquote = backquotelist; 9765 n2->narg.next = NULL;9766 10855 do { 9767 10856 checkkwd = CHKKWD | CHKALIAS; … … 9776 10865 if (lasttoken == TLP) 9777 10866 readtoken(); 9778 *cpp = cp = st alloc(sizeof(struct nclist));10867 *cpp = cp = stzalloc(sizeof(struct nclist)); 9779 10868 cp->type = NCLIST; 9780 10869 app = &cp->nclist.pattern; 9781 10870 for (;;) { 9782 *app = ap = st alloc(sizeof(struct narg));10871 *app = ap = stzalloc(sizeof(struct narg)); 9783 10872 ap->type = NARG; 10873 /*ap->narg.next = NULL; - stzalloc did it */ 9784 10874 ap->narg.text = wordtext; 9785 10875 ap->narg.backquote = backquotelist; … … 9789 10879 readtoken(); 9790 10880 } 9791 ap->narg.next = NULL;10881 //ap->narg.next = NULL; 9792 10882 if (lasttoken != TRP) 9793 10883 raise_error_unexpected_syntax(TRP); … … 9807 10897 goto redir; 9808 10898 case TLP: 9809 n1 = st alloc(sizeof(struct nredir));10899 n1 = stzalloc(sizeof(struct nredir)); 9810 10900 n1->type = NSUBSHELL; 9811 10901 n1->nredir.n = list(0); 9812 n1->nredir.redirect = NULL;10902 /*n1->nredir.redirect = NULL; - stzalloc did it */ 9813 10903 t = TRP; 9814 10904 break; … … 9819 10909 case TWORD: 9820 10910 case TREDIR: 9821 tokpushback ++;10911 tokpushback = 1; 9822 10912 return simplecmd(); 9823 10913 } … … 9835 10925 parsefname(); 9836 10926 } 9837 tokpushback ++;10927 tokpushback = 1; 9838 10928 *rpp = NULL; 9839 10929 if (redir) { 9840 10930 if (n1->type != NSUBSHELL) { 9841 n2 = st alloc(sizeof(struct nredir));10931 n2 = stzalloc(sizeof(struct nredir)); 9842 10932 n2->type = NREDIR; 9843 10933 n2->nredir.n = n1; … … 9849 10939 } 9850 10940 10941 #if ENABLE_ASH_BASH_COMPAT 10942 static int decode_dollar_squote(void) 10943 { 10944 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567"; 10945 int c, cnt; 10946 char *p; 10947 char buf[4]; 10948 10949 c = pgetc(); 10950 p = strchr(C_escapes, c); 10951 if (p) { 10952 buf[0] = c; 10953 p = buf; 10954 cnt = 3; 10955 if ((unsigned char)(c - '0') <= 7) { /* \ooo */ 10956 do { 10957 c = pgetc(); 10958 *++p = c; 10959 } while ((unsigned char)(c - '0') <= 7 && --cnt); 10960 pungetc(); 10961 } else if (c == 'x') { /* \xHH */ 10962 do { 10963 c = pgetc(); 10964 *++p = c; 10965 } while (isxdigit(c) && --cnt); 10966 pungetc(); 10967 if (cnt == 3) { /* \x but next char is "bad" */ 10968 c = 'x'; 10969 goto unrecognized; 10970 } 10971 } else { /* simple seq like \\ or \t */ 10972 p++; 10973 } 10974 *p = '\0'; 10975 p = buf; 10976 c = bb_process_escape_sequence((void*)&p); 10977 } else { /* unrecognized "\z": print both chars unless ' or " */ 10978 if (c != '\'' && c != '"') { 10979 unrecognized: 10980 c |= 0x100; /* "please encode \, then me" */ 10981 } 10982 } 10983 return c; 10984 } 10985 #endif 10986 9851 10987 /* 9852 10988 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 9853 10989 * is not NULL, read a here document. In the latter case, eofmark is the 9854 10990 * word which marks the end of the document and striptabs is true if 9855 * leading tabs should be stripped from the document. The argument firstc10991 * leading tabs should be stripped from the document. The argument c 9856 10992 * is the first character of the input token or document. 9857 10993 * … … 9860 10996 * will run code that appears at the end of readtoken1. 9861 10997 */ 9862 9863 static int parsebackquote; /* nonzero if we are inside backquotes */9864 9865 10998 #define CHECKEND() {goto checkend; checkend_return:;} 9866 10999 #define PARSEREDIR() {goto parseredir; parseredir_return:;} … … 9869 11002 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 9870 11003 #define PARSEARITH() {goto parsearith; parsearith_return:;} 9871 9872 11004 static int 9873 readtoken1(int firstc, int syntax, char *eofmark, int striptabs) 9874 { 9875 int c = firstc; 11005 readtoken1(int c, int syntax, char *eofmark, int striptabs) 11006 { 11007 /* NB: syntax parameter fits into smallint */ 11008 /* c parameter is an unsigned char or PEOF or PEOA */ 9876 11009 char *out; 9877 11010 int len; 9878 11011 char line[EOFMARKLEN + 1]; 9879 struct nodelist *bqlist = 0; 9880 int quotef = 0; 9881 int dblquote = 0; 9882 int varnest = 0; /* levels of variables expansion */ 9883 int arinest = 0; /* levels of arithmetic expansion */ 9884 int parenlevel = 0; /* levels of parens in arithmetic */ 9885 int dqvarnest = 0; /* levels of variables expansion within double quotes */ 9886 int oldstyle = 0; 9887 int prevsyntax = 0; /* syntax before arithmetic */ 11012 struct nodelist *bqlist; 11013 smallint quotef; 11014 smallint dblquote; 11015 smallint oldstyle; 11016 smallint prevsyntax; /* syntax before arithmetic */ 11017 #if ENABLE_ASH_EXPAND_PRMT 11018 smallint pssyntax; /* we are expanding a prompt string */ 11019 #endif 11020 int varnest; /* levels of variables expansion */ 11021 int arinest; /* levels of arithmetic expansion */ 11022 int parenlevel; /* levels of parens in arithmetic */ 11023 int dqvarnest; /* levels of variables expansion within double quotes */ 11024 11025 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) 11026 9888 11027 #if __GNUC__ 9889 11028 /* Avoid longjmp clobbering */ … … 9899 11038 (void) &syntax; 9900 11039 #endif 9901 9902 startlinno = plinno; 9903 dblquote = 0; 9904 if (syntax == DQSYNTAX) 9905 dblquote = 1; 11040 startlinno = g_parsefile->linno; 11041 bqlist = NULL; 9906 11042 quotef = 0; 9907 bqlist = NULL; 11043 prevsyntax = 0; 11044 #if ENABLE_ASH_EXPAND_PRMT 11045 pssyntax = (syntax == PSSYNTAX); 11046 if (pssyntax) 11047 syntax = DQSYNTAX; 11048 #endif 11049 dblquote = (syntax == DQSYNTAX); 9908 11050 varnest = 0; 9909 11051 arinest = 0; … … 9912 11054 9913 11055 STARTSTACKSTR(out); 9914 loop: { /* for each line, until end of word */ 9915 CHECKEND(); /* set c to PEOF if at end of here document */ 9916 for (;;) { /* until end of line or end of word */ 9917 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 9918 switch (SIT(c, syntax)) { 9919 case CNL: /* '\n' */ 9920 if (syntax == BASESYNTAX) 9921 goto endword; /* exit outer loop */ 9922 USTPUTC(c, out); 9923 plinno++; 9924 if (doprompt) 9925 setprompt(2); 9926 c = pgetc(); 9927 goto loop; /* continue outer loop */ 9928 case CWORD: 9929 USTPUTC(c, out); 9930 break; 9931 case CCTL: 9932 if (eofmark == NULL || dblquote) 11056 loop: 11057 /* For each line, until end of word */ 11058 CHECKEND(); /* set c to PEOF if at end of here document */ 11059 for (;;) { /* until end of line or end of word */ 11060 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 11061 switch (SIT(c, syntax)) { 11062 case CNL: /* '\n' */ 11063 if (syntax == BASESYNTAX) 11064 goto endword; /* exit outer loop */ 11065 USTPUTC(c, out); 11066 g_parsefile->linno++; 11067 setprompt_if(doprompt, 2); 11068 c = pgetc(); 11069 goto loop; /* continue outer loop */ 11070 case CWORD: 11071 USTPUTC(c, out); 11072 break; 11073 case CCTL: 11074 if (eofmark == NULL || dblquote) 11075 USTPUTC(CTLESC, out); 11076 #if ENABLE_ASH_BASH_COMPAT 11077 if (c == '\\' && bash_dollar_squote) { 11078 c = decode_dollar_squote(); 11079 if (c & 0x100) { 11080 USTPUTC('\\', out); 11081 c = (unsigned char)c; 11082 } 11083 } 11084 #endif 11085 USTPUTC(c, out); 11086 break; 11087 case CBACK: /* backslash */ 11088 c = pgetc_without_PEOA(); 11089 if (c == PEOF) { 11090 USTPUTC(CTLESC, out); 11091 USTPUTC('\\', out); 11092 pungetc(); 11093 } else if (c == '\n') { 11094 setprompt_if(doprompt, 2); 11095 } else { 11096 #if ENABLE_ASH_EXPAND_PRMT 11097 if (c == '$' && pssyntax) { 11098 USTPUTC(CTLESC, out); 11099 USTPUTC('\\', out); 11100 } 11101 #endif 11102 /* Backslash is retained if we are in "str" and next char isn't special */ 11103 if (dblquote 11104 && c != '\\' 11105 && c != '`' 11106 && c != '$' 11107 && (c != '"' || eofmark != NULL) 11108 ) { 11109 USTPUTC(CTLESC, out); 11110 USTPUTC('\\', out); 11111 } 11112 if (SIT(c, SQSYNTAX) == CCTL) 9933 11113 USTPUTC(CTLESC, out); 9934 11114 USTPUTC(c, out); 9935 break; 9936 case CBACK: /* backslash */ 9937 c = pgetc2(); 9938 if (c == PEOF) { 9939 USTPUTC(CTLESC, out); 9940 USTPUTC('\\', out); 11115 quotef = 1; 11116 } 11117 break; 11118 case CSQUOTE: 11119 syntax = SQSYNTAX; 11120 quotemark: 11121 if (eofmark == NULL) { 11122 USTPUTC(CTLQUOTEMARK, out); 11123 } 11124 break; 11125 case CDQUOTE: 11126 syntax = DQSYNTAX; 11127 dblquote = 1; 11128 goto quotemark; 11129 case CENDQUOTE: 11130 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) 11131 if (eofmark != NULL && arinest == 0 11132 && varnest == 0 11133 ) { 11134 USTPUTC(c, out); 11135 } else { 11136 if (dqvarnest == 0) { 11137 syntax = BASESYNTAX; 11138 dblquote = 0; 11139 } 11140 quotef = 1; 11141 goto quotemark; 11142 } 11143 break; 11144 case CVAR: /* '$' */ 11145 PARSESUB(); /* parse substitution */ 11146 break; 11147 case CENDVAR: /* '}' */ 11148 if (varnest > 0) { 11149 varnest--; 11150 if (dqvarnest > 0) { 11151 dqvarnest--; 11152 } 11153 c = CTLENDVAR; 11154 } 11155 USTPUTC(c, out); 11156 break; 11157 #if ENABLE_SH_MATH_SUPPORT 11158 case CLP: /* '(' in arithmetic */ 11159 parenlevel++; 11160 USTPUTC(c, out); 11161 break; 11162 case CRP: /* ')' in arithmetic */ 11163 if (parenlevel > 0) { 11164 parenlevel--; 11165 } else { 11166 if (pgetc() == ')') { 11167 if (--arinest == 0) { 11168 syntax = prevsyntax; 11169 dblquote = (syntax == DQSYNTAX); 11170 c = CTLENDARI; 11171 } 11172 } else { 11173 /* 11174 * unbalanced parens 11175 * (don't 2nd guess - no error) 11176 */ 9941 11177 pungetc(); 9942 } else if (c == '\n') {9943 if (doprompt)9944 setprompt(2);9945 } else {9946 if (dblquote &&9947 c != '\\' && c != '`' &&9948 c != '$' && (9949 c != '"' ||9950 eofmark != NULL)9951 ) {9952 USTPUTC(CTLESC, out);9953 USTPUTC('\\', out);9954 }9955 if (SIT(c, SQSYNTAX) == CCTL)9956 USTPUTC(CTLESC, out);9957 USTPUTC(c, out);9958 quotef++;9959 11178 } 9960 break; 9961 case CSQUOTE: 9962 syntax = SQSYNTAX; 9963 quotemark: 9964 if (eofmark == NULL) { 9965 USTPUTC(CTLQUOTEMARK, out); 11179 } 11180 USTPUTC(c, out); 11181 break; 11182 #endif 11183 case CBQUOTE: /* '`' */ 11184 PARSEBACKQOLD(); 11185 break; 11186 case CENDFILE: 11187 goto endword; /* exit outer loop */ 11188 case CIGN: 11189 break; 11190 default: 11191 if (varnest == 0) { 11192 #if ENABLE_ASH_BASH_COMPAT 11193 if (c == '&') { 11194 if (pgetc() == '>') 11195 c = 0x100 + '>'; /* flag &> */ 11196 pungetc(); 9966 11197 } 9967 break; 9968 case CDQUOTE: 9969 syntax = DQSYNTAX; 9970 dblquote = 1; 9971 goto quotemark; 9972 case CENDQUOTE: 9973 if (eofmark != NULL && arinest == 0 9974 && varnest == 0 9975 ) { 9976 USTPUTC(c, out); 9977 } else { 9978 if (dqvarnest == 0) { 9979 syntax = BASESYNTAX; 9980 dblquote = 0; 9981 } 9982 quotef++; 9983 goto quotemark; 9984 } 9985 break; 9986 case CVAR: /* '$' */ 9987 PARSESUB(); /* parse substitution */ 9988 break; 9989 case CENDVAR: /* '}' */ 9990 if (varnest > 0) { 9991 varnest--; 9992 if (dqvarnest > 0) { 9993 dqvarnest--; 9994 } 9995 USTPUTC(CTLENDVAR, out); 9996 } else { 9997 USTPUTC(c, out); 9998 } 9999 break; 10000 #if ENABLE_ASH_MATH_SUPPORT 10001 case CLP: /* '(' in arithmetic */ 10002 parenlevel++; 11198 #endif 11199 goto endword; /* exit outer loop */ 11200 } 11201 IF_ASH_ALIAS(if (c != PEOA)) 10003 11202 USTPUTC(c, out); 10004 break; 10005 case CRP: /* ')' in arithmetic */ 10006 if (parenlevel > 0) { 10007 USTPUTC(c, out); 10008 --parenlevel; 10009 } else { 10010 if (pgetc() == ')') { 10011 if (--arinest == 0) { 10012 USTPUTC(CTLENDARI, out); 10013 syntax = prevsyntax; 10014 if (syntax == DQSYNTAX) 10015 dblquote = 1; 10016 else 10017 dblquote = 0; 10018 } else 10019 USTPUTC(')', out); 10020 } else { 10021 /* 10022 * unbalanced parens 10023 * (don't 2nd guess - no error) 10024 */ 10025 pungetc(); 10026 USTPUTC(')', out); 10027 } 10028 } 10029 break; 10030 #endif 10031 case CBQUOTE: /* '`' */ 10032 PARSEBACKQOLD(); 10033 break; 10034 case CENDFILE: 10035 goto endword; /* exit outer loop */ 10036 case CIGN: 10037 break; 10038 default: 10039 if (varnest == 0) 10040 goto endword; /* exit outer loop */ 10041 #if ENABLE_ASH_ALIAS 10042 if (c != PEOA) 10043 #endif 10044 USTPUTC(c, out); 10045 10046 } 10047 c = pgetc_macro(); 10048 } 10049 } 11203 } 11204 c = pgetc_fast(); 11205 } /* for (;;) */ 10050 11206 endword: 10051 #if ENABLE_ASH_MATH_SUPPORT 11207 11208 #if ENABLE_SH_MATH_SUPPORT 10052 11209 if (syntax == ARISYNTAX) 10053 raise_error_syntax(" Missing '))'");11210 raise_error_syntax("missing '))'"); 10054 11211 #endif 10055 11212 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10056 raise_error_syntax(" Unterminated quoted string");11213 raise_error_syntax("unterminated quoted string"); 10057 11214 if (varnest != 0) { 10058 startlinno = plinno;11215 startlinno = g_parsefile->linno; 10059 11216 /* { */ 10060 raise_error_syntax(" Missing '}'");11217 raise_error_syntax("missing '}'"); 10061 11218 } 10062 11219 USTPUTC('\0', out); … … 10064 11221 out = stackblock(); 10065 11222 if (eofmark == NULL) { 10066 if ((c == '>' || c == '<' )11223 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>')) 10067 11224 && quotef == 0 10068 && len <= 2 10069 && (*out == '\0' || isdigit(*out))) { 10070 PARSEREDIR(); 10071 return lasttoken = TREDIR; 10072 } else { 10073 pungetc(); 10074 } 11225 ) { 11226 if (isdigit_str9(out)) { 11227 PARSEREDIR(); /* passed as params: out, c */ 11228 lasttoken = TREDIR; 11229 return lasttoken; 11230 } 11231 /* else: non-number X seen, interpret it 11232 * as "NNNX>file" = "NNNX >file" */ 11233 } 11234 pungetc(); 10075 11235 } 10076 11236 quoteflag = quotef; … … 10090 11250 if (eofmark) { 10091 11251 #if ENABLE_ASH_ALIAS 10092 if (c == PEOA) { 10093 c = pgetc2(); 10094 } 11252 if (c == PEOA) 11253 c = pgetc_without_PEOA(); 10095 11254 #endif 10096 11255 if (striptabs) { 10097 11256 while (c == '\t') { 10098 c = pgetc 2();11257 c = pgetc_without_PEOA(); 10099 11258 } 10100 11259 } … … 10104 11263 10105 11264 p = line; 10106 for (q = eofmark + 1; *q && *p == *q; p++, q++); 11265 for (q = eofmark + 1; *q && *p == *q; p++, q++) 11266 continue; 10107 11267 if (*p == '\n' && *q == '\0') { 10108 11268 c = PEOF; 10109 plinno++;11269 g_parsefile->linno++; 10110 11270 needprompt = doprompt; 10111 11271 } else { … … 10124 11284 */ 10125 11285 parseredir: { 10126 char fd = *out; 11286 /* out is already checked to be a valid number or "" */ 11287 int fd = (*out == '\0' ? -1 : atoi(out)); 10127 11288 union node *np; 10128 11289 10129 np = st alloc(sizeof(struct nfile));11290 np = stzalloc(sizeof(struct nfile)); 10130 11291 if (c == '>') { 10131 11292 np->nfile.fd = 1; … … 10137 11298 else if (c == '&') 10138 11299 np->type = NTOFD; 11300 /* it also can be NTO2 (>&file), but we can't figure it out yet */ 10139 11301 else { 10140 11302 np->type = NTO; 10141 11303 pungetc(); 10142 11304 } 10143 } else { /* c == '<' */ 10144 np->nfile.fd = 0; 11305 } 11306 #if ENABLE_ASH_BASH_COMPAT 11307 else if (c == 0x100 + '>') { /* this flags &> redirection */ 11308 np->nfile.fd = 1; 11309 pgetc(); /* this is '>', no need to check */ 11310 np->type = NTO2; 11311 } 11312 #endif 11313 else { /* c == '<' */ 11314 /*np->nfile.fd = 0; - stzalloc did it */ 10145 11315 c = pgetc(); 10146 11316 switch (c) { 10147 11317 case '<': 10148 11318 if (sizeof(struct nfile) != sizeof(struct nhere)) { 10149 np = st alloc(sizeof(struct nhere));10150 np->nfile.fd = 0;11319 np = stzalloc(sizeof(struct nhere)); 11320 /*np->nfile.fd = 0; - stzalloc did it */ 10151 11321 } 10152 11322 np->type = NHERE; 10153 heredoc = st alloc(sizeof(struct heredoc));11323 heredoc = stzalloc(sizeof(struct heredoc)); 10154 11324 heredoc->here = np; 10155 11325 c = pgetc(); … … 10157 11327 heredoc->striptabs = 1; 10158 11328 } else { 10159 heredoc->striptabs = 0;11329 /*heredoc->striptabs = 0; - stzalloc did it */ 10160 11330 pungetc(); 10161 11331 } … … 10176 11346 } 10177 11347 } 10178 if (fd != '\0')10179 np->nfile.fd = fd - '0';11348 if (fd >= 0) 11349 np->nfile.fd = fd; 10180 11350 redirnode = np; 10181 11351 goto parseredir_return; … … 10190 11360 * (assuming ascii char codes, as the original implementation did) */ 10191 11361 #define is_special(c) \ 10192 ((( (unsigned int)c) - 33 < 32) \10193 && ((0xc1ff920dU L >> (((unsigned int)c) - 33)) & 1))11362 (((unsigned)(c) - 33 < 32) \ 11363 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1)) 10194 11364 parsesub: { 10195 intsubtype;11365 unsigned char subtype; 10196 11366 int typeloc; 10197 11367 int flags; 10198 char *p;10199 static const char types[] ALIGN1 = "}-+?=";10200 11368 10201 11369 c = pgetc(); 10202 if ( 10203 c <= PEOA_OR_PEOF || 10204 (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 11370 if (c > 255 /* PEOA or PEOF */ 11371 || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 10205 11372 ) { 10206 USTPUTC('$', out); 11373 #if ENABLE_ASH_BASH_COMPAT 11374 if (c == '\'') 11375 bash_dollar_squote = 1; 11376 else 11377 #endif 11378 USTPUTC('$', out); 10207 11379 pungetc(); 10208 } else if (c == '(') { /* $(command) or $((arith)) */ 11380 } else if (c == '(') { 11381 /* $(command) or $((arith)) */ 10209 11382 if (pgetc() == '(') { 10210 #if ENABLE_ ASH_MATH_SUPPORT11383 #if ENABLE_SH_MATH_SUPPORT 10211 11384 PARSEARITH(); 10212 11385 #else 10213 raise_error_syntax(" We unsupport $((arith))");11386 raise_error_syntax("you disabled math support for $((arith)) syntax"); 10214 11387 #endif 10215 11388 } else { … … 10218 11391 } 10219 11392 } else { 11393 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */ 10220 11394 USTPUTC(CTLVAR, out); 10221 11395 typeloc = out - (char *)stackblock(); … … 10227 11401 c = pgetc(); 10228 11402 if (c == '}') 10229 c = '#'; 11403 c = '#'; /* ${#} - same as $# */ 10230 11404 else 10231 subtype = VSLENGTH; 10232 } else 11405 subtype = VSLENGTH; /* ${#VAR} */ 11406 } else { 10233 11407 subtype = 0; 10234 } 10235 if (c > PEOA_OR_PEOF && is_name(c)) { 11408 } 11409 } 11410 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { 11411 /* $[{[#]]NAME[}] */ 10236 11412 do { 10237 11413 STPUTC(c, out); 10238 11414 c = pgetc(); 10239 } while (c > PEOA_OR_PEOF&& is_in_name(c));11415 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); 10240 11416 } else if (isdigit(c)) { 11417 /* $[{[#]]NUM[}] */ 10241 11418 do { 10242 11419 STPUTC(c, out); … … 10244 11421 } while (isdigit(c)); 10245 11422 } else if (is_special(c)) { 11423 /* $[{[#]]<specialchar>[}] */ 10246 11424 USTPUTC(c, out); 10247 11425 c = pgetc(); 10248 } else 10249 badsub: raise_error_syntax("Bad substitution"); 11426 } else { 11427 badsub: 11428 raise_error_syntax("bad substitution"); 11429 } 11430 if (c != '}' && subtype == VSLENGTH) { 11431 /* ${#VAR didn't end with } */ 11432 goto badsub; 11433 } 10250 11434 10251 11435 STPUTC('=', out); 10252 11436 flags = 0; 10253 11437 if (subtype == 0) { 11438 /* ${VAR...} but not $VAR or ${#VAR} */ 11439 /* c == first char after VAR */ 10254 11440 switch (c) { 10255 11441 case ':': 11442 c = pgetc(); 11443 #if ENABLE_ASH_BASH_COMPAT 11444 if (c == ':' || c == '$' || isdigit(c)) { 11445 //TODO: support more general format ${v:EXPR:EXPR}, 11446 // where EXPR follows $(()) rules 11447 subtype = VSSUBSTR; 11448 pungetc(); 11449 break; /* "goto do_pungetc" is bigger (!) */ 11450 } 11451 #endif 10256 11452 flags = VSNUL; 10257 c = pgetc();10258 11453 /*FALLTHROUGH*/ 10259 default: 10260 p = strchr(types, c); 11454 default: { 11455 static const char types[] ALIGN1 = "}-+?="; 11456 const char *p = strchr(types, c); 10261 11457 if (p == NULL) 10262 11458 goto badsub; 10263 11459 subtype = p - types + VSNORMAL; 10264 11460 break; 11461 } 10265 11462 case '%': 10266 case '#': 10267 { 10268 int cc = c; 10269 subtype = c == '#' ? VSTRIMLEFT : 10270 VSTRIMRIGHT; 10271 c = pgetc(); 10272 if (c == cc) 10273 subtype++; 10274 else 10275 pungetc(); 10276 break; 10277 } 11463 case '#': { 11464 int cc = c; 11465 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); 11466 c = pgetc(); 11467 if (c != cc) 11468 goto do_pungetc; 11469 subtype++; 11470 break; 11471 } 11472 #if ENABLE_ASH_BASH_COMPAT 11473 case '/': 11474 /* ${v/[/]pattern/repl} */ 11475 //TODO: encode pattern and repl separately. 11476 // Currently ${v/$var_with_slash/repl} is horribly broken 11477 subtype = VSREPLACE; 11478 c = pgetc(); 11479 if (c != '/') 11480 goto do_pungetc; 11481 subtype++; /* VSREPLACEALL */ 11482 break; 11483 #endif 10278 11484 } 10279 11485 } else { 11486 do_pungetc: 10280 11487 pungetc(); 10281 11488 } 10282 11489 if (dblquote || arinest) 10283 11490 flags |= VSQUOTE; 10284 *((char *)stackblock() + typeloc)= subtype | flags;11491 ((unsigned char *)stackblock())[typeloc] = subtype | flags; 10285 11492 if (subtype != VSNORMAL) { 10286 11493 varnest++; … … 10301 11508 parsebackq: { 10302 11509 struct nodelist **nlpp; 10303 int savepbq;11510 smallint savepbq; 10304 11511 union node *n; 10305 11512 char *volatile str; … … 10307 11514 struct jmploc *volatile savehandler; 10308 11515 size_t savelen; 10309 int saveprompt = 0; 11516 smallint saveprompt = 0; 11517 10310 11518 #ifdef __GNUC__ 10311 11519 (void) &saveprompt; 10312 11520 #endif 10313 10314 11521 savepbq = parsebackquote; 10315 11522 if (setjmp(jmploc.loc)) { 10316 if (str) 10317 free(str); 11523 free(str); 10318 11524 parsebackquote = 0; 10319 11525 exception_handler = savehandler; … … 10335 11541 reread it as input, interpreting it normally. */ 10336 11542 char *pout; 10337 int pc;10338 11543 size_t psavelen; 10339 11544 char *pstr; 10340 11545 10341 10342 11546 STARTSTACKSTR(pout); 10343 11547 for (;;) { 10344 i f (needprompt) {10345 setprompt(2); 10346 }11548 int pc; 11549 11550 setprompt_if(needprompt, 2); 10347 11551 pc = pgetc(); 10348 11552 switch (pc) { … … 10353 11557 pc = pgetc(); 10354 11558 if (pc == '\n') { 10355 plinno++; 10356 if (doprompt) 10357 setprompt(2); 11559 g_parsefile->linno++; 11560 setprompt_if(doprompt, 2); 10358 11561 /* 10359 11562 * If eating a newline, avoid putting … … 10365 11568 } 10366 11569 if (pc != '\\' && pc != '`' && pc != '$' 10367 && (!dblquote || pc != '"')) 11570 && (!dblquote || pc != '"') 11571 ) { 10368 11572 STPUTC('\\', pout); 10369 if (pc > PEOA_OR_PEOF) { 11573 } 11574 if (pc <= 255 /* not PEOA or PEOF */) { 10370 11575 break; 10371 11576 } … … 10373 11578 10374 11579 case PEOF: 10375 #if ENABLE_ASH_ALIAS 10376 case PEOA: 10377 #endif 10378 startlinno = plinno; 11580 IF_ASH_ALIAS(case PEOA:) 11581 startlinno = g_parsefile->linno; 10379 11582 raise_error_syntax("EOF in backquote substitution"); 10380 11583 10381 11584 case '\n': 10382 plinno++;11585 g_parsefile->linno++; 10383 11586 needprompt = doprompt; 10384 11587 break; … … 10400 11603 while (*nlpp) 10401 11604 nlpp = &(*nlpp)->next; 10402 *nlpp = st alloc(sizeof(**nlpp));10403 (*nlpp)->next = NULL;11605 *nlpp = stzalloc(sizeof(**nlpp)); 11606 /* (*nlpp)->next = NULL; - stzalloc did it */ 10404 11607 parsebackquote = oldstyle; 10405 11608 … … 10447 11650 } 10448 11651 10449 #if ENABLE_ ASH_MATH_SUPPORT11652 #if ENABLE_SH_MATH_SUPPORT 10450 11653 /* 10451 11654 * Parse an arithmetic expansion (indicate start of one and set state) … … 10494 11697 /* singles must be first! */ 10495 11698 static const char xxreadtoken_chars[7] ALIGN1 = { 10496 '\n', '(', ')', '&', '|', ';', 0 11699 '\n', '(', ')', /* singles */ 11700 '&', '|', ';', /* doubles */ 11701 0 10497 11702 }; 11703 11704 #define xxreadtoken_singles 3 11705 #define xxreadtoken_doubles 3 10498 11706 10499 11707 static const char xxreadtoken_tokens[] ALIGN1 = { … … 10504 11712 }; 10505 11713 10506 #define xxreadtoken_doubles \10507 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))10508 #define xxreadtoken_singles \10509 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)10510 10511 11714 static int 10512 11715 xxreadtoken(void) … … 10518 11721 return lasttoken; 10519 11722 } 10520 if (needprompt) { 10521 setprompt(2); 10522 } 10523 startlinno = plinno; 11723 setprompt_if(needprompt, 2); 11724 startlinno = g_parsefile->linno; 10524 11725 for (;;) { /* until token or start of word found */ 10525 c = pgetc_macro(); 10526 10527 if ((c != ' ') && (c != '\t') 10528 #if ENABLE_ASH_ALIAS 10529 && (c != PEOA) 10530 #endif 10531 ) { 10532 if (c == '#') { 10533 while ((c = pgetc()) != '\n' && c != PEOF); 11726 c = pgetc_fast(); 11727 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 11728 continue; 11729 11730 if (c == '#') { 11731 while ((c = pgetc()) != '\n' && c != PEOF) 11732 continue; 11733 pungetc(); 11734 } else if (c == '\\') { 11735 if (pgetc() != '\n') { 10534 11736 pungetc(); 10535 } else if (c == '\\') { 10536 if (pgetc() != '\n') { 10537 pungetc(); 10538 goto READTOKEN1; 11737 break; /* return readtoken1(...) */ 11738 } 11739 startlinno = ++g_parsefile->linno; 11740 setprompt_if(doprompt, 2); 11741 } else { 11742 const char *p; 11743 11744 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 11745 if (c != PEOF) { 11746 if (c == '\n') { 11747 g_parsefile->linno++; 11748 needprompt = doprompt; 10539 11749 } 10540 startlinno = ++plinno; 10541 if (doprompt) 10542 setprompt(2); 10543 } else { 10544 const char *p 10545 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10546 10547 if (c != PEOF) { 10548 if (c == '\n') { 10549 plinno++; 10550 needprompt = doprompt; 10551 } 10552 10553 p = strchr(xxreadtoken_chars, c); 10554 if (p == NULL) { 10555 READTOKEN1: 10556 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10557 } 10558 10559 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10560 if (pgetc() == *p) { /* double occurrence? */ 10561 p += xxreadtoken_doubles + 1; 10562 } else { 10563 pungetc(); 10564 } 11750 11751 p = strchr(xxreadtoken_chars, c); 11752 if (p == NULL) 11753 break; /* return readtoken1(...) */ 11754 11755 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) { 11756 int cc = pgetc(); 11757 if (cc == c) { /* double occurrence? */ 11758 p += xxreadtoken_doubles + 1; 11759 } else { 11760 pungetc(); 11761 #if ENABLE_ASH_BASH_COMPAT 11762 if (c == '&' && cc == '>') /* &> */ 11763 break; /* return readtoken1(...) */ 11764 #endif 10565 11765 } 10566 11766 } 10567 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];10568 11767 } 10569 } 10570 } /* for */ 10571 } 10572 #else 11768 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 11769 return lasttoken; 11770 } 11771 } /* for (;;) */ 11772 11773 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 11774 } 11775 #else /* old xxreadtoken */ 10573 11776 #define RETURN(token) return lasttoken = token 10574 11777 static int … … 10581 11784 return lasttoken; 10582 11785 } 10583 if (needprompt) { 10584 setprompt(2); 10585 } 10586 startlinno = plinno; 11786 setprompt_if(needprompt, 2); 11787 startlinno = g_parsefile->linno; 10587 11788 for (;;) { /* until token or start of word found */ 10588 c = pgetc_ macro();11789 c = pgetc_fast(); 10589 11790 switch (c) { 10590 11791 case ' ': case '\t': 10591 #if ENABLE_ASH_ALIAS 10592 case PEOA: 10593 #endif 11792 IF_ASH_ALIAS(case PEOA:) 10594 11793 continue; 10595 11794 case '#': 10596 while ((c = pgetc()) != '\n' && c != PEOF); 11795 while ((c = pgetc()) != '\n' && c != PEOF) 11796 continue; 10597 11797 pungetc(); 10598 11798 continue; 10599 11799 case '\\': 10600 11800 if (pgetc() == '\n') { 10601 startlinno = ++plinno; 10602 if (doprompt) 10603 setprompt(2); 11801 startlinno = ++g_parsefile->linno; 11802 setprompt_if(doprompt, 2); 10604 11803 continue; 10605 11804 } … … 10607 11806 goto breakloop; 10608 11807 case '\n': 10609 plinno++;11808 g_parsefile->linno++; 10610 11809 needprompt = doprompt; 10611 11810 RETURN(TNL); … … 10639 11838 #undef RETURN 10640 11839 } 10641 #endif /* NEW_xxreadtoken */11840 #endif /* old xxreadtoken */ 10642 11841 10643 11842 static int … … 10646 11845 int t; 10647 11846 #if DEBUG 10648 int alreadyseen = tokpushback;11847 smallint alreadyseen = tokpushback; 10649 11848 #endif 10650 11849 … … 10678 11877 if (pp) { 10679 11878 lasttoken = t = pp - tokname_array; 10680 TRACE(("keyword %s recognized\n", tokname(t)));11879 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1)); 10681 11880 goto out; 10682 11881 } … … 10699 11898 #if DEBUG 10700 11899 if (!alreadyseen) 10701 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));11900 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : "")); 10702 11901 else 10703 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));11902 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : "")); 10704 11903 #endif 10705 11904 return t; … … 10712 11911 10713 11912 t = readtoken(); 10714 tokpushback ++;11913 tokpushback = 1; 10715 11914 return tokname_array[t][0]; 10716 11915 } 10717 11916 10718 11917 /* 10719 * Read and parse a command. Returns N EOF on end of file. (NULL is a10720 * valid parse tree indicating a blank line.)11918 * Read and parse a command. Returns NODE_EOF on end of file. 11919 * (NULL is a valid parse tree indicating a blank line.) 10721 11920 */ 10722 11921 static union node * … … 10727 11926 tokpushback = 0; 10728 11927 doprompt = interact; 10729 if (doprompt) 10730 setprompt(doprompt); 11928 setprompt_if(doprompt, doprompt); 10731 11929 needprompt = 0; 10732 11930 t = readtoken(); 10733 11931 if (t == TEOF) 10734 return N EOF;11932 return NODE_EOF; 10735 11933 if (t == TNL) 10736 11934 return NULL; 10737 tokpushback ++;11935 tokpushback = 1; 10738 11936 return list(1); 10739 11937 } … … 10749 11947 10750 11948 here = heredoclist; 10751 heredoclist = 0;11949 heredoclist = NULL; 10752 11950 10753 11951 while (here) { 10754 if (needprompt) { 10755 setprompt(2); 10756 } 10757 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 11952 setprompt_if(needprompt, 2); 11953 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, 10758 11954 here->eofmark, here->striptabs); 10759 n = st alloc(sizeof(struct narg));11955 n = stzalloc(sizeof(struct narg)); 10760 11956 n->narg.type = NARG; 10761 n->narg.next = NULL;11957 /*n->narg.next = NULL; - stzalloc did it */ 10762 11958 n->narg.text = wordtext; 10763 11959 n->narg.backquote = backquotelist; … … 10777 11973 union node n; 10778 11974 10779 /* XXX Fix (char *) cast. */ 11975 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value, 11976 * and token processing _can_ alter it (delete NULs etc). */ 10780 11977 setinputstring((char *)ps); 10781 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);11978 readtoken1(pgetc(), PSSYNTAX, nullstr, 0); 10782 11979 popfile(); 10783 11980 … … 10806 12003 10807 12004 skip = 0; 10808 while ((n = parsecmd(0)) != N EOF) {12005 while ((n = parsecmd(0)) != NODE_EOF) { 10809 12006 evaltree(n, 0); 10810 12007 popstackmark(&smark); … … 10823 12020 * The eval command. 10824 12021 */ 10825 static int 10826 evalcmd(int argc , char **argv)12022 static int FAST_FUNC 12023 evalcmd(int argc UNUSED_PARAM, char **argv) 10827 12024 { 10828 12025 char *p; 10829 12026 char *concat; 10830 char **ap; 10831 10832 if (argc > 1) { 12027 12028 if (argv[1]) { 10833 12029 p = argv[1]; 10834 if (argc > 2) { 12030 argv += 2; 12031 if (argv[0]) { 10835 12032 STARTSTACKSTR(concat); 10836 ap = argv + 2;10837 12033 for (;;) { 10838 12034 concat = stack_putstr(p, concat); 10839 p = *a p++;12035 p = *argv++; 10840 12036 if (p == NULL) 10841 12037 break; … … 10846 12042 } 10847 12043 evalstring(p, ~SKIPEVAL); 10848 10849 12044 } 10850 12045 return exitstatus; … … 10852 12047 10853 12048 /* 10854 * Read and execute commands. "Top" is nonzero for the top level command 10855 * loop; it turns on prompting if the shell is interactive. 12049 * Read and execute commands. 12050 * "Top" is nonzero for the top level command loop; 12051 * it turns on prompting if the shell is interactive. 10856 12052 */ 10857 12053 static int … … 10869 12065 setstackmark(&smark); 10870 12066 #if JOBS 10871 if ( jobctl)12067 if (doing_jobctl) 10872 12068 showjobs(stderr, SHOW_CHANGED); 10873 12069 #endif … … 10880 12076 } 10881 12077 n = parsecmd(inter); 10882 /* showtree(n); DEBUG */ 10883 if (n == NEOF) { 12078 #if DEBUG 12079 if (DEBUG > 2 && debug && (n != NODE_EOF)) 12080 showtree(n); 12081 #endif 12082 if (n == NODE_EOF) { 10884 12083 if (!top || numeof >= 50) 10885 12084 break; … … 10922 12121 return name; 10923 12122 10924 while ((fullname = padvance(&path, name)) != NULL) { 12123 /* IIRC standards do not say whether . is to be searched. 12124 * And it is even smaller this way, making it unconditional for now: 12125 */ 12126 if (1) { /* ENABLE_ASH_BASH_COMPAT */ 12127 fullname = name; 12128 goto try_cur_dir; 12129 } 12130 12131 while ((fullname = path_advance(&path, name)) != NULL) { 12132 try_cur_dir: 10925 12133 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 10926 12134 /* … … 10930 12138 return fullname; 10931 12139 } 10932 stunalloc(fullname); 12140 if (fullname != name) 12141 stunalloc(fullname); 10933 12142 } 10934 12143 … … 10938 12147 } 10939 12148 10940 static int 12149 static int FAST_FUNC 10941 12150 dotcmd(int argc, char **argv) 10942 12151 { 12152 char *fullname; 10943 12153 struct strlist *sp; 10944 12154 volatile struct shparam saveparam; 10945 int status = 0;10946 12155 10947 12156 for (sp = cmdenviron; sp; sp = sp->next) 10948 12157 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 10949 12158 10950 if (argc >= 2) { /* That's what SVR2 does */ 10951 char *fullname; 10952 10953 fullname = find_dot_file(argv[1]); 10954 10955 if (argc > 2) { 10956 saveparam = shellparam; 10957 shellparam.malloc = 0; 10958 shellparam.nparam = argc - 2; 10959 shellparam.p = argv + 2; 10960 }; 10961 10962 setinputfile(fullname, INPUT_PUSH_FILE); 10963 commandname = fullname; 10964 cmdloop(0); 10965 popfile(); 10966 10967 if (argc > 2) { 10968 freeparam(&shellparam); 10969 shellparam = saveparam; 10970 }; 10971 status = exitstatus; 10972 } 10973 return status; 10974 } 10975 10976 static int 10977 exitcmd(int argc, char **argv) 12159 if (!argv[1]) { 12160 /* bash says: "bash: .: filename argument required" */ 12161 return 2; /* bash compat */ 12162 } 12163 12164 /* "false; . empty_file; echo $?" should print 0, not 1: */ 12165 exitstatus = 0; 12166 12167 fullname = find_dot_file(argv[1]); 12168 12169 argv += 2; 12170 argc -= 2; 12171 if (argc) { /* argc > 0, argv[0] != NULL */ 12172 saveparam = shellparam; 12173 shellparam.malloced = 0; 12174 shellparam.nparam = argc; 12175 shellparam.p = argv; 12176 }; 12177 12178 setinputfile(fullname, INPUT_PUSH_FILE); 12179 commandname = fullname; 12180 cmdloop(0); 12181 popfile(); 12182 12183 if (argc) { 12184 freeparam(&shellparam); 12185 shellparam = saveparam; 12186 }; 12187 12188 return exitstatus; 12189 } 12190 12191 static int FAST_FUNC 12192 exitcmd(int argc UNUSED_PARAM, char **argv) 10978 12193 { 10979 12194 if (stoppedjobs()) 10980 12195 return 0; 10981 if (arg c > 1)12196 if (argv[1]) 10982 12197 exitstatus = number(argv[1]); 10983 12198 raise_exception(EXEXIT); 10984 12199 /* NOTREACHED */ 10985 12200 } 10986 10987 #if ENABLE_ASH_BUILTIN_ECHO10988 static int10989 echocmd(int argc, char **argv)10990 {10991 return bb_echo(argv);10992 }10993 #endif10994 10995 #if ENABLE_ASH_BUILTIN_TEST10996 static int10997 testcmd(int argc, char **argv)10998 {10999 return test_main(argc, argv);11000 }11001 #endif11002 12201 11003 12202 /* … … 11099 12298 11100 12299 #if ENABLE_FEATURE_SH_STANDALONE 11101 if (find_applet_by_name(name)) { 11102 entry->cmdtype = CMDNORMAL; 11103 entry->u.index = -1; 11104 return; 12300 { 12301 int applet_no = find_applet_by_name(name); 12302 if (applet_no >= 0) { 12303 entry->cmdtype = CMDNORMAL; 12304 entry->u.index = -2 - applet_no; 12305 return; 12306 } 11105 12307 } 11106 12308 #endif … … 11118 12320 idx = -1; 11119 12321 loop: 11120 while ((fullname = pa dvance(&path, name)) != NULL) {12322 while ((fullname = path_advance(&path, name)) != NULL) { 11121 12323 stunalloc(fullname); 11122 12324 /* NB: code below will still use fullname … … 11128 12330 goto builtin_success; 11129 12331 continue; 11130 } else if (!(act & DO_NOFUNC) 11131 && prefix(pathopt, "func")) { 11132 /* handled below */ 11133 } else { 11134 /* ignore unimplemented options */ 12332 } 12333 if ((act & DO_NOFUNC) 12334 || !prefix(pathopt, "func") 12335 ) { /* ignore unimplemented options */ 11135 12336 continue; 11136 12337 } … … 11212 12413 * The trap builtin. 11213 12414 */ 11214 static int 11215 trapcmd(int argc , char **argv)12415 static int FAST_FUNC 12416 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 11216 12417 { 11217 12418 char *action; 11218 12419 char **ap; 11219 int signo ;12420 int signo, exitcode; 11220 12421 11221 12422 nextopt(nullstr); … … 11223 12424 if (!*ap) { 11224 12425 for (signo = 0; signo < NSIG; signo++) { 11225 if (trap[signo] != NULL) { 11226 const char *sn; 11227 11228 sn = get_signame(signo); 12426 char *tr = trap_ptr[signo]; 12427 if (tr) { 12428 /* note: bash adds "SIG", but only if invoked 12429 * as "bash". If called as "sh", or if set -o posix, 12430 * then it prints short signal names. 12431 * We are printing short names: */ 11229 12432 out1fmt("trap -- %s %s\n", 11230 single_quote(trap[signo]), sn); 12433 single_quote(tr), 12434 get_signame(signo)); 12435 /* trap_ptr != trap only if we are in special-cased `trap` code. 12436 * In this case, we will exit very soon, no need to free(). */ 12437 /* if (trap_ptr != trap && tp[0]) */ 12438 /* free(tr); */ 11231 12439 } 11232 12440 } 12441 /* 12442 if (trap_ptr != trap) { 12443 free(trap_ptr); 12444 trap_ptr = trap; 12445 } 12446 */ 11233 12447 return 0; 11234 12448 } 11235 if (!ap[1]) 11236 11237 else12449 12450 action = NULL; 12451 if (ap[1]) 11238 12452 action = *ap++; 12453 exitcode = 0; 11239 12454 while (*ap) { 11240 12455 signo = get_signum(*ap); 11241 if (signo < 0) 11242 ash_msg_and_raise_error("%s: bad trap", *ap); 12456 if (signo < 0) { 12457 /* Mimic bash message exactly */ 12458 ash_msg("%s: invalid signal specification", *ap); 12459 exitcode = 1; 12460 goto next; 12461 } 11243 12462 INT_OFF; 11244 12463 if (action) { … … 11248 12467 action = ckstrdup(action); 11249 12468 } 11250 if (trap[signo]) 11251 free(trap[signo]); 12469 free(trap[signo]); 12470 if (action) 12471 may_have_traps = 1; 11252 12472 trap[signo] = action; 11253 12473 if (signo != 0) 11254 12474 setsignal(signo); 11255 12475 INT_ON; 12476 next: 11256 12477 ap++; 11257 12478 } 11258 return 0;12479 return exitcode; 11259 12480 } 11260 12481 … … 11266 12487 * Lists available builtins 11267 12488 */ 11268 static int 11269 helpcmd(int argc, char **argv) 11270 { 11271 int col, i; 11272 11273 out1fmt("\nBuilt-in commands:\n-------------------\n"); 12489 static int FAST_FUNC 12490 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12491 { 12492 unsigned col; 12493 unsigned i; 12494 12495 out1fmt( 12496 "Built-in commands:\n" 12497 "------------------\n"); 11274 12498 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { 11275 12499 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), … … 11281 12505 } 11282 12506 #if ENABLE_FEATURE_SH_STANDALONE 11283 for (i = 0; i < NUM_APPLETS; i++) { 11284 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11285 if (col > 60) { 11286 out1fmt("\n"); 11287 col = 0; 12507 { 12508 const char *a = applet_names; 12509 while (*a) { 12510 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); 12511 if (col > 60) { 12512 out1fmt("\n"); 12513 col = 0; 12514 } 12515 a += strlen(a) + 1; 11288 12516 } 11289 12517 } … … 11297 12525 * The export and readonly commands. 11298 12526 */ 11299 static int 11300 exportcmd(int argc , char **argv)12527 static int FAST_FUNC 12528 exportcmd(int argc UNUSED_PARAM, char **argv) 11301 12529 { 11302 12530 struct var *vp; … … 11304 12532 const char *p; 11305 12533 char **aptr; 11306 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;12534 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; 11307 12535 11308 12536 if (nextopt("p") != 'p') { … … 11339 12567 11340 12568 cmdp = cmdlookup(name, 0); 11341 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)12569 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION) 11342 12570 delete_cmd_entry(); 11343 12571 } … … 11348 12576 * with the same name. 11349 12577 */ 11350 static int 11351 unsetcmd(int argc , char **argv)12578 static int FAST_FUNC 12579 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 11352 12580 { 11353 12581 char **ap; … … 11356 12584 int ret = 0; 11357 12585 11358 while ((i = nextopt("vf")) != '\0') {12586 while ((i = nextopt("vf")) != 0) { 11359 12587 flag = i; 11360 12588 } … … 11372 12600 return ret & 1; 11373 12601 } 11374 11375 11376 /* setmode.c */11377 11378 #include <sys/times.h>11379 12602 11380 12603 static const unsigned char timescmd_str[] ALIGN1 = { … … 11385 12608 0 11386 12609 }; 11387 11388 static int 11389 timescmd(int ac, char **av) 11390 { 11391 long clk_tck, s, t; 12610 static int FAST_FUNC 12611 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12612 { 12613 unsigned long clk_tck, s, t; 11392 12614 const unsigned char *p; 11393 12615 struct tms buf; … … 11400 12622 t = *(clock_t *)(((char *) &buf) + p[1]); 11401 12623 s = t / clk_tck; 11402 out1fmt("%ldm%ld.%.3lds%c", 11403 s/60, s%60, 11404 ((t - s * clk_tck) * 1000) / clk_tck, 12624 t = t % clk_tck; 12625 out1fmt("%lum%lu.%03lus%c", 12626 s / 60, s % 60, 12627 (t * 1000) / clk_tck, 11405 12628 p[0]); 11406 } while (*(p += 2)); 12629 p += 2; 12630 } while (*p); 11407 12631 11408 12632 return 0; 11409 12633 } 11410 12634 11411 #if ENABLE_ASH_MATH_SUPPORT 11412 static arith_t 11413 dash_arith(const char *s) 11414 { 11415 arith_t result; 11416 int errcode = 0; 11417 11418 INT_OFF; 11419 result = arith(s, &errcode); 11420 if (errcode < 0) { 11421 if (errcode == -3) 11422 ash_msg_and_raise_error("exponent less than 0"); 11423 if (errcode == -2) 11424 ash_msg_and_raise_error("divide by zero"); 11425 if (errcode == -5) 11426 ash_msg_and_raise_error("expression recursion loop detected"); 11427 raise_error_syntax(s); 11428 } 11429 INT_ON; 11430 11431 return result; 11432 } 11433 11434 /* 11435 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. 11436 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. 12635 #if ENABLE_SH_MATH_SUPPORT 12636 /* 12637 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. 12638 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. 11437 12639 * 11438 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 11439 */ 11440 static int 11441 letcmd(int argc, char **argv) 11442 { 11443 char **ap; 11444 arith_t i = 0; 11445 11446 ap = argv + 1; 11447 if (!*ap) 12640 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 12641 */ 12642 static int FAST_FUNC 12643 letcmd(int argc UNUSED_PARAM, char **argv) 12644 { 12645 arith_t i; 12646 12647 argv++; 12648 if (!*argv) 11448 12649 ash_msg_and_raise_error("expression expected"); 11449 for (ap = argv + 1; *ap; ap++){11450 i = dash_arith(*ap);11451 } 12650 do { 12651 i = ash_arith(*argv); 12652 } while (*++argv); 11452 12653 11453 12654 return !i; 11454 12655 } 11455 #endif /* ASH_MATH_SUPPORT */ 11456 11457 11458 /* ============ miscbltin.c 11459 * 11460 * Miscellaneous builtins. 11461 */ 11462 11463 #undef rflag 11464 11465 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 11466 typedef enum __rlimit_resource rlim_t; 11467 #endif 11468 11469 /* 11470 * The read builtin. The -e option causes backslashes to escape the 11471 * following character. 11472 * 12656 #endif 12657 12658 /* 12659 * The read builtin. Options: 12660 * -r Do not interpret '\' specially 12661 * -s Turn off echo (tty only) 12662 * -n NCHARS Read NCHARS max 12663 * -p PROMPT Display PROMPT on stderr (if input is from tty) 12664 * -t SECONDS Timeout after SECONDS (tty or pipe only) 12665 * -u FD Read from given FD instead of fd 0 11473 12666 * This uses unbuffered input, which may be avoidable in some cases. 11474 */ 11475 static int 11476 readcmd(int argc, char **argv) 11477 { 11478 char **ap; 11479 int backslash; 11480 char c; 11481 int rflag; 11482 char *prompt; 11483 const char *ifs; 11484 char *p; 11485 int startword; 11486 int status; 12667 * TODO: bash also has: 12668 * -a ARRAY Read into array[0],[1],etc 12669 * -d DELIM End on DELIM char, not newline 12670 * -e Use line editing (tty only) 12671 */ 12672 static int FAST_FUNC 12673 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12674 { 12675 char *opt_n = NULL; 12676 char *opt_p = NULL; 12677 char *opt_t = NULL; 12678 char *opt_u = NULL; 12679 int read_flags = 0; 12680 const char *r; 11487 12681 int i; 11488 #if ENABLE_ASH_READ_NCHARS 11489 int nch_flag = 0; 11490 int nchars = 0; 11491 int silent = 0; 11492 struct termios tty, old_tty; 11493 #endif 11494 #if ENABLE_ASH_READ_TIMEOUT 11495 fd_set set; 11496 struct timeval ts; 11497 11498 ts.tv_sec = ts.tv_usec = 0; 11499 #endif 11500 11501 rflag = 0; 11502 prompt = NULL; 11503 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT 11504 while ((i = nextopt("p:rt:n:s")) != '\0') 11505 #elif ENABLE_ASH_READ_NCHARS 11506 while ((i = nextopt("p:rn:s")) != '\0') 11507 #elif ENABLE_ASH_READ_TIMEOUT 11508 while ((i = nextopt("p:rt:")) != '\0') 11509 #else 11510 while ((i = nextopt("p:r")) != '\0') 11511 #endif 11512 { 12682 12683 while ((i = nextopt("p:u:rt:n:s")) != '\0') { 11513 12684 switch (i) { 11514 12685 case 'p': 11515 prompt= optionarg;12686 opt_p = optionarg; 11516 12687 break; 11517 #if ENABLE_ASH_READ_NCHARS11518 12688 case 'n': 11519 nchars = strtol(optionarg, &p, 10); 11520 if (*p) 11521 ash_msg_and_raise_error("invalid count"); 11522 nch_flag = (nchars > 0); 12689 opt_n = optionarg; 11523 12690 break; 11524 12691 case 's': 11525 silent = 1;12692 read_flags |= BUILTIN_READ_SILENT; 11526 12693 break; 11527 #endif11528 #if ENABLE_ASH_READ_TIMEOUT11529 12694 case 't': 11530 ts.tv_sec = strtol(optionarg, &p, 10); 11531 ts.tv_usec = 0; 11532 if (*p == '.') { 11533 char *p2; 11534 if (*++p) { 11535 int scale; 11536 ts.tv_usec = strtol(p, &p2, 10); 11537 if (*p2) 11538 ash_msg_and_raise_error("invalid timeout"); 11539 scale = p2 - p; 11540 /* normalize to usec */ 11541 if (scale > 6) 11542 ash_msg_and_raise_error("invalid timeout"); 11543 while (scale++ < 6) 11544 ts.tv_usec *= 10; 11545 } 11546 } else if (*p) { 11547 ash_msg_and_raise_error("invalid timeout"); 11548 } 11549 if ( ! ts.tv_sec && ! ts.tv_usec) 11550 ash_msg_and_raise_error("invalid timeout"); 12695 opt_t = optionarg; 11551 12696 break; 11552 #endif11553 12697 case 'r': 11554 rflag = 1; 12698 read_flags |= BUILTIN_READ_RAW; 12699 break; 12700 case 'u': 12701 opt_u = optionarg; 11555 12702 break; 11556 12703 default: … … 11558 12705 } 11559 12706 } 11560 if (prompt && isatty(0)) { 11561 out2str(prompt); 11562 } 11563 ap = argptr; 11564 if (*ap == NULL) 11565 ash_msg_and_raise_error("arg count"); 11566 ifs = bltinlookup("IFS"); 11567 if (ifs == NULL) 11568 ifs = defifs; 11569 #if ENABLE_ASH_READ_NCHARS 11570 if (nch_flag || silent) { 11571 tcgetattr(0, &tty); 11572 old_tty = tty; 11573 if (nch_flag) { 11574 tty.c_lflag &= ~ICANON; 11575 tty.c_cc[VMIN] = nchars; 11576 } 11577 if (silent) { 11578 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); 11579 11580 } 11581 tcsetattr(0, TCSANOW, &tty); 11582 } 11583 #endif 11584 #if ENABLE_ASH_READ_TIMEOUT 11585 if (ts.tv_sec || ts.tv_usec) { 11586 FD_ZERO(&set); 11587 FD_SET(0, &set); 11588 11589 i = select(FD_SETSIZE, &set, NULL, NULL, &ts); 11590 if (!i) { 11591 #if ENABLE_ASH_READ_NCHARS 11592 if (nch_flag) 11593 tcsetattr(0, TCSANOW, &old_tty); 11594 #endif 11595 return 1; 11596 } 11597 } 11598 #endif 11599 status = 0; 11600 startword = 1; 11601 backslash = 0; 11602 STARTSTACKSTR(p); 11603 #if ENABLE_ASH_READ_NCHARS 11604 while (!nch_flag || nchars--) 11605 #else 11606 for (;;) 11607 #endif 11608 { 11609 if (read(0, &c, 1) != 1) { 11610 status = 1; 11611 break; 11612 } 11613 if (c == '\0') 11614 continue; 11615 if (backslash) { 11616 backslash = 0; 11617 if (c != '\n') 11618 goto put; 11619 continue; 11620 } 11621 if (!rflag && c == '\\') { 11622 backslash++; 11623 continue; 11624 } 11625 if (c == '\n') 11626 break; 11627 if (startword && *ifs == ' ' && strchr(ifs, c)) { 11628 continue; 11629 } 11630 startword = 0; 11631 if (ap[1] != NULL && strchr(ifs, c) != NULL) { 11632 STACKSTRNUL(p); 11633 setvar(*ap, stackblock(), 0); 11634 ap++; 11635 startword = 1; 11636 STARTSTACKSTR(p); 11637 } else { 11638 put: 11639 STPUTC(c, p); 11640 } 11641 } 11642 #if ENABLE_ASH_READ_NCHARS 11643 if (nch_flag || silent) 11644 tcsetattr(0, TCSANOW, &old_tty); 11645 #endif 11646 11647 STACKSTRNUL(p); 11648 /* Remove trailing blanks */ 11649 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) 11650 *p = '\0'; 11651 setvar(*ap, stackblock(), 0); 11652 while (*++ap != NULL) 11653 setvar(*ap, nullstr, 0); 11654 return status; 11655 } 11656 11657 static int 11658 umaskcmd(int argc, char **argv) 12707 12708 r = shell_builtin_read(setvar2, 12709 argptr, 12710 bltinlookup("IFS"), /* can be NULL */ 12711 read_flags, 12712 opt_n, 12713 opt_p, 12714 opt_t, 12715 opt_u 12716 ); 12717 12718 if ((uintptr_t)r > 1) 12719 ash_msg_and_raise_error(r); 12720 12721 return (uintptr_t)r; 12722 } 12723 12724 static int FAST_FUNC 12725 umaskcmd(int argc UNUSED_PARAM, char **argv) 11659 12726 { 11660 12727 static const char permuser[3] ALIGN1 = "ugo"; … … 11665 12732 S_IROTH, S_IWOTH, S_IXOTH 11666 12733 }; 12734 12735 /* TODO: use bb_parse_mode() instead */ 11667 12736 11668 12737 char *ap; … … 11708 12777 do { 11709 12778 if (*ap >= '8' || *ap < '0') 11710 ash_msg_and_raise_error( illnum, argv[1]);12779 ash_msg_and_raise_error(msg_illnum, argv[1]); 11711 12780 mask = (mask << 3) + (*ap - '0'); 11712 12781 } while (*++ap != '\0'); … … 11723 12792 } 11724 12793 11725 /* 11726 * ulimit builtin 11727 * 11728 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 11729 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 11730 * ash by J.T. Conklin. 11731 * 11732 * Public domain. 11733 */ 11734 11735 struct limits { 11736 const char *name; 11737 int cmd; 11738 int factor; /* multiply by to get rlim_{cur,max} values */ 11739 char option; 11740 }; 11741 11742 static const struct limits limits[] = { 11743 #ifdef RLIMIT_CPU 11744 { "time(seconds)", RLIMIT_CPU, 1, 't' }, 11745 #endif 11746 #ifdef RLIMIT_FSIZE 11747 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, 11748 #endif 11749 #ifdef RLIMIT_DATA 11750 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, 11751 #endif 11752 #ifdef RLIMIT_STACK 11753 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, 11754 #endif 11755 #ifdef RLIMIT_CORE 11756 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, 11757 #endif 11758 #ifdef RLIMIT_RSS 11759 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, 11760 #endif 11761 #ifdef RLIMIT_MEMLOCK 11762 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, 11763 #endif 11764 #ifdef RLIMIT_NPROC 11765 { "process", RLIMIT_NPROC, 1, 'p' }, 11766 #endif 11767 #ifdef RLIMIT_NOFILE 11768 { "nofiles", RLIMIT_NOFILE, 1, 'n' }, 11769 #endif 11770 #ifdef RLIMIT_AS 11771 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' }, 11772 #endif 11773 #ifdef RLIMIT_LOCKS 11774 { "locks", RLIMIT_LOCKS, 1, 'w' }, 11775 #endif 11776 { NULL, 0, 0, '\0' } 11777 }; 11778 11779 enum limtype { SOFT = 0x1, HARD = 0x2 }; 11780 11781 static void 11782 printlim(enum limtype how, const struct rlimit *limit, 11783 const struct limits *l) 11784 { 11785 rlim_t val; 11786 11787 val = limit->rlim_max; 11788 if (how & SOFT) 11789 val = limit->rlim_cur; 11790 11791 if (val == RLIM_INFINITY) 11792 out1fmt("unlimited\n"); 11793 else { 11794 val /= l->factor; 11795 out1fmt("%lld\n", (long long) val); 11796 } 11797 } 11798 11799 static int 11800 ulimitcmd(int argc, char **argv) 11801 { 11802 int c; 11803 rlim_t val = 0; 11804 enum limtype how = SOFT | HARD; 11805 const struct limits *l; 11806 int set, all = 0; 11807 int optc, what; 11808 struct rlimit limit; 11809 11810 what = 'f'; 11811 while ((optc = nextopt("HSa" 11812 #ifdef RLIMIT_CPU 11813 "t" 11814 #endif 11815 #ifdef RLIMIT_FSIZE 11816 "f" 11817 #endif 11818 #ifdef RLIMIT_DATA 11819 "d" 11820 #endif 11821 #ifdef RLIMIT_STACK 11822 "s" 11823 #endif 11824 #ifdef RLIMIT_CORE 11825 "c" 11826 #endif 11827 #ifdef RLIMIT_RSS 11828 "m" 11829 #endif 11830 #ifdef RLIMIT_MEMLOCK 11831 "l" 11832 #endif 11833 #ifdef RLIMIT_NPROC 11834 "p" 11835 #endif 11836 #ifdef RLIMIT_NOFILE 11837 "n" 11838 #endif 11839 #ifdef RLIMIT_AS 11840 "v" 11841 #endif 11842 #ifdef RLIMIT_LOCKS 11843 "w" 11844 #endif 11845 )) != '\0') 11846 switch (optc) { 11847 case 'H': 11848 how = HARD; 11849 break; 11850 case 'S': 11851 how = SOFT; 11852 break; 11853 case 'a': 11854 all = 1; 11855 break; 11856 default: 11857 what = optc; 11858 } 11859 11860 for (l = limits; l->option != what; l++) 11861 ; 11862 11863 set = *argptr ? 1 : 0; 11864 if (set) { 11865 char *p = *argptr; 11866 11867 if (all || argptr[1]) 11868 ash_msg_and_raise_error("too many arguments"); 11869 if (strncmp(p, "unlimited\n", 9) == 0) 11870 val = RLIM_INFINITY; 11871 else { 11872 val = (rlim_t) 0; 11873 11874 while ((c = *p++) >= '0' && c <= '9') { 11875 val = (val * 10) + (long)(c - '0'); 11876 if (val < (rlim_t) 0) 11877 break; 11878 } 11879 if (c) 11880 ash_msg_and_raise_error("bad number"); 11881 val *= l->factor; 11882 } 11883 } 11884 if (all) { 11885 for (l = limits; l->name; l++) { 11886 getrlimit(l->cmd, &limit); 11887 out1fmt("%-20s ", l->name); 11888 printlim(how, &limit, l); 11889 } 11890 return 0; 11891 } 11892 11893 getrlimit(l->cmd, &limit); 11894 if (set) { 11895 if (how & HARD) 11896 limit.rlim_max = val; 11897 if (how & SOFT) 11898 limit.rlim_cur = val; 11899 if (setrlimit(l->cmd, &limit) < 0) 11900 ash_msg_and_raise_error("error setting limit (%m)"); 11901 } else { 11902 printlim(how, &limit, l); 11903 } 11904 return 0; 11905 } 11906 11907 11908 /* ============ Math support */ 11909 11910 #if ENABLE_ASH_MATH_SUPPORT 11911 11912 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 11913 11914 Permission is hereby granted, free of charge, to any person obtaining 11915 a copy of this software and associated documentation files (the 11916 "Software"), to deal in the Software without restriction, including 11917 without limitation the rights to use, copy, modify, merge, publish, 11918 distribute, sublicense, and/or sell copies of the Software, and to 11919 permit persons to whom the Software is furnished to do so, subject to 11920 the following conditions: 11921 11922 The above copyright notice and this permission notice shall be 11923 included in all copies or substantial portions of the Software. 11924 11925 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11926 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11927 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 11928 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 11929 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 11930 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 11931 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11932 */ 11933 11934 /* This is my infix parser/evaluator. It is optimized for size, intended 11935 * as a replacement for yacc-based parsers. However, it may well be faster 11936 * than a comparable parser written in yacc. The supported operators are 11937 * listed in #defines below. Parens, order of operations, and error handling 11938 * are supported. This code is thread safe. The exact expression format should 11939 * be that which POSIX specifies for shells. */ 11940 11941 /* The code uses a simple two-stack algorithm. See 11942 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html 11943 * for a detailed explanation of the infix-to-postfix algorithm on which 11944 * this is based (this code differs in that it applies operators immediately 11945 * to the stack instead of adding them to a queue to end up with an 11946 * expression). */ 11947 11948 /* To use the routine, call it with an expression string and error return 11949 * pointer */ 11950 11951 /* 11952 * Aug 24, 2001 Manuel Novoa III 11953 * 11954 * Reduced the generated code size by about 30% (i386) and fixed several bugs. 11955 * 11956 * 1) In arith_apply(): 11957 * a) Cached values of *numptr and &(numptr[-1]). 11958 * b) Removed redundant test for zero denominator. 11959 * 11960 * 2) In arith(): 11961 * a) Eliminated redundant code for processing operator tokens by moving 11962 * to a table-based implementation. Also folded handling of parens 11963 * into the table. 11964 * b) Combined all 3 loops which called arith_apply to reduce generated 11965 * code size at the cost of speed. 11966 * 11967 * 3) The following expressions were treated as valid by the original code: 11968 * 1() , 0! , 1 ( *3 ) . 11969 * These bugs have been fixed by internally enclosing the expression in 11970 * parens and then checking that all binary ops and right parens are 11971 * preceded by a valid expression (NUM_TOKEN). 11972 * 11973 * Note: It may be desirable to replace Aaron's test for whitespace with 11974 * ctype's isspace() if it is used by another busybox applet or if additional 11975 * whitespace chars should be considered. Look below the "#include"s for a 11976 * precompiler test. 11977 */ 11978 11979 /* 11980 * Aug 26, 2001 Manuel Novoa III 11981 * 11982 * Return 0 for null expressions. Pointed out by Vladimir Oleynik. 11983 * 11984 * Merge in Aaron's comments previously posted to the busybox list, 11985 * modified slightly to take account of my changes to the code. 11986 * 11987 */ 11988 11989 /* 11990 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 11991 * 11992 * - allow access to variable, 11993 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) 11994 * - realize assign syntax (VAR=expr, +=, *= etc) 11995 * - realize exponentiation (** operator) 11996 * - realize comma separated - expr, expr 11997 * - realise ++expr --expr expr++ expr-- 11998 * - realise expr ? expr : expr (but, second expr calculate always) 11999 * - allow hexadecimal and octal numbers 12000 * - was restored loses XOR operator 12001 * - remove one goto label, added three ;-) 12002 * - protect $((num num)) as true zero expr (Manuel`s error) 12003 * - always use special isspace(), see comment from bash ;-) 12004 */ 12005 12006 #define arith_isspace(arithval) \ 12007 (arithval == ' ' || arithval == '\n' || arithval == '\t') 12008 12009 typedef unsigned char operator; 12010 12011 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the 12012 * precedence, and 3 high bits are an ID unique across operators of that 12013 * precedence. The ID portion is so that multiple operators can have the 12014 * same precedence, ensuring that the leftmost one is evaluated first. 12015 * Consider * and /. */ 12016 12017 #define tok_decl(prec,id) (((id)<<5)|(prec)) 12018 #define PREC(op) ((op) & 0x1F) 12019 12020 #define TOK_LPAREN tok_decl(0,0) 12021 12022 #define TOK_COMMA tok_decl(1,0) 12023 12024 #define TOK_ASSIGN tok_decl(2,0) 12025 #define TOK_AND_ASSIGN tok_decl(2,1) 12026 #define TOK_OR_ASSIGN tok_decl(2,2) 12027 #define TOK_XOR_ASSIGN tok_decl(2,3) 12028 #define TOK_PLUS_ASSIGN tok_decl(2,4) 12029 #define TOK_MINUS_ASSIGN tok_decl(2,5) 12030 #define TOK_LSHIFT_ASSIGN tok_decl(2,6) 12031 #define TOK_RSHIFT_ASSIGN tok_decl(2,7) 12032 12033 #define TOK_MUL_ASSIGN tok_decl(3,0) 12034 #define TOK_DIV_ASSIGN tok_decl(3,1) 12035 #define TOK_REM_ASSIGN tok_decl(3,2) 12036 12037 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 12038 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 12039 12040 /* conditional is right associativity too */ 12041 #define TOK_CONDITIONAL tok_decl(4,0) 12042 #define TOK_CONDITIONAL_SEP tok_decl(4,1) 12043 12044 #define TOK_OR tok_decl(5,0) 12045 12046 #define TOK_AND tok_decl(6,0) 12047 12048 #define TOK_BOR tok_decl(7,0) 12049 12050 #define TOK_BXOR tok_decl(8,0) 12051 12052 #define TOK_BAND tok_decl(9,0) 12053 12054 #define TOK_EQ tok_decl(10,0) 12055 #define TOK_NE tok_decl(10,1) 12056 12057 #define TOK_LT tok_decl(11,0) 12058 #define TOK_GT tok_decl(11,1) 12059 #define TOK_GE tok_decl(11,2) 12060 #define TOK_LE tok_decl(11,3) 12061 12062 #define TOK_LSHIFT tok_decl(12,0) 12063 #define TOK_RSHIFT tok_decl(12,1) 12064 12065 #define TOK_ADD tok_decl(13,0) 12066 #define TOK_SUB tok_decl(13,1) 12067 12068 #define TOK_MUL tok_decl(14,0) 12069 #define TOK_DIV tok_decl(14,1) 12070 #define TOK_REM tok_decl(14,2) 12071 12072 /* exponent is right associativity */ 12073 #define TOK_EXPONENT tok_decl(15,1) 12074 12075 /* For now unary operators. */ 12076 #define UNARYPREC 16 12077 #define TOK_BNOT tok_decl(UNARYPREC,0) 12078 #define TOK_NOT tok_decl(UNARYPREC,1) 12079 12080 #define TOK_UMINUS tok_decl(UNARYPREC+1,0) 12081 #define TOK_UPLUS tok_decl(UNARYPREC+1,1) 12082 12083 #define PREC_PRE (UNARYPREC+2) 12084 12085 #define TOK_PRE_INC tok_decl(PREC_PRE, 0) 12086 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1) 12087 12088 #define PREC_POST (UNARYPREC+3) 12089 12090 #define TOK_POST_INC tok_decl(PREC_POST, 0) 12091 #define TOK_POST_DEC tok_decl(PREC_POST, 1) 12092 12093 #define SPEC_PREC (UNARYPREC+4) 12094 12095 #define TOK_NUM tok_decl(SPEC_PREC, 0) 12096 #define TOK_RPAREN tok_decl(SPEC_PREC, 1) 12097 12098 #define NUMPTR (*numstackptr) 12099 12100 static int 12101 tok_have_assign(operator op) 12102 { 12103 operator prec = PREC(op); 12104 12105 convert_prec_is_assing(prec); 12106 return (prec == PREC(TOK_ASSIGN) || 12107 prec == PREC_PRE || prec == PREC_POST); 12108 } 12109 12110 static int 12111 is_right_associativity(operator prec) 12112 { 12113 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 12114 || prec == PREC(TOK_CONDITIONAL)); 12115 } 12116 12117 typedef struct ARITCH_VAR_NUM { 12118 arith_t val; 12119 arith_t contidional_second_val; 12120 char contidional_second_val_initialized; 12121 char *var; /* if NULL then is regular number, 12122 else is variable name */ 12123 } v_n_t; 12124 12125 typedef struct CHK_VAR_RECURSIVE_LOOPED { 12126 const char *var; 12127 struct CHK_VAR_RECURSIVE_LOOPED *next; 12128 } chk_var_recursive_looped_t; 12129 12130 static chk_var_recursive_looped_t *prev_chk_var_recursive; 12131 12132 static int 12133 arith_lookup_val(v_n_t *t) 12134 { 12135 if (t->var) { 12136 const char * p = lookupvar(t->var); 12137 12138 if (p) { 12139 int errcode; 12140 12141 /* recursive try as expression */ 12142 chk_var_recursive_looped_t *cur; 12143 chk_var_recursive_looped_t cur_save; 12144 12145 for (cur = prev_chk_var_recursive; cur; cur = cur->next) { 12146 if (strcmp(cur->var, t->var) == 0) { 12147 /* expression recursion loop detected */ 12148 return -5; 12149 } 12150 } 12151 /* save current lookuped var name */ 12152 cur = prev_chk_var_recursive; 12153 cur_save.var = t->var; 12154 cur_save.next = cur; 12155 prev_chk_var_recursive = &cur_save; 12156 12157 t->val = arith (p, &errcode); 12158 /* restore previous ptr after recursiving */ 12159 prev_chk_var_recursive = cur; 12160 return errcode; 12161 } 12162 /* allow undefined var as 0 */ 12163 t->val = 0; 12164 } 12165 return 0; 12166 } 12167 12168 /* "applying" a token means performing it on the top elements on the integer 12169 * stack. For a unary operator it will only change the top element, but a 12170 * binary operator will pop two arguments and push a result */ 12171 static int 12172 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) 12173 { 12174 v_n_t *numptr_m1; 12175 arith_t numptr_val, rez; 12176 int ret_arith_lookup_val; 12177 12178 /* There is no operator that can work without arguments */ 12179 if (NUMPTR == numstack) goto err; 12180 numptr_m1 = NUMPTR - 1; 12181 12182 /* check operand is var with noninteger value */ 12183 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12184 if (ret_arith_lookup_val) 12185 return ret_arith_lookup_val; 12186 12187 rez = numptr_m1->val; 12188 if (op == TOK_UMINUS) 12189 rez *= -1; 12190 else if (op == TOK_NOT) 12191 rez = !rez; 12192 else if (op == TOK_BNOT) 12193 rez = ~rez; 12194 else if (op == TOK_POST_INC || op == TOK_PRE_INC) 12195 rez++; 12196 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) 12197 rez--; 12198 else if (op != TOK_UPLUS) { 12199 /* Binary operators */ 12200 12201 /* check and binary operators need two arguments */ 12202 if (numptr_m1 == numstack) goto err; 12203 12204 /* ... and they pop one */ 12205 --NUMPTR; 12206 numptr_val = rez; 12207 if (op == TOK_CONDITIONAL) { 12208 if (! numptr_m1->contidional_second_val_initialized) { 12209 /* protect $((expr1 ? expr2)) without ": expr" */ 12210 goto err; 12211 } 12212 rez = numptr_m1->contidional_second_val; 12213 } else if (numptr_m1->contidional_second_val_initialized) { 12214 /* protect $((expr1 : expr2)) without "expr ? " */ 12215 goto err; 12216 } 12217 numptr_m1 = NUMPTR - 1; 12218 if (op != TOK_ASSIGN) { 12219 /* check operand is var with noninteger value for not '=' */ 12220 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12221 if (ret_arith_lookup_val) 12222 return ret_arith_lookup_val; 12223 } 12224 if (op == TOK_CONDITIONAL) { 12225 numptr_m1->contidional_second_val = rez; 12226 } 12227 rez = numptr_m1->val; 12228 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 12229 rez |= numptr_val; 12230 else if (op == TOK_OR) 12231 rez = numptr_val || rez; 12232 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 12233 rez &= numptr_val; 12234 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 12235 rez ^= numptr_val; 12236 else if (op == TOK_AND) 12237 rez = rez && numptr_val; 12238 else if (op == TOK_EQ) 12239 rez = (rez == numptr_val); 12240 else if (op == TOK_NE) 12241 rez = (rez != numptr_val); 12242 else if (op == TOK_GE) 12243 rez = (rez >= numptr_val); 12244 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 12245 rez >>= numptr_val; 12246 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 12247 rez <<= numptr_val; 12248 else if (op == TOK_GT) 12249 rez = (rez > numptr_val); 12250 else if (op == TOK_LT) 12251 rez = (rez < numptr_val); 12252 else if (op == TOK_LE) 12253 rez = (rez <= numptr_val); 12254 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 12255 rez *= numptr_val; 12256 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 12257 rez += numptr_val; 12258 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 12259 rez -= numptr_val; 12260 else if (op == TOK_ASSIGN || op == TOK_COMMA) 12261 rez = numptr_val; 12262 else if (op == TOK_CONDITIONAL_SEP) { 12263 if (numptr_m1 == numstack) { 12264 /* protect $((expr : expr)) without "expr ? " */ 12265 goto err; 12266 } 12267 numptr_m1->contidional_second_val_initialized = op; 12268 numptr_m1->contidional_second_val = numptr_val; 12269 } else if (op == TOK_CONDITIONAL) { 12270 rez = rez ? 12271 numptr_val : numptr_m1->contidional_second_val; 12272 } else if (op == TOK_EXPONENT) { 12273 if (numptr_val < 0) 12274 return -3; /* exponent less than 0 */ 12275 else { 12276 arith_t c = 1; 12277 12278 if (numptr_val) 12279 while (numptr_val--) 12280 c *= rez; 12281 rez = c; 12282 } 12283 } else if (numptr_val==0) /* zero divisor check */ 12284 return -2; 12285 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 12286 rez /= numptr_val; 12287 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 12288 rez %= numptr_val; 12289 } 12290 if (tok_have_assign(op)) { 12291 char buf[sizeof(arith_t_type)*3 + 2]; 12292 12293 if (numptr_m1->var == NULL) { 12294 /* Hmm, 1=2 ? */ 12295 goto err; 12296 } 12297 /* save to shell variable */ 12298 #if ENABLE_ASH_MATH_SUPPORT_64 12299 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); 12300 #else 12301 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); 12302 #endif 12303 setvar(numptr_m1->var, buf, 0); 12304 /* after saving, make previous value for v++ or v-- */ 12305 if (op == TOK_POST_INC) 12306 rez--; 12307 else if (op == TOK_POST_DEC) 12308 rez++; 12309 } 12310 numptr_m1->val = rez; 12311 /* protect geting var value, is number now */ 12312 numptr_m1->var = NULL; 12313 return 0; 12314 err: 12315 return -1; 12316 } 12317 12318 /* longest must be first */ 12319 static const char op_tokens[] ALIGN1 = { 12320 '<','<','=',0, TOK_LSHIFT_ASSIGN, 12321 '>','>','=',0, TOK_RSHIFT_ASSIGN, 12322 '<','<', 0, TOK_LSHIFT, 12323 '>','>', 0, TOK_RSHIFT, 12324 '|','|', 0, TOK_OR, 12325 '&','&', 0, TOK_AND, 12326 '!','=', 0, TOK_NE, 12327 '<','=', 0, TOK_LE, 12328 '>','=', 0, TOK_GE, 12329 '=','=', 0, TOK_EQ, 12330 '|','=', 0, TOK_OR_ASSIGN, 12331 '&','=', 0, TOK_AND_ASSIGN, 12332 '*','=', 0, TOK_MUL_ASSIGN, 12333 '/','=', 0, TOK_DIV_ASSIGN, 12334 '%','=', 0, TOK_REM_ASSIGN, 12335 '+','=', 0, TOK_PLUS_ASSIGN, 12336 '-','=', 0, TOK_MINUS_ASSIGN, 12337 '-','-', 0, TOK_POST_DEC, 12338 '^','=', 0, TOK_XOR_ASSIGN, 12339 '+','+', 0, TOK_POST_INC, 12340 '*','*', 0, TOK_EXPONENT, 12341 '!', 0, TOK_NOT, 12342 '<', 0, TOK_LT, 12343 '>', 0, TOK_GT, 12344 '=', 0, TOK_ASSIGN, 12345 '|', 0, TOK_BOR, 12346 '&', 0, TOK_BAND, 12347 '*', 0, TOK_MUL, 12348 '/', 0, TOK_DIV, 12349 '%', 0, TOK_REM, 12350 '+', 0, TOK_ADD, 12351 '-', 0, TOK_SUB, 12352 '^', 0, TOK_BXOR, 12353 /* uniq */ 12354 '~', 0, TOK_BNOT, 12355 ',', 0, TOK_COMMA, 12356 '?', 0, TOK_CONDITIONAL, 12357 ':', 0, TOK_CONDITIONAL_SEP, 12358 ')', 0, TOK_RPAREN, 12359 '(', 0, TOK_LPAREN, 12360 0 12361 }; 12362 /* ptr to ")" */ 12363 #define endexpression &op_tokens[sizeof(op_tokens)-7] 12364 12365 static arith_t 12366 arith(const char *expr, int *perrcode) 12367 { 12368 char arithval; /* Current character under analysis */ 12369 operator lasttok, op; 12370 operator prec; 12371 12372 const char *p = endexpression; 12373 int errcode; 12374 12375 size_t datasizes = strlen(expr) + 2; 12376 12377 /* Stack of integers */ 12378 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 12379 * in any given correct or incorrect expression is left as an exercise to 12380 * the reader. */ 12381 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 12382 *numstackptr = numstack; 12383 /* Stack of operator tokens */ 12384 operator *stack = alloca((datasizes) * sizeof(operator)), 12385 *stackptr = stack; 12386 12387 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 12388 *perrcode = errcode = 0; 12389 12390 while (1) { 12391 arithval = *expr; 12392 if (arithval == 0) { 12393 if (p == endexpression) { 12394 /* Null expression. */ 12395 return 0; 12396 } 12397 12398 /* This is only reached after all tokens have been extracted from the 12399 * input stream. If there are still tokens on the operator stack, they 12400 * are to be applied in order. At the end, there should be a final 12401 * result on the integer stack */ 12402 12403 if (expr != endexpression + 1) { 12404 /* If we haven't done so already, */ 12405 /* append a closing right paren */ 12406 expr = endexpression; 12407 /* and let the loop process it. */ 12408 continue; 12409 } 12410 /* At this point, we're done with the expression. */ 12411 if (numstackptr != numstack+1) { 12412 /* ... but if there isn't, it's bad */ 12413 err: 12414 return (*perrcode = -1); 12415 } 12416 if (numstack->var) { 12417 /* expression is $((var)) only, lookup now */ 12418 errcode = arith_lookup_val(numstack); 12419 } 12420 ret: 12421 *perrcode = errcode; 12422 return numstack->val; 12423 } 12424 12425 /* Continue processing the expression. */ 12426 if (arith_isspace(arithval)) { 12427 /* Skip whitespace */ 12428 goto prologue; 12429 } 12430 p = endofname(expr); 12431 if (p != expr) { 12432 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 12433 12434 numstackptr->var = alloca(var_name_size); 12435 safe_strncpy(numstackptr->var, expr, var_name_size); 12436 expr = p; 12437 num: 12438 numstackptr->contidional_second_val_initialized = 0; 12439 numstackptr++; 12440 lasttok = TOK_NUM; 12441 continue; 12442 } 12443 if (isdigit(arithval)) { 12444 numstackptr->var = NULL; 12445 #if ENABLE_ASH_MATH_SUPPORT_64 12446 numstackptr->val = strtoll(expr, (char **) &expr, 0); 12447 #else 12448 numstackptr->val = strtol(expr, (char **) &expr, 0); 12449 #endif 12450 goto num; 12451 } 12452 for (p = op_tokens; ; p++) { 12453 const char *o; 12454 12455 if (*p == 0) { 12456 /* strange operator not found */ 12457 goto err; 12458 } 12459 for (o = expr; *p && *o == *p; p++) 12460 o++; 12461 if (! *p) { 12462 /* found */ 12463 expr = o - 1; 12464 break; 12465 } 12466 /* skip tail uncompared token */ 12467 while (*p) 12468 p++; 12469 /* skip zero delim */ 12470 p++; 12471 } 12472 op = p[1]; 12473 12474 /* post grammar: a++ reduce to num */ 12475 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 12476 lasttok = TOK_NUM; 12477 12478 /* Plus and minus are binary (not unary) _only_ if the last 12479 * token was as number, or a right paren (which pretends to be 12480 * a number, since it evaluates to one). Think about it. 12481 * It makes sense. */ 12482 if (lasttok != TOK_NUM) { 12483 switch (op) { 12484 case TOK_ADD: 12485 op = TOK_UPLUS; 12486 break; 12487 case TOK_SUB: 12488 op = TOK_UMINUS; 12489 break; 12490 case TOK_POST_INC: 12491 op = TOK_PRE_INC; 12492 break; 12493 case TOK_POST_DEC: 12494 op = TOK_PRE_DEC; 12495 break; 12496 } 12497 } 12498 /* We don't want a unary operator to cause recursive descent on the 12499 * stack, because there can be many in a row and it could cause an 12500 * operator to be evaluated before its argument is pushed onto the 12501 * integer stack. */ 12502 /* But for binary operators, "apply" everything on the operator 12503 * stack until we find an operator with a lesser priority than the 12504 * one we have just extracted. */ 12505 /* Left paren is given the lowest priority so it will never be 12506 * "applied" in this way. 12507 * if associativity is right and priority eq, applied also skip 12508 */ 12509 prec = PREC(op); 12510 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { 12511 /* not left paren or unary */ 12512 if (lasttok != TOK_NUM) { 12513 /* binary op must be preceded by a num */ 12514 goto err; 12515 } 12516 while (stackptr != stack) { 12517 if (op == TOK_RPAREN) { 12518 /* The algorithm employed here is simple: while we don't 12519 * hit an open paren nor the bottom of the stack, pop 12520 * tokens and apply them */ 12521 if (stackptr[-1] == TOK_LPAREN) { 12522 --stackptr; 12523 /* Any operator directly after a */ 12524 lasttok = TOK_NUM; 12525 /* close paren should consider itself binary */ 12526 goto prologue; 12527 } 12528 } else { 12529 operator prev_prec = PREC(stackptr[-1]); 12530 12531 convert_prec_is_assing(prec); 12532 convert_prec_is_assing(prev_prec); 12533 if (prev_prec < prec) 12534 break; 12535 /* check right assoc */ 12536 if (prev_prec == prec && is_right_associativity(prec)) 12537 break; 12538 } 12539 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 12540 if (errcode) goto ret; 12541 } 12542 if (op == TOK_RPAREN) { 12543 goto err; 12544 } 12545 } 12546 12547 /* Push this operator to the stack and remember it. */ 12548 *stackptr++ = lasttok = op; 12549 prologue: 12550 ++expr; 12551 } /* while */ 12552 } 12553 #endif /* ASH_MATH_SUPPORT */ 12554 12794 static int FAST_FUNC 12795 ulimitcmd(int argc UNUSED_PARAM, char **argv) 12796 { 12797 return shell_builtin_ulimit(argv); 12798 } 12555 12799 12556 12800 /* ============ main() and helpers */ … … 12559 12803 * Called to exit the shell. 12560 12804 */ 12561 static void exitshell(void) ATTRIBUTE_NORETURN;12805 static void exitshell(void) NORETURN; 12562 12806 static void 12563 12807 exitshell(void) … … 12570 12814 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 12571 12815 if (setjmp(loc.loc)) { 12572 if (exception == EXEXIT)12816 if (exception_type == EXEXIT) 12573 12817 /* dash bug: it just does _exit(exitstatus) here 12574 12818 * but we have to do setjobctl(0) first! … … 12583 12827 trap[0] = NULL; 12584 12828 evalstring(p, 0); 12829 free(p); 12585 12830 } 12586 12831 flush_stdout_stderr(); … … 12595 12840 { 12596 12841 /* from input.c: */ 12597 basepf.nextc = basepf.buf = basebuf; 12842 /* we will never free this */ 12843 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 12598 12844 12599 12845 /* from trap.c: */ 12600 12846 signal(SIGCHLD, SIG_DFL); 12847 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 12848 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" 12849 */ 12850 signal(SIGHUP, SIG_DFL); 12601 12851 12602 12852 /* from var.c: */ 12603 12853 { 12604 12854 char **envp; 12605 char ppid[sizeof(int)*3 + 1];12606 12855 const char *p; 12607 12856 struct stat st1, st2; … … 12614 12863 } 12615 12864 12616 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); 12617 setvar("PPID", ppid, 0); 12865 setvar("PPID", utoa(getppid()), 0); 12618 12866 12619 12867 p = lookupvar("PWD"); … … 12630 12878 */ 12631 12879 static void 12632 procargs( int argc,char **argv)12880 procargs(char **argv) 12633 12881 { 12634 12882 int i; … … 12638 12886 xargv = argv; 12639 12887 arg0 = xargv[0]; 12640 if (argc > 0)12888 /* if (xargv[0]) - mmm, this is always true! */ 12641 12889 xargv++; 12642 12890 for (i = 0; i < NOPTS; i++) 12643 12891 optlist[i] = 2; 12644 12892 argptr = xargv; 12645 options(1); 12893 if (options(1)) { 12894 /* it already printed err message */ 12895 raise_exception(EXERROR); 12896 } 12646 12897 xargv = argptr; 12647 12898 xminusc = minusc; … … 12678 12929 shellparam.optoff = -1; 12679 12930 #endif 12680 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */12931 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */ 12681 12932 while (*xargv) { 12682 12933 shellparam.nparam++; … … 12713 12964 loopnest = 0; 12714 12965 /* from input.c: */ 12715 parselleft = parsenleft = 0; /* clear input buffer */ 12966 g_parsefile->left_in_buffer = 0; 12967 g_parsefile->left_in_line = 0; /* clear input buffer */ 12716 12968 popallfiles(); 12717 12969 /* from parser.c: */ … … 12719 12971 checkkwd = 0; 12720 12972 /* from redir.c: */ 12721 clearredir( 0);12973 clearredir(/*drop:*/ 0); 12722 12974 } 12723 12975 … … 12734 12986 * is used to figure out how far we had gotten. 12735 12987 */ 12736 int ash_main(int argc, char **argv) ;12737 int ash_main(int argc , char **argv)12738 { 12739 c har *shinit;12740 volatile int state;12988 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 12989 int ash_main(int argc UNUSED_PARAM, char **argv) 12990 { 12991 const char *shinit; 12992 volatile smallint state; 12741 12993 struct jmploc jmploc; 12742 12994 struct stackmark smark; 12743 12995 12996 /* Initialize global data */ 12997 INIT_G_misc(); 12998 INIT_G_memstack(); 12999 INIT_G_var(); 13000 #if ENABLE_ASH_ALIAS 13001 INIT_G_alias(); 13002 #endif 13003 INIT_G_cmdtable(); 13004 12744 13005 #if PROFILE 12745 13006 monitor(4, etext, profile_buf, sizeof(profile_buf), 50); … … 12751 13012 state = 0; 12752 13013 if (setjmp(jmploc.loc)) { 12753 int e;12754 int s;13014 smallint e; 13015 smallint s; 12755 13016 12756 13017 reset(); 12757 13018 12758 e = exception ;13019 e = exception_type; 12759 13020 if (e == EXERROR) 12760 13021 exitstatus = 2; 12761 13022 s = state; 12762 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 13023 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { 12763 13024 exitshell(); 12764 13025 } 12765 13026 if (e == EXINT) { 12766 13027 outcslow('\n', stderr); 12767 13028 } 13029 12768 13030 popstackmark(&smark); 12769 13031 FORCE_INT_ON; /* enable interrupts */ … … 12779 13041 #if DEBUG 12780 13042 opentrace(); 12781 trace_puts("Shell args: ");13043 TRACE(("Shell args: ")); 12782 13044 trace_puts_args(argv); 12783 13045 #endif 12784 13046 rootpid = getpid(); 12785 13047 12786 #if ENABLE_ASH_RANDOM_SUPPORT12787 rseed = rootpid + time(NULL);12788 #endif12789 13048 init(); 12790 13049 setstackmark(&smark); 12791 procargs(argc, argv); 13050 procargs(argv); 13051 12792 13052 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 12793 13053 if (iflag) { … … 12804 13064 } 12805 13065 #endif 12806 if ( argv[0] &&argv[0][0] == '-')13066 if (/* argv[0] && */ argv[0][0] == '-') 12807 13067 isloginsh = 1; 12808 13068 if (isloginsh) { … … 12828 13088 state3: 12829 13089 state = 4; 12830 if (minusc) 13090 if (minusc) { 13091 /* evalstring pushes parsefile stack. 13092 * Ensure we don't falsely claim that 0 (stdin) 13093 * is one of stacked source fds. 13094 * Testcase: ash -c 'exec 1>&0' must not complain. */ 13095 // if (!sflag) g_parsefile->pf_fd = -1; 13096 // ^^ not necessary since now we special-case fd 0 13097 // in is_hidden_fd() to not be considered "hidden fd" 12831 13098 evalstring(minusc, 0); 13099 } 12832 13100 12833 13101 if (sflag || minusc == NULL) { 12834 #if ENABLE_FEATURE_EDITING_SAVEHISTORY12835 if ( iflag) {13102 #if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 13103 if (iflag) { 12836 13104 const char *hp = lookupvar("HISTFILE"); 12837 12838 if (hp != NULL) 13105 if (hp) 12839 13106 line_input_state->hist_file = hp; 12840 13107 } … … 12852 13119 } 12853 13120 #endif 13121 TRACE(("End of main reached\n")); 12854 13122 exitshell(); 12855 13123 /* NOTREACHED */ 12856 13124 } 12857 12858 #if DEBUG12859 const char *applet_name = "debug stuff usage";12860 int main(int argc, char **argv)12861 {12862 return ash_main(argc, argv);12863 }12864 #endif12865 13125 12866 13126 -
branches/2.2.9/mindi-busybox/shell/ash_test/ash-arith/arith.right
r1765 r2725 56 56 20 20 57 57 30 30 58 ./arith.tests: line 117: syntax error: 1 ? 20 : x+=258 ./arith.tests: line 117: arithmetic syntax error 59 59 6 6 60 60 6,5,3 6,5,3 … … 62 62 255 255 63 63 40 40 64 ./arith.tests: line 163: syntax error: 7 = 4364 ./arith.tests: line 163: arithmetic syntax error 65 65 ./arith.tests: line 165: divide by zero 66 ./arith.tests: let: line 166: syntax error: jv += $iv67 ./arith.tests: line 167: syntax error: jv += $iv68 ./arith.tests: let: line 168: syntax error: rv = 7 + (43 * 666 ./arith.tests: let: line 166: arithmetic syntax error 67 ./arith.tests: line 167: arithmetic syntax error 68 ./arith.tests: let: line 168: arithmetic syntax error 69 69 abc 70 70 def 71 71 ghi 72 ./arith.tests: line 191: syntax error: ( 4 + A ) + 472 ./arith.tests: line 191: arithmetic syntax error 73 73 16 16 74 ./arith.tests: line 196: syntax error: 4 ? : 3 + 575 ./arith.tests: line 197: syntax error: 1 ? 2076 ./arith.tests: line 198: syntax error: 4 ? 20 :74 ./arith.tests: line 196: arithmetic syntax error 75 ./arith.tests: line 197: malformed ?: operator 76 ./arith.tests: line 198: arithmetic syntax error 77 77 9 9 78 ./arith.tests: line 205: syntax error: 0 && B=4279 ./arith.tests: line 208: syntax error: 1 || B=8878 ./arith.tests: line 205: arithmetic syntax error 79 ./arith.tests: line 208: arithmetic syntax error 80 80 9 9 81 81 9 9 … … 98 98 4 4 99 99 4 4 100 ./arith.tests: line 257: syntax error: 7--101 ./arith.tests: line 259: syntax error: --x=7102 ./arith.tests: line 260: syntax error: ++x=7103 ./arith.tests: line 262: syntax error: x++=7104 ./arith.tests: line 263: syntax error: x--=7100 ./arith.tests: line 257: arithmetic syntax error 101 ./arith.tests: line 259: arithmetic syntax error 102 ./arith.tests: line 260: arithmetic syntax error 103 ./arith.tests: line 262: arithmetic syntax error 104 ./arith.tests: line 263: arithmetic syntax error 105 105 4 4 106 106 7 7 107 107 -7 -7 108 ./arith1.sub: line 2: syntax error: 4--109 ./arith1.sub: line 3: syntax error: 4++110 ./arith1.sub: line 4: syntax error: 4 --111 ./arith1.sub: line 5: syntax error: 4 ++108 ./arith1.sub: line 2: arithmetic syntax error 109 ./arith1.sub: line 3: arithmetic syntax error 110 ./arith1.sub: line 4: arithmetic syntax error 111 ./arith1.sub: line 5: arithmetic syntax error 112 112 6 6 113 113 3 3 … … 120 120 -2 -2 121 121 1 1 122 ./arith1.sub: line 37: syntax error: +++7123 ./arith2.sub: line 2: syntax error: --7124 ./arith2.sub: line 3: syntax error: ++7125 ./arith2.sub: line 4: syntax error: -- 7126 ./arith2.sub: line 5: syntax error: ++ 7122 ./arith1.sub: line 37: arithmetic syntax error 123 ./arith2.sub: line 2: arithmetic syntax error 124 ./arith2.sub: line 3: arithmetic syntax error 125 ./arith2.sub: line 4: arithmetic syntax error 126 ./arith2.sub: line 5: arithmetic syntax error 127 127 5 5 128 128 1 1 129 129 4 4 130 130 0 0 131 ./arith2.sub: line 42: syntax error: -- - 7132 ./arith2.sub: line 47: syntax error: ++ + 7131 ./arith2.sub: line 42: arithmetic syntax error 132 ./arith2.sub: line 47: arithmetic syntax error 133 133 8 12 134 ./arith.tests: line 290: syntax error: a b134 ./arith.tests: line 290: arithmetic syntax error 135 135 42 136 136 42 -
branches/2.2.9/mindi-busybox/shell/ash_test/printenv.c
r1765 r2725 46 46 for (envp = environ; *envp; envp++) 47 47 puts (*envp); 48 exit (0);48 exit(EXIT_SUCCESS); 49 49 } 50 50 … … 60 60 { 61 61 puts (eval + 1); 62 exit (0);62 exit(EXIT_SUCCESS); 63 63 } 64 64 } 65 65 } 66 exit (1);66 exit(EXIT_FAILURE); 67 67 } -
branches/2.2.9/mindi-busybox/shell/ash_test/recho.c
r1765 r2725 30 30 void strprint(); 31 31 32 int 33 main(argc, argv) 34 int argc; 35 char **argv; 32 int main(int argc, char **argv) 36 33 { 37 register inti;34 int i; 38 35 39 36 for (i = 1; i < argc; i++) { … … 42 39 printf(">\n"); 43 40 } 44 exit( 0);41 exit(EXIT_SUCCESS); 45 42 } 46 43 47 void 48 strprint(str) 49 char *str; 44 void strprint(char *str) 50 45 { 51 registerunsigned char *s;46 unsigned char *s; 52 47 53 48 for (s = (unsigned char *)str; s && *s; s++) { -
branches/2.2.9/mindi-busybox/shell/ash_test/run-all
r1765 r2725 1 1 #!/bin/sh 2 2 3 test -x ash || { echo "No ./ash?!"; exit; } 3 TOPDIR=$PWD 4 5 test -x ash || { 6 echo "No ./ash - creating a link to ../../busybox" 7 ln -s ../../busybox ash 8 } 4 9 test -x printenv || gcc -O2 -o printenv printenv.c || exit $? 5 10 test -x recho || gcc -O2 -o recho recho.c || exit $? … … 15 20 { 16 21 test -d "$1" || return 0 22 # echo do_test "$1" 23 # $1 but with / replaced by # so that it can be used as filename part 24 noslash=`echo "$1" | sed 's:/:#:g'` 17 25 ( 18 26 cd "$1" || { echo "cannot cd $1!"; exit 1; } … … 24 32 #*) echo $x ; sh $x ;; 25 33 *) 26 sh "$x" >" ../$1-$x.fail" 2>&1 && \27 { echo "$1/$x: ok"; rm " ../$1-$x.fail"; } || echo "$1/$x: fail";34 sh "$x" >"$TOPDIR/$noslash-$x.fail" 2>&1 && \ 35 { echo "$1/$x: ok"; rm "$TOPDIR/$noslash-$x.fail"; } || echo "$1/$x: fail"; 28 36 ;; 29 37 esac … … 37 45 { 38 46 "$THIS_SH" "./$x" >"$name.xx" 2>&1 39 diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" 47 diff -u "$name.xx" "$name.right" >"$TOPDIR/$noslash-$x.fail" \ 48 && rm -f "$name.xx" "$TOPDIR/$noslash-$x.fail" 40 49 } && echo "$1/$x: ok" || echo "$1/$x: fail" 41 50 done … … 49 58 # All sub directories 50 59 modules=`ls -d ash-*` 60 # If you want to test ash against hush and msh testsuites 61 # (have to copy hush_test and msh_test dirs to current dir first): 62 #modules=`ls -d ash-* hush_test/hush-* msh_test/msh-*` 51 63 52 64 for module in $modules; do -
branches/2.2.9/mindi-busybox/shell/ash_test/zecho.c
r1765 r2725 22 22 #include <stdlib.h> 23 23 24 int 25 main(argc, argv) 26 int argc; 27 char **argv; 24 int main(int argc, char **argv) 28 25 { 29 26 argv++; … … 36 33 37 34 putchar('\n'); 38 exit( 0);35 exit(EXIT_SUCCESS); 39 36 } -
branches/2.2.9/mindi-busybox/shell/cttyhack.c
r1765 r2725 1 /* This code is adapted from busybox project 1 /* vi: set sw=4 ts=4: */ 2 /* 3 * Copyright (c) 2007 Denys Vlasenko <vda.linux@googlemail.com> 2 4 * 3 * Licensed under GPLv2 5 * Licensed under GPLv2, see file LICENSE in this source tree. 4 6 */ 5 7 #include "libbb.h" 6 8 9 //applet:IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_DROP)) 10 11 //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o 12 13 //config:config CTTYHACK 14 //config: bool "cttyhack" 15 //config: default y 16 //config: help 17 //config: One common problem reported on the mailing list is "can't access tty; 18 //config: job control turned off" error message which typically appears when 19 //config: one tries to use shell with stdin/stdout opened to /dev/console. 20 //config: This device is special - it cannot be a controlling tty. 21 //config: 22 //config: Proper solution is to use correct device instead of /dev/console. 23 //config: 24 //config: cttyhack provides "quick and dirty" solution to this problem. 25 //config: It analyzes stdin with various ioctls, trying to determine whether 26 //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). 27 //config: If it detects one, it closes stdin/out/err and reopens that device. 28 //config: Then it executes given program. Opening the device will make 29 //config: that device a controlling tty. This may require cttyhack 30 //config: to be a session leader. 31 //config: 32 //config: Example for /etc/inittab (for busybox init): 33 //config: 34 //config: ::respawn:/bin/cttyhack /bin/sh 35 //config: 36 //config: Starting an interactive shell from boot shell script: 37 //config: 38 //config: setsid cttyhack sh 39 //config: 40 //config: Giving controlling tty to shell running with PID 1: 41 //config: 42 //config: # exec cttyhack sh 43 //config: 44 //config: Without cttyhack, you need to know exact tty name, 45 //config: and do something like this: 46 //config: 47 //config: # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1' 48 //config: 49 50 //usage:#define cttyhack_trivial_usage 51 //usage: "PROG ARGS" 52 //usage:#define cttyhack_full_usage "\n\n" 53 //usage: "Give PROG a controlling tty if possible." 54 //usage: "\nExample for /etc/inittab (for busybox init):" 55 //usage: "\n ::respawn:/bin/cttyhack /bin/sh" 56 //usage: "\nGiving controlling tty to shell running with PID 1:" 57 //usage: "\n $ exec cttyhack sh" 58 //usage: "\nStarting interactive shell from boot shell script:" 59 //usage: "\n setsid cttyhack sh" 60 61 #if !defined(__linux__) && !defined(TIOCGSERIAL) && !ENABLE_WERROR 62 # warning cttyhack will not be able to detect a controlling tty on this system 63 #endif 64 7 65 /* From <linux/vt.h> */ 8 66 struct vt_stat { 9 unsigned short v_active; 10 unsigned short v_signal; 11 unsigned short v_state; 67 unsigned short v_active; /* active vt */ 68 unsigned short v_signal; /* signal to send */ 69 unsigned short v_state; /* vt bitmask */ 12 70 }; 13 enum { VT_GETSTATE = 0x5603 }; 71 enum { VT_GETSTATE = 0x5603 }; /* get global vt state info */ 14 72 15 73 /* From <linux/serial.h> */ … … 27 85 char reserved_char[1]; 28 86 int hub6; 29 unsigned short closing_wait; /* time to wait before closing */30 unsigned short closing_wait2; /* no longer used... */87 unsigned short closing_wait; /* time to wait before closing */ 88 unsigned short closing_wait2; /* no longer used... */ 31 89 unsigned char *iomem_base; 32 90 unsigned short iomem_reg_shift; … … 36 94 }; 37 95 38 int cttyhack_main(int argc, char **argv) ATTRIBUTE_NORETURN;39 int cttyhack_main(int argc , char **argv)96 int cttyhack_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 97 int cttyhack_main(int argc UNUSED_PARAM, char **argv) 40 98 { 41 99 int fd; … … 52 110 53 111 strcpy(console, "/dev/tty"); 54 if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { 55 /* this is a serial console */ 56 sprintf(console + 8, "S%d", u.sr.line); 57 } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { 58 /* this is linux virtual tty */ 59 sprintf(console + 8, "S%d" + 1, u.vt.v_active); 112 fd = open(console, O_RDWR); 113 if (fd >= 0) { 114 /* We already have ctty, nothing to do */ 115 close(fd); 116 } else { 117 /* We don't have ctty (or don't have "/dev/tty" node...) */ 118 if (0) {} 119 #ifdef TIOCGSERIAL 120 else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { 121 /* this is a serial console */ 122 sprintf(console + 8, "S%d", u.sr.line); 123 } 124 #endif 125 #ifdef __linux__ 126 else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { 127 /* this is linux virtual tty */ 128 sprintf(console + 8, "S%d" + 1, u.vt.v_active); 129 } 130 #endif 131 if (console[8]) { 132 fd = xopen(console, O_RDWR); 133 //bb_error_msg("switching to '%s'", console); 134 dup2(fd, 0); 135 dup2(fd, 1); 136 dup2(fd, 2); 137 while (fd > 2) 138 close(fd--); 139 /* Some other session may have it as ctty, 140 * steal it from them: 141 */ 142 ioctl(0, TIOCSCTTY, 1); 143 } 60 144 } 61 145 62 if (console[8]) { 63 fd = xopen(console, O_RDWR); 64 //bb_error_msg("switching to '%s'", console); 65 dup2(fd, 0); 66 dup2(fd, 1); 67 dup2(fd, 2); 68 while (fd > 2) close(fd--); 69 } 70 71 execvp(argv[0], argv); 72 bb_perror_msg_and_die("cannot exec '%s'", argv[0]); 146 BB_EXECVP_or_die(argv); 73 147 } -
branches/2.2.9/mindi-busybox/shell/hush.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * sh.c -- a prototype Bourne shell grammar parser4 * 5 * 6 * 3 * A prototype Bourne shell grammar parser. 4 * Intended to follow the original Thompson and Ritchie 5 * "small and simple is beautiful" philosophy, which 6 * incidentally is a good match to today's BusyBox. 7 7 * 8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org> 8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org> 9 * Copyright (C) 2008,2009 Denys Vlasenko <vda.linux@googlemail.com> 10 * 11 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 12 * 10 13 * Credits: … … 21 24 * 22 25 * Other credits: 23 * b_addchr() derived from similar w_addchar function in glibc-2.224 * setup_redirect(), redirect_opt_num(), and big chunks of main()25 * and many builtins derived from contributions by Erik Andersen 26 * miscellaneous bugfixes from Matt Kraai26 * o_addchr derived from similar w_addchar function in glibc-2.2. 27 * parse_redirect, redirect_opt_num, and big chunks of main 28 * and many builtins derived from contributions by Erik Andersen. 29 * Miscellaneous bugfixes from Matt Kraai. 27 30 * 28 31 * There are two big (and related) architecture differences between … … 37 40 * across continuation lines. 38 41 * 39 * Bash grammar not implemented: (how many of these were in original sh?) 40 * $_ 41 * ! negation operator for pipes 42 * &> and >& redirection of stdout+stderr 43 * Brace Expansion 44 * Tilde Expansion 45 * fancy forms of Parameter Expansion 42 * TODOs: 43 * grep for "TODO" and fix (some of them are easy) 44 * special variables (done: PWD, PPID, RANDOM) 45 * tilde expansion 46 46 * aliases 47 * Arithmetic Expansion48 * <(list) and >(list) Process Substitution49 * reserved words: case, esac, select, function50 * Here Documents ( << word )51 * Functions52 * Major bugs:53 * job handling woefully incomplete and buggy (improved --vda)54 * reserved word execution woefully incomplete and buggy55 * to-do:56 * port selected bugfixes from post-0.49 busybox lash - done?57 * finish implementing reserved words: for, while, until, do, done58 * change { and } from special chars to reserved words59 * builtins: break, continue, eval, return, set, trap, ulimit60 * test magic exec61 * handle children going into background62 * clean up recognition of null pipes63 * check setting of global_argc and global_argv64 * control-C handling, probably with longjmp65 47 * follow IFS rules more precisely, including update semantics 66 * figure out what to do with backslash-newline 67 * explain why we use signal instead of sigaction 68 * propagate syntax errors, die on resource errors? 69 * continuation lines, both explicit and implicit - done? 70 * memory leak finding and plugging - done? 71 * more testing, especially quoting rules and redirection 72 * document how quoting rules not precisely followed for variable assignments 73 * maybe change charmap[] to use 2-bit entries 74 * (eventually) remove all the printf's 48 * builtins mandated by standards we don't support: 49 * [un]alias, command, fc, getopts, newgrp, readonly, times 50 * make complex ${var%...} constructs support optional 51 * make here documents optional 75 52 * 76 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 53 * Bash compat TODO: 54 * redirection of stdout+stderr: &> and >& 55 * reserved words: function select 56 * advanced test: [[ ]] 57 * process substitution: <(list) and >(list) 58 * =~: regex operator 59 * let EXPR [EXPR...] 60 * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION) 61 * If the last arg evaluates to 0, let returns 1; 0 otherwise. 62 * NB: let `echo 'a=a + 1'` - error (IOW: multi-word expansion is used) 63 * ((EXPR)) 64 * The EXPR is evaluated according to ARITHMETIC EVALUATION. 65 * This is exactly equivalent to let "EXPR". 66 * $[EXPR]: synonym for $((EXPR)) 67 * 68 * Won't do: 69 * In bash, export builtin is special, its arguments are assignments 70 * and therefore expansion of them should be "one-word" expansion: 71 * $ export i=`echo 'a b'` # export has one arg: "i=a b" 72 * compare with: 73 * $ ls i=`echo 'a b'` # ls has two args: "i=a" and "b" 74 * ls: cannot access i=a: No such file or directory 75 * ls: cannot access b: No such file or directory 76 * Note1: same applies to local builtin. 77 * Note2: bash 3.2.33(1) does this only if export word itself 78 * is not quoted: 79 * $ export i=`echo 'aaa bbb'`; echo "$i" 80 * aaa bbb 81 * $ "export" i=`echo 'aaa bbb'`; echo "$i" 82 * aaa 77 83 */ 78 79 80 #include <glob.h> /* glob, of course */ 81 #include <getopt.h> /* should be pretty obvious */ 84 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 85 #include <malloc.h> /* for malloc_trim */ 86 #include <glob.h> 82 87 /* #include <dmalloc.h> */ 83 84 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */ 85 86 #include "busybox.h" /* for struct bb_applet */ 87 88 #if ENABLE_HUSH_CASE 89 # include <fnmatch.h> 90 #endif 91 92 #include "shell_common.h" 93 #include "math.h" 94 #include "match.h" 95 #if ENABLE_HUSH_RANDOM_SUPPORT 96 # include "random.h" 97 #else 98 # define CLEAR_RANDOM_T(rnd) ((void)0) 99 #endif 100 #ifndef PIPE_BUF 101 # define PIPE_BUF 4096 /* amount of buffering in a pipe */ 102 #endif 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_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) 107 //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) 108 109 //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o 110 //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o 111 112 //config:config HUSH 113 //config: bool "hush" 114 //config: default y 115 //config: help 116 //config: hush is a small shell (25k). It handles the normal flow control 117 //config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops, 118 //config: case/esac. Redirections, here documents, $((arithmetic)) 119 //config: and functions are supported. 120 //config: 121 //config: It will compile and work on no-mmu systems. 122 //config: 123 //config: It does not handle select, aliases, tilde expansion, 124 //config: &>file and >&file redirection of stdout+stderr. 125 //config: 126 //config:config HUSH_BASH_COMPAT 127 //config: bool "bash-compatible extensions" 128 //config: default y 129 //config: depends on HUSH 130 //config: help 131 //config: Enable bash-compatible extensions. 132 //config: 133 //config:config HUSH_BRACE_EXPANSION 134 //config: bool "Brace expansion" 135 //config: default y 136 //config: depends on HUSH_BASH_COMPAT 137 //config: help 138 //config: Enable {abc,def} extension. 139 //config: 140 //config:config HUSH_HELP 141 //config: bool "help builtin" 142 //config: default y 143 //config: depends on HUSH 144 //config: help 145 //config: Enable help builtin in hush. Code size + ~1 kbyte. 146 //config: 147 //config:config HUSH_INTERACTIVE 148 //config: bool "Interactive mode" 149 //config: default y 150 //config: depends on HUSH 151 //config: help 152 //config: Enable interactive mode (prompt and command editing). 153 //config: Without this, hush simply reads and executes commands 154 //config: from stdin just like a shell script from a file. 155 //config: No prompt, no PS1/PS2 magic shell variables. 156 //config: 157 //config:config HUSH_SAVEHISTORY 158 //config: bool "Save command history to .hush_history" 159 //config: default y 160 //config: depends on HUSH_INTERACTIVE && FEATURE_EDITING_SAVEHISTORY 161 //config: help 162 //config: Enable history saving in hush. 163 //config: 164 //config:config HUSH_JOB 165 //config: bool "Job control" 166 //config: default y 167 //config: depends on HUSH_INTERACTIVE 168 //config: help 169 //config: Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current 170 //config: command (not entire shell), fg/bg builtins work. Without this option, 171 //config: "cmd &" still works by simply spawning a process and immediately 172 //config: prompting for next command (or executing next command in a script), 173 //config: but no separate process group is formed. 174 //config: 175 //config:config HUSH_TICK 176 //config: bool "Process substitution" 177 //config: default y 178 //config: depends on HUSH 179 //config: help 180 //config: Enable process substitution `command` and $(command) in hush. 181 //config: 182 //config:config HUSH_IF 183 //config: bool "Support if/then/elif/else/fi" 184 //config: default y 185 //config: depends on HUSH 186 //config: help 187 //config: Enable if/then/elif/else/fi in hush. 188 //config: 189 //config:config HUSH_LOOPS 190 //config: bool "Support for, while and until loops" 191 //config: default y 192 //config: depends on HUSH 193 //config: help 194 //config: Enable for, while and until loops in hush. 195 //config: 196 //config:config HUSH_CASE 197 //config: bool "Support case ... esac statement" 198 //config: default y 199 //config: depends on HUSH 200 //config: help 201 //config: Enable case ... esac statement in hush. +400 bytes. 202 //config: 203 //config:config HUSH_FUNCTIONS 204 //config: bool "Support funcname() { commands; } syntax" 205 //config: default y 206 //config: depends on HUSH 207 //config: help 208 //config: Enable support for shell functions in hush. +800 bytes. 209 //config: 210 //config:config HUSH_LOCAL 211 //config: bool "Support local builtin" 212 //config: default y 213 //config: depends on HUSH_FUNCTIONS 214 //config: help 215 //config: Enable support for local variables in functions. 216 //config: 217 //config:config HUSH_RANDOM_SUPPORT 218 //config: bool "Pseudorandom generator and $RANDOM variable" 219 //config: default y 220 //config: depends on HUSH 221 //config: help 222 //config: Enable pseudorandom generator and dynamic variable "$RANDOM". 223 //config: Each read of "$RANDOM" will generate a new pseudorandom value. 224 //config: 225 //config:config HUSH_EXPORT_N 226 //config: bool "Support 'export -n' option" 227 //config: default y 228 //config: depends on HUSH 229 //config: help 230 //config: export -n unexports variables. It is a bash extension. 231 //config: 232 //config:config HUSH_MODE_X 233 //config: bool "Support 'hush -x' option and 'set -x' command" 234 //config: default y 235 //config: depends on HUSH 236 //config: help 237 //config: This instructs hush to print commands before execution. 238 //config: Adds ~300 bytes. 239 //config: 240 //config:config MSH 241 //config: bool "msh (deprecated: aliased to hush)" 242 //config: default n 243 //config: select HUSH 244 //config: help 245 //config: msh is deprecated and will be removed, please migrate to hush. 246 //config: 247 248 //usage:#define hush_trivial_usage NOUSAGE_STR 249 //usage:#define hush_full_usage "" 250 //usage:#define msh_trivial_usage NOUSAGE_STR 251 //usage:#define msh_full_usage "" 252 //usage:#define sh_trivial_usage NOUSAGE_STR 253 //usage:#define sh_full_usage "" 254 //usage:#define bash_trivial_usage NOUSAGE_STR 255 //usage:#define bash_full_usage "" 256 257 258 /* Build knobs */ 259 #define LEAK_HUNTING 0 260 #define BUILD_AS_NOMMU 0 261 /* Enable/disable sanity checks. Ok to enable in production, 262 * only adds a bit of bloat. Set to >1 to get non-production level verbosity. 263 * Keeping 1 for now even in released versions. 264 */ 265 #define HUSH_DEBUG 1 266 /* Slightly bigger (+200 bytes), but faster hush. 267 * So far it only enables a trick with counting SIGCHLDs and forks, 268 * which allows us to do fewer waitpid's. 269 * (we can detect a case where neither forks were done nor SIGCHLDs happened 270 * and therefore waitpid will return the same result as last time) 271 */ 272 #define ENABLE_HUSH_FAST 0 273 /* TODO: implement simplified code for users which do not need ${var%...} ops 274 * So far ${var%...} ops are always enabled: 275 */ 276 #define ENABLE_HUSH_DOLLAR_OPS 1 277 278 279 #if BUILD_AS_NOMMU 280 # undef BB_MMU 281 # undef USE_FOR_NOMMU 282 # undef USE_FOR_MMU 283 # define BB_MMU 0 284 # define USE_FOR_NOMMU(...) __VA_ARGS__ 285 # define USE_FOR_MMU(...) 286 #endif 287 288 #include "NUM_APPLETS.h" 289 #if NUM_APPLETS == 1 290 /* STANDALONE does not make sense, and won't compile */ 291 # undef CONFIG_FEATURE_SH_STANDALONE 292 # undef ENABLE_FEATURE_SH_STANDALONE 293 # undef IF_FEATURE_SH_STANDALONE 294 # undef IF_NOT_FEATURE_SH_STANDALONE 295 # define ENABLE_FEATURE_SH_STANDALONE 0 296 # define IF_FEATURE_SH_STANDALONE(...) 297 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ 298 #endif 299 300 #if !ENABLE_HUSH_INTERACTIVE 301 # undef ENABLE_FEATURE_EDITING 302 # define ENABLE_FEATURE_EDITING 0 303 # undef ENABLE_FEATURE_EDITING_FANCY_PROMPT 304 # define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 305 #endif 306 307 /* Do we support ANY keywords? */ 308 #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE 309 # define HAS_KEYWORDS 1 310 # define IF_HAS_KEYWORDS(...) __VA_ARGS__ 311 # define IF_HAS_NO_KEYWORDS(...) 312 #else 313 # define HAS_KEYWORDS 0 314 # define IF_HAS_KEYWORDS(...) 315 # define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__ 316 #endif 88 317 89 318 /* If you comment out one of these below, it will be #defined later … … 94 323 #define debug_print_tree(a, b) do {} while (0) 95 324 #define debug_printf_exec(...) do {} while (0) 325 #define debug_printf_env(...) do {} while (0) 96 326 #define debug_printf_jobs(...) do {} while (0) 97 327 #define debug_printf_expand(...) do {} while (0) 328 #define debug_printf_varexp(...) do {} while (0) 329 #define debug_printf_glob(...) do {} while (0) 330 #define debug_printf_list(...) do {} while (0) 331 #define debug_printf_subst(...) do {} while (0) 98 332 #define debug_printf_clean(...) do {} while (0) 99 333 100 #ifndef debug_printf 101 #define debug_printf(...) fprintf(stderr, __VA_ARGS__) 102 #endif 103 104 #ifndef debug_printf_parse 105 #define debug_printf_parse(...) fprintf(stderr, __VA_ARGS__) 106 #endif 107 108 #ifndef debug_printf_exec 109 #define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) 110 #endif 111 112 #ifndef debug_printf_jobs 113 #define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__) 114 #define DEBUG_SHELL_JOBS 1 115 #endif 116 117 #ifndef debug_printf_expand 118 #define debug_printf_expand(...) fprintf(stderr, __VA_ARGS__) 119 #define DEBUG_EXPAND 1 120 #endif 121 122 /* Keep unconditionally on for now */ 123 #define ENABLE_HUSH_DEBUG 1 124 125 #ifndef debug_printf_clean 126 /* broken, of course, but OK for testing */ 127 static const char *indenter(int i) 128 { 129 static const char blanks[] ALIGN1 = 130 " "; 131 return &blanks[sizeof(blanks) - i - 1]; 132 } 133 #define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__) 134 #define DEBUG_CLEAN 1 135 #endif 136 137 138 #if !ENABLE_HUSH_INTERACTIVE 139 #undef ENABLE_FEATURE_EDITING 140 #define ENABLE_FEATURE_EDITING 0 141 #undef ENABLE_FEATURE_EDITING_FANCY_PROMPT 142 #define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 334 #define ERR_PTR ((void*)(long)1) 335 336 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 337 338 #define _SPECIAL_VARS_STR "_*@$!?#" 339 #define SPECIAL_VARS_STR ("_*@$!?#" + 1) 340 #define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3) 341 #if ENABLE_HUSH_BASH_COMPAT 342 /* Support / and // replace ops */ 343 /* Note that // is stored as \ in "encoded" string representation */ 344 # define VAR_ENCODED_SUBST_OPS "\\/%#:-=+?" 345 # define VAR_SUBST_OPS ("\\/%#:-=+?" + 1) 346 # define MINUS_PLUS_EQUAL_QUESTION ("\\/%#:-=+?" + 5) 347 #else 348 # define VAR_ENCODED_SUBST_OPS "%#:-=+?" 349 # define VAR_SUBST_OPS "%#:-=+?" 350 # define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3) 143 351 #endif 144 352 145 353 #define SPECIAL_VAR_SYMBOL 3 146 354 147 #define PARSEFLAG_EXIT_FROM_LOOP 1 148 #define PARSEFLAG_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ 149 #define PARSEFLAG_REPARSING (1 << 2) /* >= 2nd pass */ 150 151 typedef enum { 152 REDIRECT_INPUT = 1, 153 REDIRECT_OVERWRITE = 2, 154 REDIRECT_APPEND = 3, 155 REDIRECT_HEREIS = 4, 156 REDIRECT_IO = 5 157 } redir_type; 158 159 /* The descrip member of this structure is only used to make debugging 160 * output pretty */ 355 struct variable; 356 357 static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER; 358 359 /* This supports saving pointers malloced in vfork child, 360 * to be freed in the parent. 361 */ 362 #if !BB_MMU 363 typedef struct nommu_save_t { 364 char **new_env; 365 struct variable *old_vars; 366 char **argv; 367 char **argv_from_re_execing; 368 } nommu_save_t; 369 #endif 370 371 enum { 372 RES_NONE = 0, 373 #if ENABLE_HUSH_IF 374 RES_IF , 375 RES_THEN , 376 RES_ELIF , 377 RES_ELSE , 378 RES_FI , 379 #endif 380 #if ENABLE_HUSH_LOOPS 381 RES_FOR , 382 RES_WHILE , 383 RES_UNTIL , 384 RES_DO , 385 RES_DONE , 386 #endif 387 #if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE 388 RES_IN , 389 #endif 390 #if ENABLE_HUSH_CASE 391 RES_CASE , 392 /* three pseudo-keywords support contrived "case" syntax: */ 393 RES_CASE_IN, /* "case ... IN", turns into RES_MATCH when IN is observed */ 394 RES_MATCH , /* "word)" */ 395 RES_CASE_BODY, /* "this command is inside CASE" */ 396 RES_ESAC , 397 #endif 398 RES_XXXX , 399 RES_SNTX 400 }; 401 402 typedef struct o_string { 403 char *data; 404 int length; /* position where data is appended */ 405 int maxlen; 406 int o_expflags; 407 /* At least some part of the string was inside '' or "", 408 * possibly empty one: word"", wo''rd etc. */ 409 smallint has_quoted_part; 410 smallint has_empty_slot; 411 smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ 412 } o_string; 413 enum { 414 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ 415 EXP_FLAG_GLOB = 0x2, 416 /* Protect newly added chars against globbing 417 * by prepending \ to *, ?, [, \ */ 418 EXP_FLAG_ESC_GLOB_CHARS = 0x1, 419 }; 420 enum { 421 MAYBE_ASSIGNMENT = 0, 422 DEFINITELY_ASSIGNMENT = 1, 423 NOT_ASSIGNMENT = 2, 424 /* Not an assigment, but next word may be: "if v=xyz cmd;" */ 425 WORD_IS_KEYWORD = 3, 426 }; 427 /* Used for initialization: o_string foo = NULL_O_STRING; */ 428 #define NULL_O_STRING { NULL } 429 430 /* I can almost use ordinary FILE*. Is open_memstream() universally 431 * available? Where is it documented? */ 432 typedef struct in_str { 433 const char *p; 434 /* eof_flag=1: last char in ->p is really an EOF */ 435 char eof_flag; /* meaningless if ->p == NULL */ 436 char peek_buf[2]; 437 #if ENABLE_HUSH_INTERACTIVE 438 smallint promptme; 439 smallint promptmode; /* 0: PS1, 1: PS2 */ 440 #endif 441 FILE *file; 442 int (*get) (struct in_str *) FAST_FUNC; 443 int (*peek) (struct in_str *) FAST_FUNC; 444 } in_str; 445 #define i_getch(input) ((input)->get(input)) 446 #define i_peek(input) ((input)->peek(input)) 447 448 /* The descrip member of this structure is only used to make 449 * debugging output pretty */ 161 450 static const struct { 162 451 int mode; … … 164 453 char descrip[3]; 165 454 } redir_table[] = { 166 { 0, 0, "()" },167 455 { O_RDONLY, 0, "<" }, 168 456 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, 169 457 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, 170 { O_RDONLY, -1, "<<" }, 171 { O_RDWR, 1, "<>" } 458 { O_CREAT|O_RDWR, 1, "<>" }, 459 { O_RDONLY, 0, "<<" }, 460 /* Should not be needed. Bogus default_fd helps in debugging */ 461 /* { O_RDONLY, 77, "<<" }, */ 172 462 }; 173 463 174 typedef enum { 464 struct redir_struct { 465 struct redir_struct *next; 466 char *rd_filename; /* filename */ 467 int rd_fd; /* fd to redirect */ 468 /* fd to redirect to, or -3 if rd_fd is to be closed (n>&-) */ 469 int rd_dup; 470 smallint rd_type; /* (enum redir_type) */ 471 /* note: for heredocs, rd_filename contains heredoc delimiter, 472 * and subsequently heredoc itself; and rd_dup is a bitmask: 473 * bit 0: do we need to trim leading tabs? 474 * bit 1: is heredoc quoted (<<'delim' syntax) ? 475 */ 476 }; 477 typedef enum redir_type { 478 REDIRECT_INPUT = 0, 479 REDIRECT_OVERWRITE = 1, 480 REDIRECT_APPEND = 2, 481 REDIRECT_IO = 3, 482 REDIRECT_HEREDOC = 4, 483 REDIRECT_HEREDOC2 = 5, /* REDIRECT_HEREDOC after heredoc is loaded */ 484 485 REDIRFD_CLOSE = -3, 486 REDIRFD_SYNTAX_ERR = -2, 487 REDIRFD_TO_FILE = -1, 488 /* otherwise, rd_fd is redirected to rd_dup */ 489 490 HEREDOC_SKIPTABS = 1, 491 HEREDOC_QUOTED = 2, 492 } redir_type; 493 494 495 struct command { 496 pid_t pid; /* 0 if exited */ 497 int assignment_cnt; /* how many argv[i] are assignments? */ 498 smallint is_stopped; /* is the command currently running? */ 499 smallint cmd_type; /* CMD_xxx */ 500 #define CMD_NORMAL 0 501 #define CMD_SUBSHELL 1 502 #if ENABLE_HUSH_BASH_COMPAT 503 /* used for "[[ EXPR ]]" */ 504 # define CMD_SINGLEWORD_NOGLOB 2 505 #endif 506 #if ENABLE_HUSH_FUNCTIONS 507 # define CMD_FUNCDEF 3 508 #endif 509 510 smalluint cmd_exitcode; 511 /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */ 512 struct pipe *group; 513 #if !BB_MMU 514 char *group_as_string; 515 #endif 516 #if ENABLE_HUSH_FUNCTIONS 517 struct function *child_func; 518 /* This field is used to prevent a bug here: 519 * while...do f1() {a;}; f1; f1() {b;}; f1; done 520 * When we execute "f1() {a;}" cmd, we create new function and clear 521 * cmd->group, cmd->group_as_string, cmd->argv[0]. 522 * When we execute "f1() {b;}", we notice that f1 exists, 523 * and that its "parent cmd" struct is still "alive", 524 * we put those fields back into cmd->xxx 525 * (struct function has ->parent_cmd ptr to facilitate that). 526 * When we loop back, we can execute "f1() {a;}" again and set f1 correctly. 527 * Without this trick, loop would execute a;b;b;b;... 528 * instead of correct sequence a;b;a;b;... 529 * When command is freed, it severs the link 530 * (sets ->child_func->parent_cmd to NULL). 531 */ 532 #endif 533 char **argv; /* command name and arguments */ 534 /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) 535 * and on execution these are substituted with their values. 536 * Substitution can make _several_ words out of one argv[n]! 537 * Example: argv[0]=='.^C*^C.' here: echo .$*. 538 * References of the form ^C`cmd arg^C are `cmd arg` substitutions. 539 */ 540 struct redir_struct *redirects; /* I/O redirections */ 541 }; 542 /* Is there anything in this command at all? */ 543 #define IS_NULL_CMD(cmd) \ 544 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) 545 546 struct pipe { 547 struct pipe *next; 548 int num_cmds; /* total number of commands in pipe */ 549 int alive_cmds; /* number of commands running (not exited) */ 550 int stopped_cmds; /* number of commands alive, but stopped */ 551 #if ENABLE_HUSH_JOB 552 int jobid; /* job number */ 553 pid_t pgrp; /* process group ID for the job */ 554 char *cmdtext; /* name of job */ 555 #endif 556 struct command *cmds; /* array of commands in pipe */ 557 smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ 558 IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ 559 IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ 560 }; 561 typedef enum pipe_style { 175 562 PIPE_SEQ = 1, 176 563 PIPE_AND = 2, … … 178 565 PIPE_BG = 4, 179 566 } pipe_style; 180 181 /* might eventually control execution */ 182 typedef enum { 183 RES_NONE = 0, 184 #if ENABLE_HUSH_IF 185 RES_IF = 1, 186 RES_THEN = 2, 187 RES_ELIF = 3, 188 RES_ELSE = 4, 189 RES_FI = 5, 190 #endif 191 #if ENABLE_HUSH_LOOPS 192 RES_FOR = 6, 193 RES_WHILE = 7, 194 RES_UNTIL = 8, 195 RES_DO = 9, 196 RES_DONE = 10, 197 RES_IN = 11, 198 #endif 199 RES_XXXX = 12, 200 RES_SNTX = 13 201 } reserved_style; 202 enum { 203 FLAG_END = (1 << RES_NONE ), 204 #if ENABLE_HUSH_IF 205 FLAG_IF = (1 << RES_IF ), 206 FLAG_THEN = (1 << RES_THEN ), 207 FLAG_ELIF = (1 << RES_ELIF ), 208 FLAG_ELSE = (1 << RES_ELSE ), 209 FLAG_FI = (1 << RES_FI ), 210 #endif 211 #if ENABLE_HUSH_LOOPS 212 FLAG_FOR = (1 << RES_FOR ), 213 FLAG_WHILE = (1 << RES_WHILE), 214 FLAG_UNTIL = (1 << RES_UNTIL), 215 FLAG_DO = (1 << RES_DO ), 216 FLAG_DONE = (1 << RES_DONE ), 217 FLAG_IN = (1 << RES_IN ), 218 #endif 219 FLAG_START = (1 << RES_XXXX ), 220 }; 567 /* Is there anything in this pipe at all? */ 568 #define IS_NULL_PIPE(pi) \ 569 ((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE)) 221 570 222 571 /* This holds pointers to the various results of parsing */ 223 struct p _context {224 struct child_prog *child;572 struct parse_context { 573 /* linked list of pipes */ 225 574 struct pipe *list_head; 575 /* last pipe (being constructed right now) */ 226 576 struct pipe *pipe; 577 /* last command in pipe (being constructed right now) */ 578 struct command *command; 579 /* last redirect in command->redirects list */ 227 580 struct redir_struct *pending_redirect; 228 smallint res_w; 229 smallint parse_type; /* bitmask of PARSEFLAG_xxx, defines type of parser : ";$" common or special symbol */ 230 int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ 231 struct p_context *stack; 232 /* How about quoting status? */ 233 }; 234 235 struct redir_struct { 236 struct redir_struct *next; /* pointer to the next redirect in the list */ 237 redir_type type; /* type of redirection */ 238 int fd; /* file descriptor being redirected */ 239 int dup; /* -1, or file descriptor being duplicated */ 240 glob_t word; /* *word.gl_pathv is the filename */ 241 }; 242 243 struct child_prog { 244 pid_t pid; /* 0 if exited */ 245 char **argv; /* program name and arguments */ 246 struct pipe *group; /* if non-NULL, first in group or subshell */ 247 smallint subshell; /* flag, non-zero if group must be forked */ 248 smallint is_stopped; /* is the program currently running? */ 249 struct redir_struct *redirects; /* I/O redirections */ 250 glob_t glob_result; /* result of parameter globbing */ 251 struct pipe *family; /* pointer back to the child's parent pipe */ 252 //sp counting seems to be broken... so commented out, grep for '//sp:' 253 //sp: int sp; /* number of SPECIAL_VAR_SYMBOL */ 254 //seems to be unused, grep for '//pt:' 255 //pt: int parse_type; 256 }; 257 /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) 258 * and on execution these are substituted with their values. 259 * Substitution can make _several_ words out of one argv[n]! 260 * Example: argv[0]=='.^C*^C.' here: echo .$*. 261 */ 262 263 struct pipe { 264 struct pipe *next; 265 int num_progs; /* total number of programs in job */ 266 int running_progs; /* number of programs running (not exited) */ 267 int stopped_progs; /* number of programs alive, but stopped */ 268 #if ENABLE_HUSH_JOB 269 int jobid; /* job number */ 270 pid_t pgrp; /* process group ID for the job */ 271 char *cmdtext; /* name of job */ 272 #endif 273 char *cmdbuf; /* buffer various argv's point into */ 274 struct child_prog *progs; /* array of commands in pipe */ 275 int job_context; /* bitmask defining current context */ 276 smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ 277 smallint res_word; /* needed for if, for, while, until... */ 278 }; 279 280 struct close_me { 281 struct close_me *next; 282 int fd; 581 #if !BB_MMU 582 o_string as_string; 583 #endif 584 #if HAS_KEYWORDS 585 smallint ctx_res_w; 586 smallint ctx_inverted; /* "! cmd | cmd" */ 587 #if ENABLE_HUSH_CASE 588 smallint ctx_dsemicolon; /* ";;" seen */ 589 #endif 590 /* bitmask of FLAG_xxx, for figuring out valid reserved words */ 591 int old_flag; 592 /* group we are enclosed in: 593 * example: "if pipe1; pipe2; then pipe3; fi" 594 * when we see "if" or "then", we malloc and copy current context, 595 * and make ->stack point to it. then we parse pipeN. 596 * when closing "then" / fi" / whatever is found, 597 * we move list_head into ->stack->command->group, 598 * copy ->stack into current context, and delete ->stack. 599 * (parsing of { list } and ( list ) doesn't use this method) 600 */ 601 struct parse_context *stack; 602 #endif 283 603 }; 284 604 … … 292 612 struct variable *next; 293 613 char *varstr; /* points to "name=" portion */ 614 #if ENABLE_HUSH_LOCAL 615 unsigned func_nest_level; 616 #endif 294 617 int max_len; /* if > 0, name is part of initial env; else name is malloced */ 295 618 smallint flg_export; /* putenv should be done on this var */ … … 297 620 }; 298 621 299 typedef struct { 300 char *data; 301 int length; 302 int maxlen; 303 int quote; 304 int nonnull; 305 } o_string; 306 #define NULL_O_STRING {NULL,0,0,0,0} 307 /* used for initialization: o_string foo = NULL_O_STRING; */ 308 309 /* I can almost use ordinary FILE *. Is open_memstream() universally 310 * available? Where is it documented? */ 311 struct in_str { 312 const char *p; 313 /* eof_flag=1: last char in ->p is really an EOF */ 314 char eof_flag; /* meaningless if ->p == NULL */ 315 char peek_buf[2]; 316 #if ENABLE_HUSH_INTERACTIVE 317 smallint promptme; 318 smallint promptmode; /* 0: PS1, 1: PS2 */ 319 #endif 320 FILE *file; 321 int (*get) (struct in_str *); 322 int (*peek) (struct in_str *); 622 enum { 623 BC_BREAK = 1, 624 BC_CONTINUE = 2, 323 625 }; 324 #define b_getch(input) ((input)->get(input)) 325 #define b_peek(input) ((input)->peek(input)) 326 626 627 #if ENABLE_HUSH_FUNCTIONS 628 struct function { 629 struct function *next; 630 char *name; 631 struct command *parent_cmd; 632 struct pipe *body; 633 # if !BB_MMU 634 char *body_as_string; 635 # endif 636 }; 637 #endif 638 639 640 /* set -/+o OPT support. (TODO: make it optional) 641 * bash supports the following opts: 642 * allexport off 643 * braceexpand on 644 * emacs on 645 * errexit off 646 * errtrace off 647 * functrace off 648 * hashall on 649 * histexpand off 650 * history on 651 * ignoreeof off 652 * interactive-comments on 653 * keyword off 654 * monitor on 655 * noclobber off 656 * noexec off 657 * noglob off 658 * nolog off 659 * notify off 660 * nounset off 661 * onecmd off 662 * physical off 663 * pipefail off 664 * posix off 665 * privileged off 666 * verbose off 667 * vi off 668 * xtrace off 669 */ 670 static const char o_opt_strings[] ALIGN1 = "pipefail\0"; 327 671 enum { 328 CHAR_ORDINARY = 0, 329 CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */ 330 CHAR_IFS = 2, /* treated as ordinary if quoted */ 331 CHAR_SPECIAL = 3, /* example: $ */ 672 OPT_O_PIPEFAIL, 673 NUM_OPT_O 332 674 }; 333 675 334 #define HUSH_VER_STR "0.02"335 676 336 677 /* "Globals" within this file */ 337 338 678 /* Sorted roughly by size (smaller offsets == smaller code) */ 339 679 struct globals { 680 /* interactive_fd != 0 means we are an interactive shell. 681 * If we are, then saved_tty_pgrp can also be != 0, meaning 682 * that controlling tty is available. With saved_tty_pgrp == 0, 683 * job control still works, but terminal signals 684 * (^C, ^Z, ^Y, ^\) won't work at all, and background 685 * process groups can only be created with "cmd &". 686 * With saved_tty_pgrp != 0, hush will use tcsetpgrp() 687 * to give tty to the foreground process group, 688 * and will take it back when the group is stopped (^Z) 689 * or killed (^C). 690 */ 340 691 #if ENABLE_HUSH_INTERACTIVE 341 692 /* 'interactive_fd' is a fd# open to ctty, if we have one … … 344 695 const char *PS1; 345 696 const char *PS2; 697 # define G_interactive_fd (G.interactive_fd) 698 #else 699 # define G_interactive_fd 0 346 700 #endif 347 701 #if ENABLE_FEATURE_EDITING 348 702 line_input_t *line_input_state; 349 703 #endif 704 pid_t root_pid; 705 pid_t root_ppid; 706 pid_t last_bg_pid; 707 #if ENABLE_HUSH_RANDOM_SUPPORT 708 random_t random_gen; 709 #endif 350 710 #if ENABLE_HUSH_JOB 351 711 int run_list_level; 352 pid_t saved_task_pgrp;712 int last_jobid; 353 713 pid_t saved_tty_pgrp; 354 int last_jobid;355 714 struct pipe *job_list; 356 struct pipe *toplevel_list; 357 smallint ctrl_z_flag; 358 #endif 359 smallint fake_mode; 360 /* these three support $?, $#, and $1 */ 715 # define G_saved_tty_pgrp (G.saved_tty_pgrp) 716 #else 717 # define G_saved_tty_pgrp 0 718 #endif 719 char o_opt[NUM_OPT_O]; 720 smallint flag_SIGINT; 721 #if ENABLE_HUSH_LOOPS 722 smallint flag_break_continue; 723 #endif 724 #if ENABLE_HUSH_FUNCTIONS 725 /* 0: outside of a function (or sourced file) 726 * -1: inside of a function, ok to use return builtin 727 * 1: return is invoked, skip all till end of func 728 */ 729 smallint flag_return_in_progress; 730 #endif 731 smallint n_mode; 732 #if ENABLE_HUSH_MODE_X 733 smallint x_mode; 734 # define G_x_mode (G.x_mode) 735 #else 736 # define G_x_mode 0 737 #endif 738 smallint exiting; /* used to prevent EXIT trap recursion */ 739 /* These four support $?, $#, and $1 */ 740 smalluint last_exitcode; 741 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 742 smalluint global_args_malloced; 743 smalluint inherited_set_is_saved; 744 /* how many non-NULL argv's we have. NB: $# + 1 */ 745 int global_argc; 361 746 char **global_argv; 362 int global_argc; 363 int last_return_code; 747 #if !BB_MMU 748 char *argv0_for_re_execing; 749 #endif 750 #if ENABLE_HUSH_LOOPS 751 unsigned depth_break_continue; 752 unsigned depth_of_loop; 753 #endif 364 754 const char *ifs; 365 struct close_me *close_me_head;366 755 const char *cwd; 367 unsigned last_bg_pid; 368 struct variable *top_var; /* = &shell_ver (set in main()) */ 369 struct variable shell_ver; 370 #if ENABLE_FEATURE_SH_STANDALONE 371 struct nofork_save_area nofork_save; 372 #endif 756 struct variable *top_var; 757 char **expanded_assignments; 758 #if ENABLE_HUSH_FUNCTIONS 759 struct function *top_func; 760 # if ENABLE_HUSH_LOCAL 761 struct variable **shadowed_vars_pp; 762 unsigned func_nest_level; 763 # endif 764 #endif 765 /* Signal and trap handling */ 766 #if ENABLE_HUSH_FAST 767 unsigned count_SIGCHLD; 768 unsigned handled_SIGCHLD; 769 smallint we_have_children; 770 #endif 771 /* which signals have non-DFL handler (even with no traps set)? */ 772 unsigned non_DFL_mask; 773 char **traps; /* char *traps[NSIG] */ 774 sigset_t blocked_set; 775 sigset_t inherited_set; 776 #if HUSH_DEBUG 777 unsigned long memleak_value; 778 int debug_indent; 779 #endif 780 char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; 781 }; 782 #define G (*ptr_to_globals) 783 /* Not #defining name to G.name - this quickly gets unwieldy 784 * (too many defines). Also, I actually prefer to see when a variable 785 * is global, thus "G." prefix is a useful hint */ 786 #define INIT_G() do { \ 787 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 788 } while (0) 789 790 791 /* Function prototypes for builtins */ 792 static int builtin_cd(char **argv) FAST_FUNC; 793 static int builtin_echo(char **argv) FAST_FUNC; 794 static int builtin_eval(char **argv) FAST_FUNC; 795 static int builtin_exec(char **argv) FAST_FUNC; 796 static int builtin_exit(char **argv) FAST_FUNC; 797 static int builtin_export(char **argv) FAST_FUNC; 373 798 #if ENABLE_HUSH_JOB 374 sigjmp_buf toplevel_jb; 375 #endif 376 unsigned char charmap[256]; 377 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 378 }; 379 380 #define G (*ptr_to_globals) 381 382 #if !ENABLE_HUSH_INTERACTIVE 383 enum { interactive_fd = 0 }; 384 #endif 385 #if !ENABLE_HUSH_JOB 386 enum { run_list_level = 0 }; 387 #endif 388 389 #if ENABLE_HUSH_INTERACTIVE 390 #define interactive_fd (G.interactive_fd ) 391 #define PS1 (G.PS1 ) 392 #define PS2 (G.PS2 ) 393 #endif 394 #if ENABLE_FEATURE_EDITING 395 #define line_input_state (G.line_input_state) 396 #endif 397 #if ENABLE_HUSH_JOB 398 #define run_list_level (G.run_list_level ) 399 #define saved_task_pgrp (G.saved_task_pgrp ) 400 #define saved_tty_pgrp (G.saved_tty_pgrp ) 401 #define last_jobid (G.last_jobid ) 402 #define job_list (G.job_list ) 403 #define toplevel_list (G.toplevel_list ) 404 #define toplevel_jb (G.toplevel_jb ) 405 #define ctrl_z_flag (G.ctrl_z_flag ) 406 #endif /* JOB */ 407 #define global_argv (G.global_argv ) 408 #define global_argc (G.global_argc ) 409 #define last_return_code (G.last_return_code) 410 #define ifs (G.ifs ) 411 #define fake_mode (G.fake_mode ) 412 #define close_me_head (G.close_me_head ) 413 #define cwd (G.cwd ) 414 #define last_bg_pid (G.last_bg_pid ) 415 #define top_var (G.top_var ) 416 #define shell_ver (G.shell_ver ) 417 #if ENABLE_FEATURE_SH_STANDALONE 418 #define nofork_save (G.nofork_save ) 419 #endif 420 #if ENABLE_HUSH_JOB 421 #define toplevel_jb (G.toplevel_jb ) 422 #endif 423 #define charmap (G.charmap ) 424 #define user_input_buf (G.user_input_buf ) 425 426 427 #define B_CHUNK 100 428 #define B_NOSPAC 1 429 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 430 431 #if 1 432 /* Normal */ 433 static void syntax(const char *msg) 434 { 435 /* Was using fancy stuff: 436 * (interactive_fd ? bb_error_msg : bb_error_msg_and_die)(...params...) 437 * but it SEGVs. ?! Oh well... explicit temp ptr works around that */ 438 void (*fp)(const char *s, ...); 439 440 fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die); 441 fp(msg ? "%s: %s" : "syntax error", "syntax error", msg); 442 } 443 444 #else 445 /* Debug */ 446 static void syntax_lineno(int line) 447 { 448 void (*fp)(const char *s, ...); 449 450 fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die); 451 fp("syntax error hush.c:%d", line); 452 } 453 #define syntax(str) syntax_lineno(__LINE__) 454 #endif 455 456 /* Index of subroutines: */ 457 /* function prototypes for builtins */ 458 static int builtin_cd(char **argv); 459 static int builtin_eval(char **argv); 460 static int builtin_exec(char **argv); 461 static int builtin_exit(char **argv); 462 static int builtin_export(char **argv); 463 #if ENABLE_HUSH_JOB 464 static int builtin_fg_bg(char **argv); 465 static int builtin_jobs(char **argv); 799 static int builtin_fg_bg(char **argv) FAST_FUNC; 800 static int builtin_jobs(char **argv) FAST_FUNC; 466 801 #endif 467 802 #if ENABLE_HUSH_HELP 468 static int builtin_help(char **argv); 469 #endif 470 static int builtin_pwd(char **argv); 471 static int builtin_read(char **argv); 472 static int builtin_set(char **argv); 473 static int builtin_shift(char **argv); 474 static int builtin_source(char **argv); 475 static int builtin_umask(char **argv); 476 static int builtin_unset(char **argv); 477 //static int builtin_not_written(char **argv); 478 /* o_string manipulation: */ 479 static int b_check_space(o_string *o, int len); 480 static int b_addchr(o_string *o, int ch); 481 static void b_reset(o_string *o); 482 static int b_addqchr(o_string *o, int ch, int quote); 483 /* in_str manipulations: */ 484 static int static_get(struct in_str *i); 485 static int static_peek(struct in_str *i); 486 static int file_get(struct in_str *i); 487 static int file_peek(struct in_str *i); 488 static void setup_file_in_str(struct in_str *i, FILE *f); 489 static void setup_string_in_str(struct in_str *i, const char *s); 490 /* close_me manipulations: */ 491 static void mark_open(int fd); 492 static void mark_closed(int fd); 493 static void close_all(void); 494 /* "run" the final data structures: */ 495 #if !defined(DEBUG_CLEAN) 496 #define free_pipe_list(head, indent) free_pipe_list(head) 497 #define free_pipe(pi, indent) free_pipe(pi) 498 #endif 499 static int free_pipe_list(struct pipe *head, int indent); 500 static int free_pipe(struct pipe *pi, int indent); 501 /* really run the final data structures: */ 502 static int setup_redirects(struct child_prog *prog, int squirrel[]); 503 static int run_list_real(struct pipe *pi); 504 static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; 505 static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; 506 static int run_pipe_real(struct pipe *pi); 507 /* extended glob support: */ 508 static int globhack(const char *src, int flags, glob_t *pglob); 509 static int glob_needed(const char *s); 510 static int xglob(o_string *dest, int flags, glob_t *pglob); 511 /* variable assignment: */ 512 static int is_assignment(const char *s); 513 /* data structure manipulation: */ 514 static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); 515 static void initialize_context(struct p_context *ctx); 516 static int done_word(o_string *dest, struct p_context *ctx); 517 static int done_command(struct p_context *ctx); 518 static int done_pipe(struct p_context *ctx, pipe_style type); 519 /* primary string parsing: */ 520 static int redirect_dup_num(struct in_str *input); 521 static int redirect_opt_num(o_string *o); 522 #if ENABLE_HUSH_TICK 523 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, const char *subst_end); 524 #endif 525 static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); 526 static const char *lookup_param(const char *src); 527 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 528 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); 529 /* setup: */ 530 static int parse_and_run_stream(struct in_str *inp, int parse_flag); 531 static int parse_and_run_string(const char *s, int parse_flag); 532 static int parse_and_run_file(FILE *f); 533 /* job management: */ 534 static int checkjobs(struct pipe* fg_pipe); 535 #if ENABLE_HUSH_JOB 536 static int checkjobs_and_fg_shell(struct pipe* fg_pipe); 537 static void insert_bg_job(struct pipe *pi); 538 static void remove_bg_job(struct pipe *pi); 539 static void delete_finished_bg_job(struct pipe *pi); 540 #else 541 int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ 542 #endif 543 /* local variable support */ 544 static char **expand_strvec_to_strvec(char **argv); 545 /* used for eval */ 546 static char *expand_strvec_to_string(char **argv); 547 /* used for expansion of right hand of assignments */ 548 static char *expand_string_to_string(const char *str); 549 static struct variable *get_local_var(const char *name); 550 static int set_local_var(char *str, int flg_export); 551 static void unset_local_var(const char *name); 803 static int builtin_help(char **argv) FAST_FUNC; 804 #endif 805 #if ENABLE_HUSH_LOCAL 806 static int builtin_local(char **argv) FAST_FUNC; 807 #endif 808 #if HUSH_DEBUG 809 static int builtin_memleak(char **argv) FAST_FUNC; 810 #endif 811 #if ENABLE_PRINTF 812 static int builtin_printf(char **argv) FAST_FUNC; 813 #endif 814 static int builtin_pwd(char **argv) FAST_FUNC; 815 static int builtin_read(char **argv) FAST_FUNC; 816 static int builtin_set(char **argv) FAST_FUNC; 817 static int builtin_shift(char **argv) FAST_FUNC; 818 static int builtin_source(char **argv) FAST_FUNC; 819 static int builtin_test(char **argv) FAST_FUNC; 820 static int builtin_trap(char **argv) FAST_FUNC; 821 static int builtin_type(char **argv) FAST_FUNC; 822 static int builtin_true(char **argv) FAST_FUNC; 823 static int builtin_umask(char **argv) FAST_FUNC; 824 static int builtin_unset(char **argv) FAST_FUNC; 825 static int builtin_wait(char **argv) FAST_FUNC; 826 #if ENABLE_HUSH_LOOPS 827 static int builtin_break(char **argv) FAST_FUNC; 828 static int builtin_continue(char **argv) FAST_FUNC; 829 #endif 830 #if ENABLE_HUSH_FUNCTIONS 831 static int builtin_return(char **argv) FAST_FUNC; 832 #endif 552 833 553 834 /* Table of built-in functions. They can be forked or not, depending on … … 558 839 * still be set at the end. */ 559 840 struct built_in_command { 560 const char * cmd; /* name */561 int (* function) (char **argv); /* function ptr */841 const char *b_cmd; 842 int (*b_function)(char **argv) FAST_FUNC; 562 843 #if ENABLE_HUSH_HELP 563 const char * descr; /* description */564 # define BLTIN(cmd, func, help) { cmd, func, help }844 const char *b_descr; 845 # define BLTIN(cmd, func, help) { cmd, func, help } 565 846 #else 566 # define BLTIN(cmd, func, help) { cmd, func }847 # define BLTIN(cmd, func, help) { cmd, func } 567 848 #endif 568 849 }; 569 850 570 static const struct built_in_command bltins[] = { 851 static const struct built_in_command bltins1[] = { 852 BLTIN("." , builtin_source , "Run commands in a file"), 853 BLTIN(":" , builtin_true , NULL), 571 854 #if ENABLE_HUSH_JOB 572 BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"), 573 #endif 574 // BLTIN("break" , builtin_not_written, "Exit for, while or until loop"), 575 BLTIN("cd" , builtin_cd, "Change working directory"), 576 // BLTIN("continue", builtin_not_written, "Continue for, while or until loop"), 577 BLTIN("eval" , builtin_eval, "Construct and run shell command"), 578 BLTIN("exec" , builtin_exec, "Exec command, replacing this shell with the exec'd process"), 579 BLTIN("exit" , builtin_exit, "Exit from shell"), 580 BLTIN("export", builtin_export, "Set environment variable"), 855 BLTIN("bg" , builtin_fg_bg , "Resume a job in the background"), 856 #endif 857 #if ENABLE_HUSH_LOOPS 858 BLTIN("break" , builtin_break , "Exit from a loop"), 859 #endif 860 BLTIN("cd" , builtin_cd , "Change directory"), 861 #if ENABLE_HUSH_LOOPS 862 BLTIN("continue" , builtin_continue, "Start new loop iteration"), 863 #endif 864 BLTIN("eval" , builtin_eval , "Construct and run shell command"), 865 BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"), 866 BLTIN("exit" , builtin_exit , "Exit"), 867 BLTIN("export" , builtin_export , "Set environment variables"), 581 868 #if ENABLE_HUSH_JOB 582 BLTIN("fg" , builtin_fg_bg, "Bring job into the foreground"), 583 BLTIN("jobs" , builtin_jobs, "Lists the active jobs"), 584 #endif 585 // TODO: remove pwd? we have it as an applet... 586 BLTIN("pwd" , builtin_pwd, "Print current directory"), 587 BLTIN("read" , builtin_read, "Input environment variable"), 588 // BLTIN("return", builtin_not_written, "Return from a function"), 589 BLTIN("set" , builtin_set, "Set/unset shell local variables"), 590 BLTIN("shift" , builtin_shift, "Shift positional parameters"), 591 // BLTIN("trap" , builtin_not_written, "Trap signals"), 592 // BLTIN("ulimit", builtin_not_written, "Controls resource limits"), 593 BLTIN("umask" , builtin_umask, "Sets file creation mask"), 594 BLTIN("unset" , builtin_unset, "Unset environment variable"), 595 BLTIN("." , builtin_source, "Source-in and run commands in a file"), 869 BLTIN("fg" , builtin_fg_bg , "Bring job into the foreground"), 870 #endif 596 871 #if ENABLE_HUSH_HELP 597 BLTIN("help" , builtin_help, "List shell built-in commands"), 598 #endif 599 BLTIN(NULL, NULL, NULL) 872 BLTIN("help" , builtin_help , NULL), 873 #endif 874 #if ENABLE_HUSH_JOB 875 BLTIN("jobs" , builtin_jobs , "List jobs"), 876 #endif 877 #if ENABLE_HUSH_LOCAL 878 BLTIN("local" , builtin_local , "Set local variables"), 879 #endif 880 #if HUSH_DEBUG 881 BLTIN("memleak" , builtin_memleak , NULL), 882 #endif 883 BLTIN("read" , builtin_read , "Input into variable"), 884 #if ENABLE_HUSH_FUNCTIONS 885 BLTIN("return" , builtin_return , "Return from a function"), 886 #endif 887 BLTIN("set" , builtin_set , "Set/unset positional parameters"), 888 BLTIN("shift" , builtin_shift , "Shift positional parameters"), 889 #if ENABLE_HUSH_BASH_COMPAT 890 BLTIN("source" , builtin_source , "Run commands in a file"), 891 #endif 892 BLTIN("trap" , builtin_trap , "Trap signals"), 893 BLTIN("type" , builtin_type , "Show command type"), 894 BLTIN("ulimit" , shell_builtin_ulimit , "Control resource limits"), 895 BLTIN("umask" , builtin_umask , "Set file creation mask"), 896 BLTIN("unset" , builtin_unset , "Unset variables"), 897 BLTIN("wait" , builtin_wait , "Wait for process"), 600 898 }; 601 899 /* For now, echo and test are unconditionally enabled. 900 * Maybe make it configurable? */ 901 static const struct built_in_command bltins2[] = { 902 BLTIN("[" , builtin_test , NULL), 903 BLTIN("echo" , builtin_echo , NULL), 904 #if ENABLE_PRINTF 905 BLTIN("printf" , builtin_printf , NULL), 906 #endif 907 BLTIN("pwd" , builtin_pwd , NULL), 908 BLTIN("test" , builtin_test , NULL), 909 }; 910 911 912 /* Debug printouts. 913 */ 914 #if HUSH_DEBUG 915 /* prevent disasters with G.debug_indent < 0 */ 916 # define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "") 917 # define debug_enter() (G.debug_indent++) 918 # define debug_leave() (G.debug_indent--) 919 #else 920 # define indent() ((void)0) 921 # define debug_enter() ((void)0) 922 # define debug_leave() ((void)0) 923 #endif 924 925 #ifndef debug_printf 926 # define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__)) 927 #endif 928 929 #ifndef debug_printf_parse 930 # define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__)) 931 #endif 932 933 #ifndef debug_printf_exec 934 #define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__)) 935 #endif 936 937 #ifndef debug_printf_env 938 # define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__)) 939 #endif 940 941 #ifndef debug_printf_jobs 942 # define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__)) 943 # define DEBUG_JOBS 1 944 #else 945 # define DEBUG_JOBS 0 946 #endif 947 948 #ifndef debug_printf_expand 949 # define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__)) 950 # define DEBUG_EXPAND 1 951 #else 952 # define DEBUG_EXPAND 0 953 #endif 954 955 #ifndef debug_printf_varexp 956 # define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__)) 957 #endif 958 959 #ifndef debug_printf_glob 960 # define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__)) 961 # define DEBUG_GLOB 1 962 #else 963 # define DEBUG_GLOB 0 964 #endif 965 966 #ifndef debug_printf_list 967 # define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) 968 #endif 969 970 #ifndef debug_printf_subst 971 # define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__)) 972 #endif 973 974 #ifndef debug_printf_clean 975 # define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__)) 976 # define DEBUG_CLEAN 1 977 #else 978 # define DEBUG_CLEAN 0 979 #endif 980 981 #if DEBUG_EXPAND 982 static void debug_print_strings(const char *prefix, char **vv) 983 { 984 indent(); 985 fdprintf(2, "%s:\n", prefix); 986 while (*vv) 987 fdprintf(2, " '%s'\n", *vv++); 988 } 989 #else 990 # define debug_print_strings(prefix, vv) ((void)0) 991 #endif 992 993 994 /* Leak hunting. Use hush_leaktool.sh for post-processing. 995 */ 996 #if LEAK_HUNTING 997 static void *xxmalloc(int lineno, size_t size) 998 { 999 void *ptr = xmalloc((size + 0xff) & ~0xff); 1000 fdprintf(2, "line %d: malloc %p\n", lineno, ptr); 1001 return ptr; 1002 } 1003 static void *xxrealloc(int lineno, void *ptr, size_t size) 1004 { 1005 ptr = xrealloc(ptr, (size + 0xff) & ~0xff); 1006 fdprintf(2, "line %d: realloc %p\n", lineno, ptr); 1007 return ptr; 1008 } 1009 static char *xxstrdup(int lineno, const char *str) 1010 { 1011 char *ptr = xstrdup(str); 1012 fdprintf(2, "line %d: strdup %p\n", lineno, ptr); 1013 return ptr; 1014 } 1015 static void xxfree(void *ptr) 1016 { 1017 fdprintf(2, "free %p\n", ptr); 1018 free(ptr); 1019 } 1020 # define xmalloc(s) xxmalloc(__LINE__, s) 1021 # define xrealloc(p, s) xxrealloc(__LINE__, p, s) 1022 # define xstrdup(s) xxstrdup(__LINE__, s) 1023 # define free(p) xxfree(p) 1024 #endif 1025 1026 1027 /* Syntax and runtime errors. They always abort scripts. 1028 * In interactive use they usually discard unparsed and/or unexecuted commands 1029 * and return to the prompt. 1030 * HUSH_DEBUG >= 2 prints line number in this file where it was detected. 1031 */ 1032 #if HUSH_DEBUG < 2 1033 # define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) 1034 # define syntax_error(lineno, msg) syntax_error(msg) 1035 # define syntax_error_at(lineno, msg) syntax_error_at(msg) 1036 # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) 1037 # define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s) 1038 # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) 1039 #endif 1040 1041 static void die_if_script(unsigned lineno, const char *fmt, ...) 1042 { 1043 va_list p; 1044 1045 #if HUSH_DEBUG >= 2 1046 bb_error_msg("hush.c:%u", lineno); 1047 #endif 1048 va_start(p, fmt); 1049 bb_verror_msg(fmt, p, NULL); 1050 va_end(p); 1051 if (!G_interactive_fd) 1052 xfunc_die(); 1053 } 1054 1055 static void syntax_error(unsigned lineno, const char *msg) 1056 { 1057 if (msg) 1058 die_if_script(lineno, "syntax error: %s", msg); 1059 else 1060 die_if_script(lineno, "syntax error", NULL); 1061 } 1062 1063 static void syntax_error_at(unsigned lineno, const char *msg) 1064 { 1065 die_if_script(lineno, "syntax error at '%s'", msg); 1066 } 1067 1068 static void syntax_error_unterm_str(unsigned lineno, const char *s) 1069 { 1070 die_if_script(lineno, "syntax error: unterminated %s", s); 1071 } 1072 1073 /* It so happens that all such cases are totally fatal 1074 * even if shell is interactive: EOF while looking for closing 1075 * delimiter. There is nowhere to read stuff from after that, 1076 * it's EOF! The only choice is to terminate. 1077 */ 1078 static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; 1079 static void syntax_error_unterm_ch(unsigned lineno, char ch) 1080 { 1081 char msg[2] = { ch, '\0' }; 1082 syntax_error_unterm_str(lineno, msg); 1083 xfunc_die(); 1084 } 1085 1086 static void syntax_error_unexpected_ch(unsigned lineno, int ch) 1087 { 1088 char msg[2]; 1089 msg[0] = ch; 1090 msg[1] = '\0'; 1091 die_if_script(lineno, "syntax error: unexpected %s", ch == EOF ? "EOF" : msg); 1092 } 1093 1094 #if HUSH_DEBUG < 2 1095 # undef die_if_script 1096 # undef syntax_error 1097 # undef syntax_error_at 1098 # undef syntax_error_unterm_ch 1099 # undef syntax_error_unterm_str 1100 # undef syntax_error_unexpected_ch 1101 #else 1102 # define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) 1103 # define syntax_error(msg) syntax_error(__LINE__, msg) 1104 # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) 1105 # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) 1106 # define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s) 1107 # define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch) 1108 #endif 1109 1110 1111 #if ENABLE_HUSH_INTERACTIVE 1112 static void cmdedit_update_prompt(void); 1113 #else 1114 # define cmdedit_update_prompt() ((void)0) 1115 #endif 1116 1117 1118 /* Utility functions 1119 */ 1120 /* Replace each \x with x in place, return ptr past NUL. */ 1121 static char *unbackslash(char *src) 1122 { 1123 char *dst = src = strchrnul(src, '\\'); 1124 while (1) { 1125 if (*src == '\\') 1126 src++; 1127 if ((*dst++ = *src++) == '\0') 1128 break; 1129 } 1130 return dst; 1131 } 1132 1133 static char **add_strings_to_strings(char **strings, char **add, int need_to_dup) 1134 { 1135 int i; 1136 unsigned count1; 1137 unsigned count2; 1138 char **v; 1139 1140 v = strings; 1141 count1 = 0; 1142 if (v) { 1143 while (*v) { 1144 count1++; 1145 v++; 1146 } 1147 } 1148 count2 = 0; 1149 v = add; 1150 while (*v) { 1151 count2++; 1152 v++; 1153 } 1154 v = xrealloc(strings, (count1 + count2 + 1) * sizeof(char*)); 1155 v[count1 + count2] = NULL; 1156 i = count2; 1157 while (--i >= 0) 1158 v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]); 1159 return v; 1160 } 1161 #if LEAK_HUNTING 1162 static char **xx_add_strings_to_strings(int lineno, char **strings, char **add, int need_to_dup) 1163 { 1164 char **ptr = add_strings_to_strings(strings, add, need_to_dup); 1165 fdprintf(2, "line %d: add_strings_to_strings %p\n", lineno, ptr); 1166 return ptr; 1167 } 1168 #define add_strings_to_strings(strings, add, need_to_dup) \ 1169 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup) 1170 #endif 1171 1172 /* Note: takes ownership of "add" ptr (it is not strdup'ed) */ 1173 static char **add_string_to_strings(char **strings, char *add) 1174 { 1175 char *v[2]; 1176 v[0] = add; 1177 v[1] = NULL; 1178 return add_strings_to_strings(strings, v, /*dup:*/ 0); 1179 } 1180 #if LEAK_HUNTING 1181 static char **xx_add_string_to_strings(int lineno, char **strings, char *add) 1182 { 1183 char **ptr = add_string_to_strings(strings, add); 1184 fdprintf(2, "line %d: add_string_to_strings %p\n", lineno, ptr); 1185 return ptr; 1186 } 1187 #define add_string_to_strings(strings, add) \ 1188 xx_add_string_to_strings(__LINE__, strings, add) 1189 #endif 1190 1191 static void free_strings(char **strings) 1192 { 1193 char **v; 1194 1195 if (!strings) 1196 return; 1197 v = strings; 1198 while (*v) { 1199 free(*v); 1200 v++; 1201 } 1202 free(strings); 1203 } 1204 1205 1206 /* Helpers for setting new $n and restoring them back 1207 */ 1208 typedef struct save_arg_t { 1209 char *sv_argv0; 1210 char **sv_g_argv; 1211 int sv_g_argc; 1212 smallint sv_g_malloced; 1213 } save_arg_t; 1214 1215 static void save_and_replace_G_args(save_arg_t *sv, char **argv) 1216 { 1217 int n; 1218 1219 sv->sv_argv0 = argv[0]; 1220 sv->sv_g_argv = G.global_argv; 1221 sv->sv_g_argc = G.global_argc; 1222 sv->sv_g_malloced = G.global_args_malloced; 1223 1224 argv[0] = G.global_argv[0]; /* retain $0 */ 1225 G.global_argv = argv; 1226 G.global_args_malloced = 0; 1227 1228 n = 1; 1229 while (*++argv) 1230 n++; 1231 G.global_argc = n; 1232 } 1233 1234 static void restore_G_args(save_arg_t *sv, char **argv) 1235 { 1236 char **pp; 1237 1238 if (G.global_args_malloced) { 1239 /* someone ran "set -- arg1 arg2 ...", undo */ 1240 pp = G.global_argv; 1241 while (*++pp) /* note: does not free $0 */ 1242 free(*pp); 1243 free(G.global_argv); 1244 } 1245 argv[0] = sv->sv_argv0; 1246 G.global_argv = sv->sv_g_argv; 1247 G.global_argc = sv->sv_g_argc; 1248 G.global_args_malloced = sv->sv_g_malloced; 1249 } 1250 1251 1252 /* Basic theory of signal handling in shell 1253 * ======================================== 1254 * This does not describe what hush does, rather, it is current understanding 1255 * what it _should_ do. If it doesn't, it's a bug. 1256 * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap 1257 * 1258 * Signals are handled only after each pipe ("cmd | cmd | cmd" thing) 1259 * is finished or backgrounded. It is the same in interactive and 1260 * non-interactive shells, and is the same regardless of whether 1261 * a user trap handler is installed or a shell special one is in effect. 1262 * ^C or ^Z from keyboard seems to execute "at once" because it usually 1263 * backgrounds (i.e. stops) or kills all members of currently running 1264 * pipe. 1265 * 1266 * Wait builtin in interruptible by signals for which user trap is set 1267 * or by SIGINT in interactive shell. 1268 * 1269 * Trap handlers will execute even within trap handlers. (right?) 1270 * 1271 * User trap handlers are forgotten when subshell ("(cmd)") is entered, 1272 * except for handlers set to '' (empty string). 1273 * 1274 * If job control is off, backgrounded commands ("cmd &") 1275 * have SIGINT, SIGQUIT set to SIG_IGN. 1276 * 1277 * Commands which are run in command substitution ("`cmd`") 1278 * have SIGTTIN, SIGTTOU, SIGTSTP set to SIG_IGN. 1279 * 1280 * Ordinary commands have signals set to SIG_IGN/DFL as inherited 1281 * by the shell from its parent. 1282 * 1283 * Signals which differ from SIG_DFL action 1284 * (note: child (i.e., [v]forked) shell is not an interactive shell): 1285 * 1286 * SIGQUIT: ignore 1287 * SIGTERM (interactive): ignore 1288 * SIGHUP (interactive): 1289 * send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit 1290 * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore 1291 * Note that ^Z is handled not by trapping SIGTSTP, but by seeing 1292 * that all pipe members are stopped. Try this in bash: 1293 * while :; do :; done - ^Z does not background it 1294 * (while :; do :; done) - ^Z backgrounds it 1295 * SIGINT (interactive): wait for last pipe, ignore the rest 1296 * of the command line, show prompt. NB: ^C does not send SIGINT 1297 * to interactive shell while shell is waiting for a pipe, 1298 * since shell is bg'ed (is not in foreground process group). 1299 * Example 1: this waits 5 sec, but does not execute ls: 1300 * "echo $$; sleep 5; ls -l" + "kill -INT <pid>" 1301 * Example 2: this does not wait and does not execute ls: 1302 * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>" 1303 * Example 3: this does not wait 5 sec, but executes ls: 1304 * "sleep 5; ls -l" + press ^C 1305 * 1306 * (What happens to signals which are IGN on shell start?) 1307 * (What happens with signal mask on shell start?) 1308 * 1309 * Implementation in hush 1310 * ====================== 1311 * We use in-kernel pending signal mask to determine which signals were sent. 1312 * We block all signals which we don't want to take action immediately, 1313 * i.e. we block all signals which need to have special handling as described 1314 * above, and all signals which have traps set. 1315 * After each pipe execution, we extract any pending signals via sigtimedwait() 1316 * and act on them. 1317 * 1318 * unsigned non_DFL_mask: a mask of such "special" signals 1319 * sigset_t blocked_set: current blocked signal set 1320 * 1321 * "trap - SIGxxx": 1322 * clear bit in blocked_set unless it is also in non_DFL_mask 1323 * "trap 'cmd' SIGxxx": 1324 * set bit in blocked_set (even if 'cmd' is '') 1325 * after [v]fork, if we plan to be a shell: 1326 * unblock signals with special interactive handling 1327 * (child shell is not interactive), 1328 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc) 1329 * after [v]fork, if we plan to exec: 1330 * POSIX says fork clears pending signal mask in child - no need to clear it. 1331 * Restore blocked signal set to one inherited by shell just prior to exec. 1332 * 1333 * Note: as a result, we do not use signal handlers much. The only uses 1334 * are to count SIGCHLDs 1335 * and to restore tty pgrp on signal-induced exit. 1336 * 1337 * Note 2 (compat): 1338 * Standard says "When a subshell is entered, traps that are not being ignored 1339 * are set to the default actions". bash interprets it so that traps which 1340 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1341 */ 1342 enum { 1343 SPECIAL_INTERACTIVE_SIGS = 0 1344 | (1 << SIGTERM) 1345 | (1 << SIGINT) 1346 | (1 << SIGHUP) 1347 , 1348 SPECIAL_JOB_SIGS = 0 602 1349 #if ENABLE_HUSH_JOB 603 604 /* move to libbb? */ 605 static void signal_SA_RESTART(int sig, void (*handler)(int)) 606 { 607 struct sigaction sa; 608 sa.sa_handler = handler; 609 sa.sa_flags = SA_RESTART; 610 sigemptyset(&sa.sa_mask); 611 sigaction(sig, &sa, NULL); 612 } 613 614 /* Signals are grouped, we handle them in batches */ 615 static void set_fatal_sighandler(void (*handler)(int)) 616 { 617 signal(SIGILL , handler); 618 signal(SIGTRAP, handler); 619 signal(SIGABRT, handler); 620 signal(SIGFPE , handler); 621 signal(SIGBUS , handler); 622 signal(SIGSEGV, handler); 623 /* bash 3.2 seems to handle these just like 'fatal' ones */ 624 signal(SIGHUP , handler); 625 signal(SIGPIPE, handler); 626 signal(SIGALRM, handler); 627 } 628 static void set_jobctrl_sighandler(void (*handler)(int)) 629 { 630 signal(SIGTSTP, handler); 631 signal(SIGTTIN, handler); 632 signal(SIGTTOU, handler); 633 } 634 static void set_misc_sighandler(void (*handler)(int)) 635 { 636 signal(SIGINT , handler); 637 signal(SIGQUIT, handler); 638 signal(SIGTERM, handler); 639 } 640 /* SIGCHLD is special and handled separately */ 641 642 static void set_every_sighandler(void (*handler)(int)) 643 { 644 set_fatal_sighandler(handler); 645 set_jobctrl_sighandler(handler); 646 set_misc_sighandler(handler); 647 signal(SIGCHLD, handler); 648 } 649 650 static void handler_ctrl_c(int sig) 651 { 652 debug_printf_jobs("got sig %d\n", sig); 653 // as usual we can have all kinds of nasty problems with leaked malloc data here 654 siglongjmp(toplevel_jb, 1); 655 } 656 657 static void handler_ctrl_z(int sig) 658 { 659 pid_t pid; 660 661 debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid()); 662 pid = fork(); 663 if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */ 664 return; 665 ctrl_z_flag = 1; 666 if (!pid) { /* child */ 667 setpgrp(); 668 debug_printf_jobs("set pgrp for child %d ok\n", getpid()); 669 set_every_sighandler(SIG_DFL); 670 raise(SIGTSTP); /* resend TSTP so that child will be stopped */ 671 debug_printf_jobs("returning in child\n"); 672 /* return to nofork, it will eventually exit now, 673 * not return back to shell */ 674 return; 675 } 676 /* parent */ 677 /* finish filling up pipe info */ 678 toplevel_list->pgrp = pid; /* child is in its own pgrp */ 679 toplevel_list->progs[0].pid = pid; 680 /* parent needs to longjmp out of running nofork. 681 * we will "return" exitcode 0, with child put in background */ 682 // as usual we can have all kinds of nasty problems with leaked malloc data here 683 debug_printf_jobs("siglongjmp in parent\n"); 684 siglongjmp(toplevel_jb, 1); 685 } 1350 | (1 << SIGTTIN) 1351 | (1 << SIGTTOU) 1352 | (1 << SIGTSTP) 1353 #endif 1354 }; 1355 1356 #if ENABLE_HUSH_FAST 1357 static void SIGCHLD_handler(int sig UNUSED_PARAM) 1358 { 1359 G.count_SIGCHLD++; 1360 //bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1361 } 1362 #endif 1363 1364 #if ENABLE_HUSH_JOB 1365 1366 /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ 1367 # define disable_restore_tty_pgrp_on_exit() (die_sleep = 0) 1368 /* After [v]fork, in parent: restore tty pgrp on xfunc death */ 1369 # define enable_restore_tty_pgrp_on_exit() (die_sleep = -1) 686 1370 687 1371 /* Restores tty foreground process group, and exits. 688 1372 * May be called as signal handler for fatal signal 689 * (will faithfullyresend signal to itself, producing correct exit state)1373 * (will resend signal to itself, producing correct exit state) 690 1374 * or called directly with -EXITCODE. 691 1375 * We also call it if xfunc is exiting. */ 692 static void sigexit(int sig) ATTRIBUTE_NORETURN;1376 static void sigexit(int sig) NORETURN; 693 1377 static void sigexit(int sig) 694 1378 { 695 sigset_t block_all;696 697 1379 /* Disable all signals: job control, SIGPIPE, etc. */ 698 sigfillset(&block_all); 699 sigprocmask(SIG_SETMASK, &block_all, NULL); 700 701 if (interactive_fd) 702 tcsetpgrp(interactive_fd, saved_tty_pgrp); 1380 sigprocmask_allsigs(SIG_BLOCK); 1381 1382 /* Careful: we can end up here after [v]fork. Do not restore 1383 * tty pgrp then, only top-level shell process does that */ 1384 if (G_saved_tty_pgrp && getpid() == G.root_pid) 1385 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 703 1386 704 1387 /* Not a signal, just exit */ … … 706 1389 _exit(- sig); 707 1390 708 /* Enable only this sig and kill ourself with it */ 709 signal(sig, SIG_DFL); 710 sigdelset(&block_all, sig); 711 sigprocmask(SIG_SETMASK, &block_all, NULL); 712 raise(sig); 713 _exit(1); /* Should not reach it */ 714 } 1391 kill_myself_with_sig(sig); /* does not return */ 1392 } 1393 #else 1394 1395 # define disable_restore_tty_pgrp_on_exit() ((void)0) 1396 # define enable_restore_tty_pgrp_on_exit() ((void)0) 1397 1398 #endif 715 1399 716 1400 /* Restores tty foreground process group, and exits. */ 717 static void hush_exit(int exitcode) ATTRIBUTE_NORETURN;1401 static void hush_exit(int exitcode) NORETURN; 718 1402 static void hush_exit(int exitcode) 719 1403 { 720 fflush(NULL); /* flush all streams */ 1404 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { 1405 /* Prevent recursion: 1406 * trap "echo Hi; exit" EXIT; exit 1407 */ 1408 char *argv[3]; 1409 /* argv[0] is unused */ 1410 argv[1] = G.traps[0]; 1411 argv[2] = NULL; 1412 G.exiting = 1; /* prevent EXIT trap recursion */ 1413 /* Note: G.traps[0] is not cleared! 1414 * "trap" will still show it, if executed 1415 * in the handler */ 1416 builtin_eval(argv); 1417 } 1418 1419 #if ENABLE_FEATURE_CLEAN_UP 1420 { 1421 struct variable *cur_var; 1422 if (G.cwd != bb_msg_unknown) 1423 free((char*)G.cwd); 1424 cur_var = G.top_var; 1425 while (cur_var) { 1426 struct variable *tmp = cur_var; 1427 if (!cur_var->max_len) 1428 free(cur_var->varstr); 1429 cur_var = cur_var->next; 1430 free(tmp); 1431 } 1432 } 1433 #endif 1434 1435 #if ENABLE_HUSH_JOB 1436 fflush_all(); 721 1437 sigexit(- (exitcode & 0xff)); 722 } 723 724 #else /* !JOB */ 725 726 #define set_fatal_sighandler(handler) ((void)0) 727 #define set_jobctrl_sighandler(handler) ((void)0) 728 #define set_misc_sighandler(handler) ((void)0) 729 #define hush_exit(e) exit(e) 730 731 #endif /* JOB */ 732 733 734 static const char *set_cwd(void) 735 { 736 if (cwd == bb_msg_unknown) 737 cwd = NULL; /* xrealloc_getcwd_or_warn(arg) calls free(arg)! */ 738 cwd = xrealloc_getcwd_or_warn((char *)cwd); 739 if (!cwd) 740 cwd = bb_msg_unknown; 741 return cwd; 742 } 743 744 /* built-in 'eval' handler */ 745 static int builtin_eval(char **argv) 746 { 747 int rcode = EXIT_SUCCESS; 748 749 if (argv[1]) { 750 char *str = expand_strvec_to_string(argv + 1); 751 parse_and_run_string(str, PARSEFLAG_EXIT_FROM_LOOP | 752 PARSEFLAG_SEMICOLON); 1438 #else 1439 exit(exitcode); 1440 #endif 1441 } 1442 1443 1444 static int check_and_run_traps(int sig) 1445 { 1446 /* I want it in rodata, not in bss. 1447 * gcc 4.2.1 puts it in rodata only if it has { 0, 0 } 1448 * initializer. But other compilers may still use bss. 1449 * TODO: find more portable solution. 1450 */ 1451 static const struct timespec zero_timespec = { 0, 0 }; 1452 smalluint save_rcode; 1453 int last_sig = 0; 1454 1455 if (sig) 1456 goto jump_in; 1457 while (1) { 1458 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); 1459 if (sig <= 0) 1460 break; 1461 jump_in: 1462 last_sig = sig; 1463 if (G.traps && G.traps[sig]) { 1464 if (G.traps[sig][0]) { 1465 /* We have user-defined handler */ 1466 char *argv[3]; 1467 /* argv[0] is unused */ 1468 argv[1] = G.traps[sig]; 1469 argv[2] = NULL; 1470 save_rcode = G.last_exitcode; 1471 builtin_eval(argv); 1472 G.last_exitcode = save_rcode; 1473 } /* else: "" trap, ignoring signal */ 1474 continue; 1475 } 1476 /* not a trap: special action */ 1477 switch (sig) { 1478 #if ENABLE_HUSH_FAST 1479 case SIGCHLD: 1480 G.count_SIGCHLD++; 1481 //bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1482 break; 1483 #endif 1484 case SIGINT: 1485 /* Builtin was ^C'ed, make it look prettier: */ 1486 bb_putchar('\n'); 1487 G.flag_SIGINT = 1; 1488 break; 1489 #if ENABLE_HUSH_JOB 1490 case SIGHUP: { 1491 struct pipe *job; 1492 /* bash is observed to signal whole process groups, 1493 * not individual processes */ 1494 for (job = G.job_list; job; job = job->next) { 1495 if (job->pgrp <= 0) 1496 continue; 1497 debug_printf_exec("HUPing pgrp %d\n", job->pgrp); 1498 if (kill(- job->pgrp, SIGHUP) == 0) 1499 kill(- job->pgrp, SIGCONT); 1500 } 1501 sigexit(SIGHUP); 1502 } 1503 #endif 1504 default: /* ignored: */ 1505 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1506 break; 1507 } 1508 } 1509 return last_sig; 1510 } 1511 1512 1513 static const char *get_cwd(int force) 1514 { 1515 if (force || G.cwd == NULL) { 1516 /* xrealloc_getcwd_or_warn(arg) calls free(arg), 1517 * we must not try to free(bb_msg_unknown) */ 1518 if (G.cwd == bb_msg_unknown) 1519 G.cwd = NULL; 1520 G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd); 1521 if (!G.cwd) 1522 G.cwd = bb_msg_unknown; 1523 } 1524 return G.cwd; 1525 } 1526 1527 1528 /* 1529 * Shell and environment variable support 1530 */ 1531 static struct variable **get_ptr_to_local_var(const char *name, unsigned len) 1532 { 1533 struct variable **pp; 1534 struct variable *cur; 1535 1536 pp = &G.top_var; 1537 while ((cur = *pp) != NULL) { 1538 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') 1539 return pp; 1540 pp = &cur->next; 1541 } 1542 return NULL; 1543 } 1544 1545 static const char* FAST_FUNC get_local_var_value(const char *name) 1546 { 1547 struct variable **vpp; 1548 unsigned len = strlen(name); 1549 1550 if (G.expanded_assignments) { 1551 char **cpp = G.expanded_assignments; 1552 while (*cpp) { 1553 char *cp = *cpp; 1554 if (strncmp(cp, name, len) == 0 && cp[len] == '=') 1555 return cp + len + 1; 1556 cpp++; 1557 } 1558 } 1559 1560 vpp = get_ptr_to_local_var(name, len); 1561 if (vpp) 1562 return (*vpp)->varstr + len + 1; 1563 1564 if (strcmp(name, "PPID") == 0) 1565 return utoa(G.root_ppid); 1566 // bash compat: UID? EUID? 1567 #if ENABLE_HUSH_RANDOM_SUPPORT 1568 if (strcmp(name, "RANDOM") == 0) 1569 return utoa(next_random(&G.random_gen)); 1570 #endif 1571 return NULL; 1572 } 1573 1574 /* str holds "NAME=VAL" and is expected to be malloced. 1575 * We take ownership of it. 1576 * flg_export: 1577 * 0: do not change export flag 1578 * (if creating new variable, flag will be 0) 1579 * 1: set export flag and putenv the variable 1580 * -1: clear export flag and unsetenv the variable 1581 * flg_read_only is set only when we handle -R var=val 1582 */ 1583 #if !BB_MMU && ENABLE_HUSH_LOCAL 1584 /* all params are used */ 1585 #elif BB_MMU && ENABLE_HUSH_LOCAL 1586 #define set_local_var(str, flg_export, local_lvl, flg_read_only) \ 1587 set_local_var(str, flg_export, local_lvl) 1588 #elif BB_MMU && !ENABLE_HUSH_LOCAL 1589 #define set_local_var(str, flg_export, local_lvl, flg_read_only) \ 1590 set_local_var(str, flg_export) 1591 #elif !BB_MMU && !ENABLE_HUSH_LOCAL 1592 #define set_local_var(str, flg_export, local_lvl, flg_read_only) \ 1593 set_local_var(str, flg_export, flg_read_only) 1594 #endif 1595 static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_only) 1596 { 1597 struct variable **var_pp; 1598 struct variable *cur; 1599 char *eq_sign; 1600 int name_len; 1601 1602 eq_sign = strchr(str, '='); 1603 if (!eq_sign) { /* not expected to ever happen? */ 753 1604 free(str); 754 rcode = last_return_code; 755 } 756 return rcode; 757 } 758 759 /* built-in 'cd <path>' handler */ 760 static int builtin_cd(char **argv) 761 { 762 const char *newdir; 763 if (argv[1] == NULL) 764 newdir = getenv("HOME") ? : "/"; 765 else 766 newdir = argv[1]; 767 if (chdir(newdir)) { 768 printf("cd: %s: %s\n", newdir, strerror(errno)); 769 return EXIT_FAILURE; 770 } 771 set_cwd(); 1605 return -1; 1606 } 1607 1608 name_len = eq_sign - str + 1; /* including '=' */ 1609 var_pp = &G.top_var; 1610 while ((cur = *var_pp) != NULL) { 1611 if (strncmp(cur->varstr, str, name_len) != 0) { 1612 var_pp = &cur->next; 1613 continue; 1614 } 1615 /* We found an existing var with this name */ 1616 if (cur->flg_read_only) { 1617 #if !BB_MMU 1618 if (!flg_read_only) 1619 #endif 1620 bb_error_msg("%s: readonly variable", str); 1621 free(str); 1622 return -1; 1623 } 1624 if (flg_export == -1) { // "&& cur->flg_export" ? 1625 debug_printf_env("%s: unsetenv '%s'\n", __func__, str); 1626 *eq_sign = '\0'; 1627 unsetenv(str); 1628 *eq_sign = '='; 1629 } 1630 #if ENABLE_HUSH_LOCAL 1631 if (cur->func_nest_level < local_lvl) { 1632 /* New variable is declared as local, 1633 * and existing one is global, or local 1634 * from enclosing function. 1635 * Remove and save old one: */ 1636 *var_pp = cur->next; 1637 cur->next = *G.shadowed_vars_pp; 1638 *G.shadowed_vars_pp = cur; 1639 /* bash 3.2.33(1) and exported vars: 1640 * # export z=z 1641 * # f() { local z=a; env | grep ^z; } 1642 * # f 1643 * z=a 1644 * # env | grep ^z 1645 * z=z 1646 */ 1647 if (cur->flg_export) 1648 flg_export = 1; 1649 break; 1650 } 1651 #endif 1652 if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) { 1653 free_and_exp: 1654 free(str); 1655 goto exp; 1656 } 1657 if (cur->max_len != 0) { 1658 if (cur->max_len >= strlen(str)) { 1659 /* This one is from startup env, reuse space */ 1660 strcpy(cur->varstr, str); 1661 goto free_and_exp; 1662 } 1663 } else { 1664 /* max_len == 0 signifies "malloced" var, which we can 1665 * (and has to) free */ 1666 free(cur->varstr); 1667 } 1668 cur->max_len = 0; 1669 goto set_str_and_exp; 1670 } 1671 1672 /* Not found - create new variable struct */ 1673 cur = xzalloc(sizeof(*cur)); 1674 #if ENABLE_HUSH_LOCAL 1675 cur->func_nest_level = local_lvl; 1676 #endif 1677 cur->next = *var_pp; 1678 *var_pp = cur; 1679 1680 set_str_and_exp: 1681 cur->varstr = str; 1682 #if !BB_MMU 1683 cur->flg_read_only = flg_read_only; 1684 #endif 1685 exp: 1686 if (flg_export == 1) 1687 cur->flg_export = 1; 1688 if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') 1689 cmdedit_update_prompt(); 1690 if (cur->flg_export) { 1691 if (flg_export == -1) { 1692 cur->flg_export = 0; 1693 /* unsetenv was already done */ 1694 } else { 1695 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); 1696 return putenv(cur->varstr); 1697 } 1698 } 1699 return 0; 1700 } 1701 1702 /* Used at startup and after each cd */ 1703 static void set_pwd_var(int exp) 1704 { 1705 set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), 1706 /*exp:*/ exp, /*lvl:*/ 0, /*ro:*/ 0); 1707 } 1708 1709 static int unset_local_var_len(const char *name, int name_len) 1710 { 1711 struct variable *cur; 1712 struct variable **var_pp; 1713 1714 if (!name) 1715 return EXIT_SUCCESS; 1716 var_pp = &G.top_var; 1717 while ((cur = *var_pp) != NULL) { 1718 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { 1719 if (cur->flg_read_only) { 1720 bb_error_msg("%s: readonly variable", name); 1721 return EXIT_FAILURE; 1722 } 1723 *var_pp = cur->next; 1724 debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr); 1725 bb_unsetenv(cur->varstr); 1726 if (name_len == 3 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') 1727 cmdedit_update_prompt(); 1728 if (!cur->max_len) 1729 free(cur->varstr); 1730 free(cur); 1731 return EXIT_SUCCESS; 1732 } 1733 var_pp = &cur->next; 1734 } 772 1735 return EXIT_SUCCESS; 773 1736 } 774 1737 775 /* built-in 'exec' handler */ 776 static int builtin_exec(char **argv) 777 { 778 if (argv[1] == NULL) 779 return EXIT_SUCCESS; /* Really? */ 780 pseudo_exec_argv(argv + 1); 781 /* never returns */ 782 } 783 784 /* built-in 'exit' handler */ 785 static int builtin_exit(char **argv) 786 { 787 // TODO: bash does it ONLY on top-level sh exit (+interacive only?) 788 //puts("exit"); /* bash does it */ 789 // TODO: warn if we have background jobs: "There are stopped jobs" 790 // On second consecutive 'exit', exit anyway. 791 792 if (argv[1] == NULL) 793 hush_exit(last_return_code); 794 /* mimic bash: exit 123abc == exit 255 + error msg */ 795 xfunc_error_retval = 255; 796 /* bash: exit -2 == exit 254, no error msg */ 797 hush_exit(xatoi(argv[1]) & 0xff); 798 } 799 800 /* built-in 'export VAR=value' handler */ 801 static int builtin_export(char **argv) 802 { 803 const char *value; 804 char *name = argv[1]; 805 806 if (name == NULL) { 807 // TODO: 808 // ash emits: export VAR='VAL' 809 // bash: declare -x VAR="VAL" 810 // (both also escape as needed (quotes, $, etc)) 811 char **e = environ; 812 if (e) 813 while (*e) 814 puts(*e++); 815 return EXIT_SUCCESS; 816 } 817 818 value = strchr(name, '='); 819 if (!value) { 820 /* They are exporting something without a =VALUE */ 821 struct variable *var; 822 823 var = get_local_var(name); 824 if (var) { 825 var->flg_export = 1; 1738 static int unset_local_var(const char *name) 1739 { 1740 return unset_local_var_len(name, strlen(name)); 1741 } 1742 1743 static void unset_vars(char **strings) 1744 { 1745 char **v; 1746 1747 if (!strings) 1748 return; 1749 v = strings; 1750 while (*v) { 1751 const char *eq = strchrnul(*v, '='); 1752 unset_local_var_len(*v, (int)(eq - *v)); 1753 v++; 1754 } 1755 free(strings); 1756 } 1757 1758 static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 1759 { 1760 char *var = xasprintf("%s=%s", name, val); 1761 set_local_var(var, /*flags:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 1762 } 1763 1764 1765 /* 1766 * Helpers for "var1=val1 var2=val2 cmd" feature 1767 */ 1768 static void add_vars(struct variable *var) 1769 { 1770 struct variable *next; 1771 1772 while (var) { 1773 next = var->next; 1774 var->next = G.top_var; 1775 G.top_var = var; 1776 if (var->flg_export) { 1777 debug_printf_env("%s: restoring exported '%s'\n", __func__, var->varstr); 826 1778 putenv(var->varstr); 827 }828 /* bash does not return an error when trying to export829 * an undefined variable. Do likewise. */830 return EXIT_SUCCESS;831 }832 833 set_local_var(xstrdup(name), 1);834 return EXIT_SUCCESS;835 }836 837 #if ENABLE_HUSH_JOB838 /* built-in 'fg' and 'bg' handler */839 static int builtin_fg_bg(char **argv)840 {841 int i, jobnum;842 struct pipe *pi;843 844 if (!interactive_fd)845 return EXIT_FAILURE;846 /* If they gave us no args, assume they want the last backgrounded task */847 if (!argv[1]) {848 for (pi = job_list; pi; pi = pi->next) {849 if (pi->jobid == last_jobid) {850 goto found;851 }852 }853 bb_error_msg("%s: no current job", argv[0]);854 return EXIT_FAILURE;855 }856 if (sscanf(argv[1], "%%%d", &jobnum) != 1) {857 bb_error_msg("%s: bad argument '%s'", argv[0], argv[1]);858 return EXIT_FAILURE;859 }860 for (pi = job_list; pi; pi = pi->next) {861 if (pi->jobid == jobnum) {862 goto found;863 }864 }865 bb_error_msg("%s: %d: no such job", argv[0], jobnum);866 return EXIT_FAILURE;867 found:868 // TODO: bash prints a string representation869 // of job being foregrounded (like "sleep 1 | cat")870 if (*argv[0] == 'f') {871 /* Put the job into the foreground. */872 tcsetpgrp(interactive_fd, pi->pgrp);873 }874 875 /* Restart the processes in the job */876 debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_progs, pi->pgrp);877 for (i = 0; i < pi->num_progs; i++) {878 debug_printf_jobs("reviving pid %d\n", pi->progs[i].pid);879 pi->progs[i].is_stopped = 0;880 }881 pi->stopped_progs = 0;882 883 i = kill(- pi->pgrp, SIGCONT);884 if (i < 0) {885 if (errno == ESRCH) {886 delete_finished_bg_job(pi);887 return EXIT_SUCCESS;888 1779 } else { 889 bb_perror_msg("kill (SIGCONT)"); 890 } 891 } 892 893 if (*argv[0] == 'f') { 894 remove_bg_job(pi); 895 return checkjobs_and_fg_shell(pi); 896 } 897 return EXIT_SUCCESS; 898 } 899 #endif 900 901 /* built-in 'help' handler */ 902 #if ENABLE_HUSH_HELP 903 static int builtin_help(char **argv ATTRIBUTE_UNUSED) 904 { 905 const struct built_in_command *x; 906 907 printf("\nBuilt-in commands:\n"); 908 printf("-------------------\n"); 909 for (x = bltins; x->cmd; x++) { 910 printf("%s\t%s\n", x->cmd, x->descr); 911 } 912 printf("\n\n"); 913 return EXIT_SUCCESS; 914 } 915 #endif 916 917 #if ENABLE_HUSH_JOB 918 /* built-in 'jobs' handler */ 919 static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) 920 { 921 struct pipe *job; 922 const char *status_string; 923 924 for (job = job_list; job; job = job->next) { 925 if (job->running_progs == job->stopped_progs) 926 status_string = "Stopped"; 927 else 928 status_string = "Running"; 929 930 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); 931 } 932 return EXIT_SUCCESS; 933 } 934 #endif 935 936 /* built-in 'pwd' handler */ 937 static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) 938 { 939 puts(set_cwd()); 940 return EXIT_SUCCESS; 941 } 942 943 /* built-in 'read VAR' handler */ 944 static int builtin_read(char **argv) 945 { 946 char *string; 947 const char *name = argv[1] ? argv[1] : "REPLY"; 948 949 string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name)); 950 return set_local_var(string, 0); 951 } 952 953 /* built-in 'set [VAR=value]' handler */ 954 static int builtin_set(char **argv) 955 { 956 char *temp = argv[1]; 957 struct variable *e; 958 959 if (temp == NULL) 960 for (e = top_var; e; e = e->next) 961 puts(e->varstr); 962 else 963 set_local_var(xstrdup(temp), 0); 964 965 return EXIT_SUCCESS; 966 } 967 968 969 /* Built-in 'shift' handler */ 970 static int builtin_shift(char **argv) 971 { 972 int n = 1; 973 if (argv[1]) { 974 n = atoi(argv[1]); 975 } 976 if (n >= 0 && n < global_argc) { 977 global_argv[n] = global_argv[0]; 978 global_argc -= n; 979 global_argv += n; 980 return EXIT_SUCCESS; 981 } 982 return EXIT_FAILURE; 983 } 984 985 /* Built-in '.' handler (read-in and execute commands from file) */ 986 static int builtin_source(char **argv) 987 { 988 FILE *input; 989 int status; 990 991 if (argv[1] == NULL) 992 return EXIT_FAILURE; 993 994 /* XXX search through $PATH is missing */ 995 input = fopen(argv[1], "r"); 996 if (!input) { 997 bb_error_msg("cannot open '%s'", argv[1]); 998 return EXIT_FAILURE; 999 } 1000 1001 /* Now run the file */ 1002 /* XXX argv and argc are broken; need to save old global_argv 1003 * (pointer only is OK!) on this stack frame, 1004 * set global_argv=argv+1, recurse, and restore. */ 1005 mark_open(fileno(input)); 1006 status = parse_and_run_file(input); 1007 mark_closed(fileno(input)); 1008 fclose(input); 1009 return status; 1010 } 1011 1012 static int builtin_umask(char **argv) 1013 { 1014 mode_t new_umask; 1015 const char *arg = argv[1]; 1016 char *end; 1017 if (arg) { 1018 new_umask = strtoul(arg, &end, 8); 1019 if (*end != '\0' || end == arg) { 1020 return EXIT_FAILURE; 1021 } 1780 debug_printf_env("%s: restoring variable '%s'\n", __func__, var->varstr); 1781 } 1782 var = next; 1783 } 1784 } 1785 1786 static struct variable *set_vars_and_save_old(char **strings) 1787 { 1788 char **s; 1789 struct variable *old = NULL; 1790 1791 if (!strings) 1792 return old; 1793 s = strings; 1794 while (*s) { 1795 struct variable *var_p; 1796 struct variable **var_pp; 1797 char *eq; 1798 1799 eq = strchr(*s, '='); 1800 if (eq) { 1801 var_pp = get_ptr_to_local_var(*s, eq - *s); 1802 if (var_pp) { 1803 /* Remove variable from global linked list */ 1804 var_p = *var_pp; 1805 debug_printf_env("%s: removing '%s'\n", __func__, var_p->varstr); 1806 *var_pp = var_p->next; 1807 /* Add it to returned list */ 1808 var_p->next = old; 1809 old = var_p; 1810 } 1811 set_local_var(*s, /*exp:*/ 1, /*lvl:*/ 0, /*ro:*/ 0); 1812 } 1813 s++; 1814 } 1815 return old; 1816 } 1817 1818 1819 /* 1820 * in_str support 1821 */ 1822 static int FAST_FUNC static_get(struct in_str *i) 1823 { 1824 int ch = *i->p; 1825 if (ch != '\0') { 1826 i->p++; 1827 return ch; 1828 } 1829 return EOF; 1830 } 1831 1832 static int FAST_FUNC static_peek(struct in_str *i) 1833 { 1834 return *i->p; 1835 } 1836 1837 #if ENABLE_HUSH_INTERACTIVE 1838 1839 static void cmdedit_update_prompt(void) 1840 { 1841 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 1842 G.PS1 = get_local_var_value("PS1"); 1843 if (G.PS1 == NULL) 1844 G.PS1 = "\\w \\$ "; 1845 G.PS2 = get_local_var_value("PS2"); 1022 1846 } else { 1023 new_umask = umask(0); 1024 printf("%.3o\n", (unsigned) new_umask); 1025 } 1026 umask(new_umask); 1027 return EXIT_SUCCESS; 1028 } 1029 1030 /* built-in 'unset VAR' handler */ 1031 static int builtin_unset(char **argv) 1032 { 1033 /* bash always returns true */ 1034 unset_local_var(argv[1]); 1035 return EXIT_SUCCESS; 1036 } 1037 1038 //static int builtin_not_written(char **argv) 1039 //{ 1040 // printf("builtin_%s not written\n", argv[0]); 1041 // return EXIT_FAILURE; 1042 //} 1043 1044 static int b_check_space(o_string *o, int len) 1045 { 1046 /* It would be easy to drop a more restrictive policy 1047 * in here, such as setting a maximum string length */ 1048 if (o->length + len > o->maxlen) { 1049 /* assert(data == NULL || o->maxlen != 0); */ 1050 o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); 1051 o->data = xrealloc(o->data, 1 + o->maxlen); 1052 } 1053 return o->data == NULL; 1054 } 1055 1056 static int b_addchr(o_string *o, int ch) 1057 { 1058 debug_printf("b_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o); 1059 if (b_check_space(o, 1)) 1060 return B_NOSPAC; 1061 o->data[o->length] = ch; 1062 o->length++; 1063 o->data[o->length] = '\0'; 1064 return 0; 1065 } 1066 1067 static void b_reset(o_string *o) 1068 { 1069 o->length = 0; 1070 o->nonnull = 0; 1071 if (o->data != NULL) 1072 *o->data = '\0'; 1073 } 1074 1075 static void b_free(o_string *o) 1076 { 1077 b_reset(o); 1078 free(o->data); 1079 o->data = NULL; 1080 o->maxlen = 0; 1081 } 1082 1083 /* My analysis of quoting semantics tells me that state information 1084 * is associated with a destination, not a source. 1085 */ 1086 static int b_addqchr(o_string *o, int ch, int quote) 1087 { 1088 if (quote && strchr("*?[\\", ch)) { 1089 int rc; 1090 rc = b_addchr(o, '\\'); 1091 if (rc) 1092 return rc; 1093 } 1094 return b_addchr(o, ch); 1095 } 1096 1097 static int static_get(struct in_str *i) 1098 { 1099 int ch = *i->p++; 1100 if (ch == '\0') return EOF; 1101 return ch; 1102 } 1103 1104 static int static_peek(struct in_str *i) 1105 { 1106 return *i->p; 1107 } 1108 1109 #if ENABLE_HUSH_INTERACTIVE 1110 #if ENABLE_FEATURE_EDITING 1111 static void cmdedit_set_initial_prompt(void) 1112 { 1113 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1114 PS1 = NULL; 1115 #else 1116 PS1 = getenv("PS1"); 1117 if (PS1 == NULL) 1118 PS1 = "\\w \\$ "; 1119 #endif 1120 } 1121 #endif /* EDITING */ 1122 1123 static const char* setup_prompt_string(int promptmode) 1847 G.PS1 = NULL; 1848 } 1849 if (G.PS2 == NULL) 1850 G.PS2 = "> "; 1851 } 1852 1853 static const char *setup_prompt_string(int promptmode) 1124 1854 { 1125 1855 const char *prompt_str; 1126 1856 debug_printf("setup_prompt_string %d ", promptmode); 1127 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1128 /* Set up the prompt */ 1129 if (promptmode == 0) { /* PS1 */ 1130 free((char*)PS1); 1131 PS1 = xasprintf("%s %c ", cwd, (geteuid() != 0) ? '$' : '#'); 1132 prompt_str = PS1; 1133 } else { 1134 prompt_str = PS2; 1135 } 1136 #else 1137 prompt_str = (promptmode == 0) ? PS1 : PS2; 1138 #endif 1857 if (!ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 1858 /* Set up the prompt */ 1859 if (promptmode == 0) { /* PS1 */ 1860 free((char*)G.PS1); 1861 /* bash uses $PWD value, even if it is set by user. 1862 * It uses current dir only if PWD is unset. 1863 * We always use current dir. */ 1864 G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); 1865 prompt_str = G.PS1; 1866 } else 1867 prompt_str = G.PS2; 1868 } else 1869 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2; 1139 1870 debug_printf("result '%s'\n", prompt_str); 1140 1871 return prompt_str; … … 1147 1878 1148 1879 prompt_str = setup_prompt_string(i->promptmode); 1149 # if ENABLE_FEATURE_EDITING1880 # if ENABLE_FEATURE_EDITING 1150 1881 /* Enable command line editing only while a command line 1151 * is actually being read; otherwise, we'll end up bequeathing 1152 * atexit() handlers and other unwanted stuff to our 1153 * child processes (rob@sysgo.de) */ 1154 r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state); 1882 * is actually being read */ 1883 do { 1884 G.flag_SIGINT = 0; 1885 /* buglet: SIGINT will not make new prompt to appear _at once_, 1886 * only after <Enter>. (^C will work) */ 1887 r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state); 1888 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 1889 check_and_run_traps(0); 1890 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 1155 1891 i->eof_flag = (r < 0); 1156 1892 if (i->eof_flag) { /* EOF/error detected */ 1157 user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */ 1158 user_input_buf[1] = '\0'; 1159 } 1160 #else 1161 fputs(prompt_str, stdout); 1162 fflush(stdout); 1163 user_input_buf[0] = r = fgetc(i->file); 1164 /*user_input_buf[1] = '\0'; - already is and never changed */ 1893 G.user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */ 1894 G.user_input_buf[1] = '\0'; 1895 } 1896 # else 1897 do { 1898 G.flag_SIGINT = 0; 1899 fputs(prompt_str, stdout); 1900 fflush_all(); 1901 G.user_input_buf[0] = r = fgetc(i->file); 1902 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 1903 //do we need check_and_run_traps(0)? (maybe only if stdin) 1904 } while (G.flag_SIGINT); 1165 1905 i->eof_flag = (r == EOF); 1166 #endif 1167 i->p = user_input_buf; 1168 } 1906 # endif 1907 i->p = G.user_input_buf; 1908 } 1909 1169 1910 #endif /* INTERACTIVE */ 1170 1911 1171 1912 /* This is the magic location that prints prompts 1172 1913 * and gets data back from the user */ 1173 static int file_get(struct in_str *i)1914 static int FAST_FUNC file_get(struct in_str *i) 1174 1915 { 1175 1916 int ch; … … 1183 1924 if (i->eof_flag && !*i->p) 1184 1925 ch = EOF; 1926 /* note: ch is never NUL */ 1185 1927 } else { 1186 1928 /* need to double check i->file because we might be doing something 1187 1929 * more complicated by now, like sourcing or substituting. */ 1188 1930 #if ENABLE_HUSH_INTERACTIVE 1189 if ( interactive_fd && i->promptme && i->file == stdin) {1931 if (G_interactive_fd && i->promptme && i->file == stdin) { 1190 1932 do { 1191 1933 get_user_input(i); … … 1196 1938 } 1197 1939 #endif 1198 ch = fgetc(i->file);1199 } 1200 debug_printf("file_get: got a'%c' %d\n", ch, ch);1940 do ch = fgetc(i->file); while (ch == '\0'); 1941 } 1942 debug_printf("file_get: got '%c' %d\n", ch, ch); 1201 1943 #if ENABLE_HUSH_INTERACTIVE 1202 1944 if (ch == '\n') … … 1206 1948 } 1207 1949 1208 /* All the callers guarantee this routine will never be1209 * used right after a newline, so prompting is not needed.1950 /* All callers guarantee this routine will never 1951 * be used right after a newline, so prompting is not needed. 1210 1952 */ 1211 static int file_peek(struct in_str *i)1953 static int FAST_FUNC file_peek(struct in_str *i) 1212 1954 { 1213 1955 int ch; … … 1216 1958 return EOF; 1217 1959 return *i->p; 1218 } 1219 ch = fgetc(i->file); 1960 /* note: ch is never NUL */ 1961 } 1962 do ch = fgetc(i->file); while (ch == '\0'); 1220 1963 i->eof_flag = (ch == EOF); 1221 1964 i->peek_buf[0] = ch; 1222 1965 i->peek_buf[1] = '\0'; 1223 1966 i->p = i->peek_buf; 1224 debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p);1967 debug_printf("file_peek: got '%c' %d\n", ch, ch); 1225 1968 return ch; 1226 1969 } … … 1250 1993 } 1251 1994 1252 static void mark_open(int fd) 1253 { 1254 struct close_me *new = xmalloc(sizeof(struct close_me)); 1255 new->fd = fd; 1256 new->next = close_me_head; 1257 close_me_head = new; 1258 } 1259 1260 static void mark_closed(int fd) 1261 { 1262 struct close_me *tmp; 1263 if (close_me_head == NULL || close_me_head->fd != fd) 1264 bb_error_msg_and_die("corrupt close_me"); 1265 tmp = close_me_head; 1266 close_me_head = close_me_head->next; 1267 free(tmp); 1268 } 1269 1270 static void close_all(void) 1271 { 1272 struct close_me *c; 1273 for (c = close_me_head; c; c = c->next) { 1274 close(c->fd); 1275 } 1276 close_me_head = NULL; 1995 1996 /* 1997 * o_string support 1998 */ 1999 #define B_CHUNK (32 * sizeof(char*)) 2000 2001 static void o_reset_to_empty_unquoted(o_string *o) 2002 { 2003 o->length = 0; 2004 o->has_quoted_part = 0; 2005 if (o->data) 2006 o->data[0] = '\0'; 2007 } 2008 2009 static void o_free(o_string *o) 2010 { 2011 free(o->data); 2012 memset(o, 0, sizeof(*o)); 2013 } 2014 2015 static ALWAYS_INLINE void o_free_unsafe(o_string *o) 2016 { 2017 free(o->data); 2018 } 2019 2020 static void o_grow_by(o_string *o, int len) 2021 { 2022 if (o->length + len > o->maxlen) { 2023 o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); 2024 o->data = xrealloc(o->data, 1 + o->maxlen); 2025 } 2026 } 2027 2028 static void o_addchr(o_string *o, int ch) 2029 { 2030 debug_printf("o_addchr: '%c' o->length=%d o=%p\n", ch, o->length, o); 2031 o_grow_by(o, 1); 2032 o->data[o->length] = ch; 2033 o->length++; 2034 o->data[o->length] = '\0'; 2035 } 2036 2037 static void o_addblock(o_string *o, const char *str, int len) 2038 { 2039 o_grow_by(o, len); 2040 memcpy(&o->data[o->length], str, len); 2041 o->length += len; 2042 o->data[o->length] = '\0'; 2043 } 2044 2045 static void o_addstr(o_string *o, const char *str) 2046 { 2047 o_addblock(o, str, strlen(str)); 2048 } 2049 2050 #if !BB_MMU 2051 static void nommu_addchr(o_string *o, int ch) 2052 { 2053 if (o) 2054 o_addchr(o, ch); 2055 } 2056 #else 2057 # define nommu_addchr(o, str) ((void)0) 2058 #endif 2059 2060 static void o_addstr_with_NUL(o_string *o, const char *str) 2061 { 2062 o_addblock(o, str, strlen(str) + 1); 2063 } 2064 2065 /* 2066 * HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side. 2067 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v. 2068 * Apparently, on unquoted $v bash still does globbing 2069 * ("v='*.txt'; echo $v" prints all .txt files), 2070 * but NOT brace expansion! Thus, there should be TWO independent 2071 * quoting mechanisms on $v expansion side: one protects 2072 * $v from brace expansion, and other additionally protects "$v" against globbing. 2073 * We have only second one. 2074 */ 2075 2076 #if ENABLE_HUSH_BRACE_EXPANSION 2077 # define MAYBE_BRACES "{}" 2078 #else 2079 # define MAYBE_BRACES "" 2080 #endif 2081 2082 /* My analysis of quoting semantics tells me that state information 2083 * is associated with a destination, not a source. 2084 */ 2085 static void o_addqchr(o_string *o, int ch) 2086 { 2087 int sz = 1; 2088 char *found = strchr("*?[\\" MAYBE_BRACES, ch); 2089 if (found) 2090 sz++; 2091 o_grow_by(o, sz); 2092 if (found) { 2093 o->data[o->length] = '\\'; 2094 o->length++; 2095 } 2096 o->data[o->length] = ch; 2097 o->length++; 2098 o->data[o->length] = '\0'; 2099 } 2100 2101 static void o_addQchr(o_string *o, int ch) 2102 { 2103 int sz = 1; 2104 if ((o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS) 2105 && strchr("*?[\\" MAYBE_BRACES, ch) 2106 ) { 2107 sz++; 2108 o->data[o->length] = '\\'; 2109 o->length++; 2110 } 2111 o_grow_by(o, sz); 2112 o->data[o->length] = ch; 2113 o->length++; 2114 o->data[o->length] = '\0'; 2115 } 2116 2117 static void o_addqblock(o_string *o, const char *str, int len) 2118 { 2119 while (len) { 2120 char ch; 2121 int sz; 2122 int ordinary_cnt = strcspn(str, "*?[\\" MAYBE_BRACES); 2123 if (ordinary_cnt > len) /* paranoia */ 2124 ordinary_cnt = len; 2125 o_addblock(o, str, ordinary_cnt); 2126 if (ordinary_cnt == len) 2127 return; 2128 str += ordinary_cnt; 2129 len -= ordinary_cnt + 1; /* we are processing + 1 char below */ 2130 2131 ch = *str++; 2132 sz = 1; 2133 if (ch) { /* it is necessarily one of "*?[\\" MAYBE_BRACES */ 2134 sz++; 2135 o->data[o->length] = '\\'; 2136 o->length++; 2137 } 2138 o_grow_by(o, sz); 2139 o->data[o->length] = ch; 2140 o->length++; 2141 o->data[o->length] = '\0'; 2142 } 2143 } 2144 2145 static void o_addQblock(o_string *o, const char *str, int len) 2146 { 2147 if (!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)) { 2148 o_addblock(o, str, len); 2149 return; 2150 } 2151 o_addqblock(o, str, len); 2152 } 2153 2154 static void o_addQstr(o_string *o, const char *str) 2155 { 2156 o_addQblock(o, str, strlen(str)); 2157 } 2158 2159 /* A special kind of o_string for $VAR and `cmd` expansion. 2160 * It contains char* list[] at the beginning, which is grown in 16 element 2161 * increments. Actual string data starts at the next multiple of 16 * (char*). 2162 * list[i] contains an INDEX (int!) into this string data. 2163 * It means that if list[] needs to grow, data needs to be moved higher up 2164 * but list[i]'s need not be modified. 2165 * NB: remembering how many list[i]'s you have there is crucial. 2166 * o_finalize_list() operation post-processes this structure - calculates 2167 * and stores actual char* ptrs in list[]. Oh, it NULL terminates it as well. 2168 */ 2169 #if DEBUG_EXPAND || DEBUG_GLOB 2170 static void debug_print_list(const char *prefix, o_string *o, int n) 2171 { 2172 char **list = (char**)o->data; 2173 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); 2174 int i = 0; 2175 2176 indent(); 2177 fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", 2178 prefix, list, n, string_start, o->length, o->maxlen, 2179 !!(o->o_expflags & EXP_FLAG_GLOB), 2180 o->has_quoted_part, 2181 !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 2182 while (i < n) { 2183 indent(); 2184 fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i], 2185 o->data + (int)(uintptr_t)list[i] + string_start, 2186 o->data + (int)(uintptr_t)list[i] + string_start); 2187 i++; 2188 } 2189 if (n) { 2190 const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start; 2191 indent(); 2192 fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); 2193 } 2194 } 2195 #else 2196 # define debug_print_list(prefix, o, n) ((void)0) 2197 #endif 2198 2199 /* n = o_save_ptr_helper(str, n) "starts new string" by storing an index value 2200 * in list[n] so that it points past last stored byte so far. 2201 * It returns n+1. */ 2202 static int o_save_ptr_helper(o_string *o, int n) 2203 { 2204 char **list = (char**)o->data; 2205 int string_start; 2206 int string_len; 2207 2208 if (!o->has_empty_slot) { 2209 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); 2210 string_len = o->length - string_start; 2211 if (!(n & 0xf)) { /* 0, 0x10, 0x20...? */ 2212 debug_printf_list("list[%d]=%d string_start=%d (growing)\n", n, string_len, string_start); 2213 /* list[n] points to string_start, make space for 16 more pointers */ 2214 o->maxlen += 0x10 * sizeof(list[0]); 2215 o->data = xrealloc(o->data, o->maxlen + 1); 2216 list = (char**)o->data; 2217 memmove(list + n + 0x10, list + n, string_len); 2218 o->length += 0x10 * sizeof(list[0]); 2219 } else { 2220 debug_printf_list("list[%d]=%d string_start=%d\n", 2221 n, string_len, string_start); 2222 } 2223 } else { 2224 /* We have empty slot at list[n], reuse without growth */ 2225 string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */ 2226 string_len = o->length - string_start; 2227 debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n", 2228 n, string_len, string_start); 2229 o->has_empty_slot = 0; 2230 } 2231 list[n] = (char*)(uintptr_t)string_len; 2232 return n + 1; 2233 } 2234 2235 /* "What was our last o_save_ptr'ed position (byte offset relative o->data)?" */ 2236 static int o_get_last_ptr(o_string *o, int n) 2237 { 2238 char **list = (char**)o->data; 2239 int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); 2240 2241 return ((int)(uintptr_t)list[n-1]) + string_start; 2242 } 2243 2244 #if ENABLE_HUSH_BRACE_EXPANSION 2245 /* There in a GNU extension, GLOB_BRACE, but it is not usable: 2246 * first, it processes even {a} (no commas), second, 2247 * I didn't manage to make it return strings when they don't match 2248 * existing files. Need to re-implement it. 2249 */ 2250 2251 /* Helper */ 2252 static int glob_needed(const char *s) 2253 { 2254 while (*s) { 2255 if (*s == '\\') { 2256 if (!s[1]) 2257 return 0; 2258 s += 2; 2259 continue; 2260 } 2261 if (*s == '*' || *s == '[' || *s == '?' || *s == '{') 2262 return 1; 2263 s++; 2264 } 2265 return 0; 2266 } 2267 /* Return pointer to next closing brace or to comma */ 2268 static const char *next_brace_sub(const char *cp) 2269 { 2270 unsigned depth = 0; 2271 cp++; 2272 while (*cp != '\0') { 2273 if (*cp == '\\') { 2274 if (*++cp == '\0') 2275 break; 2276 cp++; 2277 continue; 2278 } 2279 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) 2280 break; 2281 if (*cp++ == '{') 2282 depth++; 2283 } 2284 2285 return *cp != '\0' ? cp : NULL; 2286 } 2287 /* Recursive brace globber. Note: may garble pattern[]. */ 2288 static int glob_brace(char *pattern, o_string *o, int n) 2289 { 2290 char *new_pattern_buf; 2291 const char *begin; 2292 const char *next; 2293 const char *rest; 2294 const char *p; 2295 size_t rest_len; 2296 2297 debug_printf_glob("glob_brace('%s')\n", pattern); 2298 2299 begin = pattern; 2300 while (1) { 2301 if (*begin == '\0') 2302 goto simple_glob; 2303 if (*begin == '{') { 2304 /* Find the first sub-pattern and at the same time 2305 * find the rest after the closing brace */ 2306 next = next_brace_sub(begin); 2307 if (next == NULL) { 2308 /* An illegal expression */ 2309 goto simple_glob; 2310 } 2311 if (*next == '}') { 2312 /* "{abc}" with no commas - illegal 2313 * brace expr, disregard and skip it */ 2314 begin = next + 1; 2315 continue; 2316 } 2317 break; 2318 } 2319 if (*begin == '\\' && begin[1] != '\0') 2320 begin++; 2321 begin++; 2322 } 2323 debug_printf_glob("begin:%s\n", begin); 2324 debug_printf_glob("next:%s\n", next); 2325 2326 /* Now find the end of the whole brace expression */ 2327 rest = next; 2328 while (*rest != '}') { 2329 rest = next_brace_sub(rest); 2330 if (rest == NULL) { 2331 /* An illegal expression */ 2332 goto simple_glob; 2333 } 2334 debug_printf_glob("rest:%s\n", rest); 2335 } 2336 rest_len = strlen(++rest) + 1; 2337 2338 /* We are sure the brace expression is well-formed */ 2339 2340 /* Allocate working buffer large enough for our work */ 2341 new_pattern_buf = xmalloc(strlen(pattern)); 2342 2343 /* We have a brace expression. BEGIN points to the opening {, 2344 * NEXT points past the terminator of the first element, and REST 2345 * points past the final }. We will accumulate result names from 2346 * recursive runs for each brace alternative in the buffer using 2347 * GLOB_APPEND. */ 2348 2349 p = begin + 1; 2350 while (1) { 2351 /* Construct the new glob expression */ 2352 memcpy( 2353 mempcpy( 2354 mempcpy(new_pattern_buf, 2355 /* We know the prefix for all sub-patterns */ 2356 pattern, begin - pattern), 2357 p, next - p), 2358 rest, rest_len); 2359 2360 /* Note: glob_brace() may garble new_pattern_buf[]. 2361 * That's why we re-copy prefix every time (1st memcpy above). 2362 */ 2363 n = glob_brace(new_pattern_buf, o, n); 2364 if (*next == '}') { 2365 /* We saw the last entry */ 2366 break; 2367 } 2368 p = next + 1; 2369 next = next_brace_sub(next); 2370 } 2371 free(new_pattern_buf); 2372 return n; 2373 2374 simple_glob: 2375 { 2376 int gr; 2377 glob_t globdata; 2378 2379 memset(&globdata, 0, sizeof(globdata)); 2380 gr = glob(pattern, 0, NULL, &globdata); 2381 debug_printf_glob("glob('%s'):%d\n", pattern, gr); 2382 if (gr != 0) { 2383 if (gr == GLOB_NOMATCH) { 2384 globfree(&globdata); 2385 /* NB: garbles parameter */ 2386 unbackslash(pattern); 2387 o_addstr_with_NUL(o, pattern); 2388 debug_printf_glob("glob pattern '%s' is literal\n", pattern); 2389 return o_save_ptr_helper(o, n); 2390 } 2391 if (gr == GLOB_NOSPACE) 2392 bb_error_msg_and_die(bb_msg_memory_exhausted); 2393 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 2394 * but we didn't specify it. Paranoia again. */ 2395 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); 2396 } 2397 if (globdata.gl_pathv && globdata.gl_pathv[0]) { 2398 char **argv = globdata.gl_pathv; 2399 while (1) { 2400 o_addstr_with_NUL(o, *argv); 2401 n = o_save_ptr_helper(o, n); 2402 argv++; 2403 if (!*argv) 2404 break; 2405 } 2406 } 2407 globfree(&globdata); 2408 } 2409 return n; 2410 } 2411 /* Performs globbing on last list[], 2412 * saving each result as a new list[]. 2413 */ 2414 static int perform_glob(o_string *o, int n) 2415 { 2416 char *pattern, *copy; 2417 2418 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data); 2419 if (!o->data) 2420 return o_save_ptr_helper(o, n); 2421 pattern = o->data + o_get_last_ptr(o, n); 2422 debug_printf_glob("glob pattern '%s'\n", pattern); 2423 if (!glob_needed(pattern)) { 2424 /* unbackslash last string in o in place, fix length */ 2425 o->length = unbackslash(pattern) - o->data; 2426 debug_printf_glob("glob pattern '%s' is literal\n", pattern); 2427 return o_save_ptr_helper(o, n); 2428 } 2429 2430 copy = xstrdup(pattern); 2431 /* "forget" pattern in o */ 2432 o->length = pattern - o->data; 2433 n = glob_brace(copy, o, n); 2434 free(copy); 2435 if (DEBUG_GLOB) 2436 debug_print_list("perform_glob returning", o, n); 2437 return n; 2438 } 2439 2440 #else /* !HUSH_BRACE_EXPANSION */ 2441 2442 /* Helper */ 2443 static int glob_needed(const char *s) 2444 { 2445 while (*s) { 2446 if (*s == '\\') { 2447 if (!s[1]) 2448 return 0; 2449 s += 2; 2450 continue; 2451 } 2452 if (*s == '*' || *s == '[' || *s == '?') 2453 return 1; 2454 s++; 2455 } 2456 return 0; 2457 } 2458 /* Performs globbing on last list[], 2459 * saving each result as a new list[]. 2460 */ 2461 static int perform_glob(o_string *o, int n) 2462 { 2463 glob_t globdata; 2464 int gr; 2465 char *pattern; 2466 2467 debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data); 2468 if (!o->data) 2469 return o_save_ptr_helper(o, n); 2470 pattern = o->data + o_get_last_ptr(o, n); 2471 debug_printf_glob("glob pattern '%s'\n", pattern); 2472 if (!glob_needed(pattern)) { 2473 literal: 2474 /* unbackslash last string in o in place, fix length */ 2475 o->length = unbackslash(pattern) - o->data; 2476 debug_printf_glob("glob pattern '%s' is literal\n", pattern); 2477 return o_save_ptr_helper(o, n); 2478 } 2479 2480 memset(&globdata, 0, sizeof(globdata)); 2481 /* Can't use GLOB_NOCHECK: it does not unescape the string. 2482 * If we glob "*.\*" and don't find anything, we need 2483 * to fall back to using literal "*.*", but GLOB_NOCHECK 2484 * will return "*.\*"! 2485 */ 2486 gr = glob(pattern, 0, NULL, &globdata); 2487 debug_printf_glob("glob('%s'):%d\n", pattern, gr); 2488 if (gr != 0) { 2489 if (gr == GLOB_NOMATCH) { 2490 globfree(&globdata); 2491 goto literal; 2492 } 2493 if (gr == GLOB_NOSPACE) 2494 bb_error_msg_and_die(bb_msg_memory_exhausted); 2495 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 2496 * but we didn't specify it. Paranoia again. */ 2497 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); 2498 } 2499 if (globdata.gl_pathv && globdata.gl_pathv[0]) { 2500 char **argv = globdata.gl_pathv; 2501 /* "forget" pattern in o */ 2502 o->length = pattern - o->data; 2503 while (1) { 2504 o_addstr_with_NUL(o, *argv); 2505 n = o_save_ptr_helper(o, n); 2506 argv++; 2507 if (!*argv) 2508 break; 2509 } 2510 } 2511 globfree(&globdata); 2512 if (DEBUG_GLOB) 2513 debug_print_list("perform_glob returning", o, n); 2514 return n; 2515 } 2516 2517 #endif /* !HUSH_BRACE_EXPANSION */ 2518 2519 /* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered. 2520 * Otherwise, just finish current list[] and start new */ 2521 static int o_save_ptr(o_string *o, int n) 2522 { 2523 if (o->o_expflags & EXP_FLAG_GLOB) { 2524 /* If o->has_empty_slot, list[n] was already globbed 2525 * (if it was requested back then when it was filled) 2526 * so don't do that again! */ 2527 if (!o->has_empty_slot) 2528 return perform_glob(o, n); /* o_save_ptr_helper is inside */ 2529 } 2530 return o_save_ptr_helper(o, n); 2531 } 2532 2533 /* "Please convert list[n] to real char* ptrs, and NULL terminate it." */ 2534 static char **o_finalize_list(o_string *o, int n) 2535 { 2536 char **list; 2537 int string_start; 2538 2539 n = o_save_ptr(o, n); /* force growth for list[n] if necessary */ 2540 if (DEBUG_EXPAND) 2541 debug_print_list("finalized", o, n); 2542 debug_printf_expand("finalized n:%d\n", n); 2543 list = (char**)o->data; 2544 string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); 2545 list[--n] = NULL; 2546 while (n) { 2547 n--; 2548 list[n] = o->data + (int)(uintptr_t)list[n] + string_start; 2549 } 2550 return list; 2551 } 2552 2553 static void free_pipe_list(struct pipe *pi); 2554 2555 /* Returns pi->next - next pipe in the list */ 2556 static struct pipe *free_pipe(struct pipe *pi) 2557 { 2558 struct pipe *next; 2559 int i; 2560 2561 debug_printf_clean("free_pipe (pid %d)\n", getpid()); 2562 for (i = 0; i < pi->num_cmds; i++) { 2563 struct command *command; 2564 struct redir_struct *r, *rnext; 2565 2566 command = &pi->cmds[i]; 2567 debug_printf_clean(" command %d:\n", i); 2568 if (command->argv) { 2569 if (DEBUG_CLEAN) { 2570 int a; 2571 char **p; 2572 for (a = 0, p = command->argv; *p; a++, p++) { 2573 debug_printf_clean(" argv[%d] = %s\n", a, *p); 2574 } 2575 } 2576 free_strings(command->argv); 2577 //command->argv = NULL; 2578 } 2579 /* not "else if": on syntax error, we may have both! */ 2580 if (command->group) { 2581 debug_printf_clean(" begin group (cmd_type:%d)\n", 2582 command->cmd_type); 2583 free_pipe_list(command->group); 2584 debug_printf_clean(" end group\n"); 2585 //command->group = NULL; 2586 } 2587 /* else is crucial here. 2588 * If group != NULL, child_func is meaningless */ 2589 #if ENABLE_HUSH_FUNCTIONS 2590 else if (command->child_func) { 2591 debug_printf_exec("cmd %p releases child func at %p\n", command, command->child_func); 2592 command->child_func->parent_cmd = NULL; 2593 } 2594 #endif 2595 #if !BB_MMU 2596 free(command->group_as_string); 2597 //command->group_as_string = NULL; 2598 #endif 2599 for (r = command->redirects; r; r = rnext) { 2600 debug_printf_clean(" redirect %d%s", 2601 r->rd_fd, redir_table[r->rd_type].descrip); 2602 /* guard against the case >$FOO, where foo is unset or blank */ 2603 if (r->rd_filename) { 2604 debug_printf_clean(" fname:'%s'\n", r->rd_filename); 2605 free(r->rd_filename); 2606 //r->rd_filename = NULL; 2607 } 2608 debug_printf_clean(" rd_dup:%d\n", r->rd_dup); 2609 rnext = r->next; 2610 free(r); 2611 } 2612 //command->redirects = NULL; 2613 } 2614 free(pi->cmds); /* children are an array, they get freed all at once */ 2615 //pi->cmds = NULL; 2616 #if ENABLE_HUSH_JOB 2617 free(pi->cmdtext); 2618 //pi->cmdtext = NULL; 2619 #endif 2620 2621 next = pi->next; 2622 free(pi); 2623 return next; 2624 } 2625 2626 static void free_pipe_list(struct pipe *pi) 2627 { 2628 while (pi) { 2629 #if HAS_KEYWORDS 2630 debug_printf_clean("pipe reserved word %d\n", pi->res_word); 2631 #endif 2632 debug_printf_clean("pipe followup code %d\n", pi->followup); 2633 pi = free_pipe(pi); 2634 } 2635 } 2636 2637 2638 /*** Parsing routines ***/ 2639 2640 #ifndef debug_print_tree 2641 static void debug_print_tree(struct pipe *pi, int lvl) 2642 { 2643 static const char *const PIPE[] = { 2644 [PIPE_SEQ] = "SEQ", 2645 [PIPE_AND] = "AND", 2646 [PIPE_OR ] = "OR" , 2647 [PIPE_BG ] = "BG" , 2648 }; 2649 static const char *RES[] = { 2650 [RES_NONE ] = "NONE" , 2651 # if ENABLE_HUSH_IF 2652 [RES_IF ] = "IF" , 2653 [RES_THEN ] = "THEN" , 2654 [RES_ELIF ] = "ELIF" , 2655 [RES_ELSE ] = "ELSE" , 2656 [RES_FI ] = "FI" , 2657 # endif 2658 # if ENABLE_HUSH_LOOPS 2659 [RES_FOR ] = "FOR" , 2660 [RES_WHILE] = "WHILE", 2661 [RES_UNTIL] = "UNTIL", 2662 [RES_DO ] = "DO" , 2663 [RES_DONE ] = "DONE" , 2664 # endif 2665 # if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE 2666 [RES_IN ] = "IN" , 2667 # endif 2668 # if ENABLE_HUSH_CASE 2669 [RES_CASE ] = "CASE" , 2670 [RES_CASE_IN ] = "CASE_IN" , 2671 [RES_MATCH] = "MATCH", 2672 [RES_CASE_BODY] = "CASE_BODY", 2673 [RES_ESAC ] = "ESAC" , 2674 # endif 2675 [RES_XXXX ] = "XXXX" , 2676 [RES_SNTX ] = "SNTX" , 2677 }; 2678 static const char *const CMDTYPE[] = { 2679 "{}", 2680 "()", 2681 "[noglob]", 2682 # if ENABLE_HUSH_FUNCTIONS 2683 "func()", 2684 # endif 2685 }; 2686 2687 int pin, prn; 2688 2689 pin = 0; 2690 while (pi) { 2691 fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", 2692 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); 2693 prn = 0; 2694 while (prn < pi->num_cmds) { 2695 struct command *command = &pi->cmds[prn]; 2696 char **argv = command->argv; 2697 2698 fdprintf(2, "%*s cmd %d assignment_cnt:%d", 2699 lvl*2, "", prn, 2700 command->assignment_cnt); 2701 if (command->group) { 2702 fdprintf(2, " group %s: (argv=%p)%s%s\n", 2703 CMDTYPE[command->cmd_type], 2704 argv 2705 # if !BB_MMU 2706 , " group_as_string:", command->group_as_string 2707 # else 2708 , "", "" 2709 # endif 2710 ); 2711 debug_print_tree(command->group, lvl+1); 2712 prn++; 2713 continue; 2714 } 2715 if (argv) while (*argv) { 2716 fdprintf(2, " '%s'", *argv); 2717 argv++; 2718 } 2719 fdprintf(2, "\n"); 2720 prn++; 2721 } 2722 pi = pi->next; 2723 pin++; 2724 } 2725 } 2726 #endif /* debug_print_tree */ 2727 2728 static struct pipe *new_pipe(void) 2729 { 2730 struct pipe *pi; 2731 pi = xzalloc(sizeof(struct pipe)); 2732 /*pi->followup = 0; - deliberately invalid value */ 2733 /*pi->res_word = RES_NONE; - RES_NONE is 0 anyway */ 2734 return pi; 2735 } 2736 2737 /* Command (member of a pipe) is complete, or we start a new pipe 2738 * if ctx->command is NULL. 2739 * No errors possible here. 2740 */ 2741 static int done_command(struct parse_context *ctx) 2742 { 2743 /* The command is really already in the pipe structure, so 2744 * advance the pipe counter and make a new, null command. */ 2745 struct pipe *pi = ctx->pipe; 2746 struct command *command = ctx->command; 2747 2748 if (command) { 2749 if (IS_NULL_CMD(command)) { 2750 debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); 2751 goto clear_and_ret; 2752 } 2753 pi->num_cmds++; 2754 debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); 2755 //debug_print_tree(ctx->list_head, 20); 2756 } else { 2757 debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); 2758 } 2759 2760 /* Only real trickiness here is that the uncommitted 2761 * command structure is not counted in pi->num_cmds. */ 2762 pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); 2763 ctx->command = command = &pi->cmds[pi->num_cmds]; 2764 clear_and_ret: 2765 memset(command, 0, sizeof(*command)); 2766 return pi->num_cmds; /* used only for 0/nonzero check */ 2767 } 2768 2769 static void done_pipe(struct parse_context *ctx, pipe_style type) 2770 { 2771 int not_null; 2772 2773 debug_printf_parse("done_pipe entered, followup %d\n", type); 2774 /* Close previous command */ 2775 not_null = done_command(ctx); 2776 ctx->pipe->followup = type; 2777 #if HAS_KEYWORDS 2778 ctx->pipe->pi_inverted = ctx->ctx_inverted; 2779 ctx->ctx_inverted = 0; 2780 ctx->pipe->res_word = ctx->ctx_res_w; 2781 #endif 2782 2783 /* Without this check, even just <enter> on command line generates 2784 * tree of three NOPs (!). Which is harmless but annoying. 2785 * IOW: it is safe to do it unconditionally. */ 2786 if (not_null 2787 #if ENABLE_HUSH_IF 2788 || ctx->ctx_res_w == RES_FI 2789 #endif 2790 #if ENABLE_HUSH_LOOPS 2791 || ctx->ctx_res_w == RES_DONE 2792 || ctx->ctx_res_w == RES_FOR 2793 || ctx->ctx_res_w == RES_IN 2794 #endif 2795 #if ENABLE_HUSH_CASE 2796 || ctx->ctx_res_w == RES_ESAC 2797 #endif 2798 ) { 2799 struct pipe *new_p; 2800 debug_printf_parse("done_pipe: adding new pipe: " 2801 "not_null:%d ctx->ctx_res_w:%d\n", 2802 not_null, ctx->ctx_res_w); 2803 new_p = new_pipe(); 2804 ctx->pipe->next = new_p; 2805 ctx->pipe = new_p; 2806 /* RES_THEN, RES_DO etc are "sticky" - 2807 * they remain set for pipes inside if/while. 2808 * This is used to control execution. 2809 * RES_FOR and RES_IN are NOT sticky (needed to support 2810 * cases where variable or value happens to match a keyword): 2811 */ 2812 #if ENABLE_HUSH_LOOPS 2813 if (ctx->ctx_res_w == RES_FOR 2814 || ctx->ctx_res_w == RES_IN) 2815 ctx->ctx_res_w = RES_NONE; 2816 #endif 2817 #if ENABLE_HUSH_CASE 2818 if (ctx->ctx_res_w == RES_MATCH) 2819 ctx->ctx_res_w = RES_CASE_BODY; 2820 if (ctx->ctx_res_w == RES_CASE) 2821 ctx->ctx_res_w = RES_CASE_IN; 2822 #endif 2823 ctx->command = NULL; /* trick done_command below */ 2824 /* Create the memory for command, roughly: 2825 * ctx->pipe->cmds = new struct command; 2826 * ctx->command = &ctx->pipe->cmds[0]; 2827 */ 2828 done_command(ctx); 2829 //debug_print_tree(ctx->list_head, 10); 2830 } 2831 debug_printf_parse("done_pipe return\n"); 2832 } 2833 2834 static void initialize_context(struct parse_context *ctx) 2835 { 2836 memset(ctx, 0, sizeof(*ctx)); 2837 ctx->pipe = ctx->list_head = new_pipe(); 2838 /* Create the memory for command, roughly: 2839 * ctx->pipe->cmds = new struct command; 2840 * ctx->command = &ctx->pipe->cmds[0]; 2841 */ 2842 done_command(ctx); 2843 } 2844 2845 /* If a reserved word is found and processed, parse context is modified 2846 * and 1 is returned. 2847 */ 2848 #if HAS_KEYWORDS 2849 struct reserved_combo { 2850 char literal[6]; 2851 unsigned char res; 2852 unsigned char assignment_flag; 2853 int flag; 2854 }; 2855 enum { 2856 FLAG_END = (1 << RES_NONE ), 2857 # if ENABLE_HUSH_IF 2858 FLAG_IF = (1 << RES_IF ), 2859 FLAG_THEN = (1 << RES_THEN ), 2860 FLAG_ELIF = (1 << RES_ELIF ), 2861 FLAG_ELSE = (1 << RES_ELSE ), 2862 FLAG_FI = (1 << RES_FI ), 2863 # endif 2864 # if ENABLE_HUSH_LOOPS 2865 FLAG_FOR = (1 << RES_FOR ), 2866 FLAG_WHILE = (1 << RES_WHILE), 2867 FLAG_UNTIL = (1 << RES_UNTIL), 2868 FLAG_DO = (1 << RES_DO ), 2869 FLAG_DONE = (1 << RES_DONE ), 2870 FLAG_IN = (1 << RES_IN ), 2871 # endif 2872 # if ENABLE_HUSH_CASE 2873 FLAG_MATCH = (1 << RES_MATCH), 2874 FLAG_ESAC = (1 << RES_ESAC ), 2875 # endif 2876 FLAG_START = (1 << RES_XXXX ), 2877 }; 2878 2879 static const struct reserved_combo* match_reserved_word(o_string *word) 2880 { 2881 /* Mostly a list of accepted follow-up reserved words. 2882 * FLAG_END means we are done with the sequence, and are ready 2883 * to turn the compound list into a command. 2884 * FLAG_START means the word must start a new compound list. 2885 */ 2886 static const struct reserved_combo reserved_list[] = { 2887 # if ENABLE_HUSH_IF 2888 { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, 2889 { "if", RES_IF, WORD_IS_KEYWORD, FLAG_THEN | FLAG_START }, 2890 { "then", RES_THEN, WORD_IS_KEYWORD, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, 2891 { "elif", RES_ELIF, WORD_IS_KEYWORD, FLAG_THEN }, 2892 { "else", RES_ELSE, WORD_IS_KEYWORD, FLAG_FI }, 2893 { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, 2894 # endif 2895 # if ENABLE_HUSH_LOOPS 2896 { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, 2897 { "while", RES_WHILE, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, 2898 { "until", RES_UNTIL, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, 2899 { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, 2900 { "do", RES_DO, WORD_IS_KEYWORD, FLAG_DONE }, 2901 { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, 2902 # endif 2903 # if ENABLE_HUSH_CASE 2904 { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, 2905 { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, 2906 # endif 2907 }; 2908 const struct reserved_combo *r; 2909 2910 for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) { 2911 if (strcmp(word->data, r->literal) == 0) 2912 return r; 2913 } 2914 return NULL; 2915 } 2916 /* Return 0: not a keyword, 1: keyword 2917 */ 2918 static int reserved_word(o_string *word, struct parse_context *ctx) 2919 { 2920 # if ENABLE_HUSH_CASE 2921 static const struct reserved_combo reserved_match = { 2922 "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC 2923 }; 2924 # endif 2925 const struct reserved_combo *r; 2926 2927 if (word->has_quoted_part) 2928 return 0; 2929 r = match_reserved_word(word); 2930 if (!r) 2931 return 0; 2932 2933 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 2934 # if ENABLE_HUSH_CASE 2935 if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) { 2936 /* "case word IN ..." - IN part starts first MATCH part */ 2937 r = &reserved_match; 2938 } else 2939 # endif 2940 if (r->flag == 0) { /* '!' */ 2941 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ 2942 syntax_error("! ! command"); 2943 ctx->ctx_res_w = RES_SNTX; 2944 } 2945 ctx->ctx_inverted = 1; 2946 return 1; 2947 } 2948 if (r->flag & FLAG_START) { 2949 struct parse_context *old; 2950 2951 old = xmalloc(sizeof(*old)); 2952 debug_printf_parse("push stack %p\n", old); 2953 *old = *ctx; /* physical copy */ 2954 initialize_context(ctx); 2955 ctx->stack = old; 2956 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { 2957 syntax_error_at(word->data); 2958 ctx->ctx_res_w = RES_SNTX; 2959 return 1; 2960 } else { 2961 /* "{...} fi" is ok. "{...} if" is not 2962 * Example: 2963 * if { echo foo; } then { echo bar; } fi */ 2964 if (ctx->command->group) 2965 done_pipe(ctx, PIPE_SEQ); 2966 } 2967 2968 ctx->ctx_res_w = r->res; 2969 ctx->old_flag = r->flag; 2970 word->o_assignment = r->assignment_flag; 2971 2972 if (ctx->old_flag & FLAG_END) { 2973 struct parse_context *old; 2974 2975 done_pipe(ctx, PIPE_SEQ); 2976 debug_printf_parse("pop stack %p\n", ctx->stack); 2977 old = ctx->stack; 2978 old->command->group = ctx->list_head; 2979 old->command->cmd_type = CMD_NORMAL; 2980 # if !BB_MMU 2981 o_addstr(&old->as_string, ctx->as_string.data); 2982 o_free_unsafe(&ctx->as_string); 2983 old->command->group_as_string = xstrdup(old->as_string.data); 2984 debug_printf_parse("pop, remembering as:'%s'\n", 2985 old->command->group_as_string); 2986 # endif 2987 *ctx = *old; /* physical copy */ 2988 free(old); 2989 } 2990 return 1; 2991 } 2992 #endif /* HAS_KEYWORDS */ 2993 2994 /* Word is complete, look at it and update parsing context. 2995 * Normal return is 0. Syntax errors return 1. 2996 * Note: on return, word is reset, but not o_free'd! 2997 */ 2998 static int done_word(o_string *word, struct parse_context *ctx) 2999 { 3000 struct command *command = ctx->command; 3001 3002 debug_printf_parse("done_word entered: '%s' %p\n", word->data, command); 3003 if (word->length == 0 && !word->has_quoted_part) { 3004 debug_printf_parse("done_word return 0: true null, ignored\n"); 3005 return 0; 3006 } 3007 3008 if (ctx->pending_redirect) { 3009 /* We do not glob in e.g. >*.tmp case. bash seems to glob here 3010 * only if run as "bash", not "sh" */ 3011 /* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 3012 * "2.7 Redirection 3013 * ...the word that follows the redirection operator 3014 * shall be subjected to tilde expansion, parameter expansion, 3015 * command substitution, arithmetic expansion, and quote 3016 * removal. Pathname expansion shall not be performed 3017 * on the word by a non-interactive shell; an interactive 3018 * shell may perform it, but shall do so only when 3019 * the expansion would result in one word." 3020 */ 3021 ctx->pending_redirect->rd_filename = xstrdup(word->data); 3022 /* Cater for >\file case: 3023 * >\a creates file a; >\\a, >"\a", >"\\a" create file \a 3024 * Same with heredocs: 3025 * for <<\H delim is H; <<\\H, <<"\H", <<"\\H" - \H 3026 */ 3027 if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) { 3028 unbackslash(ctx->pending_redirect->rd_filename); 3029 /* Is it <<"HEREDOC"? */ 3030 if (word->has_quoted_part) { 3031 ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; 3032 } 3033 } 3034 debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); 3035 ctx->pending_redirect = NULL; 3036 } else { 3037 /* If this word wasn't an assignment, next ones definitely 3038 * can't be assignments. Even if they look like ones. */ 3039 if (word->o_assignment != DEFINITELY_ASSIGNMENT 3040 && word->o_assignment != WORD_IS_KEYWORD 3041 ) { 3042 word->o_assignment = NOT_ASSIGNMENT; 3043 } else { 3044 if (word->o_assignment == DEFINITELY_ASSIGNMENT) 3045 command->assignment_cnt++; 3046 word->o_assignment = MAYBE_ASSIGNMENT; 3047 } 3048 3049 #if HAS_KEYWORDS 3050 # if ENABLE_HUSH_CASE 3051 if (ctx->ctx_dsemicolon 3052 && strcmp(word->data, "esac") != 0 /* not "... pattern) cmd;; esac" */ 3053 ) { 3054 /* already done when ctx_dsemicolon was set to 1: */ 3055 /* ctx->ctx_res_w = RES_MATCH; */ 3056 ctx->ctx_dsemicolon = 0; 3057 } else 3058 # endif 3059 if (!command->argv /* if it's the first word... */ 3060 # if ENABLE_HUSH_LOOPS 3061 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ 3062 && ctx->ctx_res_w != RES_IN 3063 # endif 3064 # if ENABLE_HUSH_CASE 3065 && ctx->ctx_res_w != RES_CASE 3066 # endif 3067 ) { 3068 debug_printf_parse("checking '%s' for reserved-ness\n", word->data); 3069 if (reserved_word(word, ctx)) { 3070 o_reset_to_empty_unquoted(word); 3071 debug_printf_parse("done_word return %d\n", 3072 (ctx->ctx_res_w == RES_SNTX)); 3073 return (ctx->ctx_res_w == RES_SNTX); 3074 } 3075 # if ENABLE_HUSH_BASH_COMPAT 3076 if (strcmp(word->data, "[[") == 0) { 3077 command->cmd_type = CMD_SINGLEWORD_NOGLOB; 3078 } 3079 /* fall through */ 3080 # endif 3081 } 3082 #endif 3083 if (command->group) { 3084 /* "{ echo foo; } echo bar" - bad */ 3085 syntax_error_at(word->data); 3086 debug_printf_parse("done_word return 1: syntax error, " 3087 "groups and arglists don't mix\n"); 3088 return 1; 3089 } 3090 if (word->has_quoted_part 3091 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ 3092 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) 3093 /* (otherwise it's known to be not empty and is already safe) */ 3094 ) { 3095 /* exclude "$@" - it can expand to no word despite "" */ 3096 char *p = word->data; 3097 while (p[0] == SPECIAL_VAR_SYMBOL 3098 && (p[1] & 0x7f) == '@' 3099 && p[2] == SPECIAL_VAR_SYMBOL 3100 ) { 3101 p += 3; 3102 } 3103 if (p == word->data || p[0] != '\0') { 3104 /* saw no "$@", or not only "$@" but some 3105 * real text is there too */ 3106 /* insert "empty variable" reference, this makes 3107 * e.g. "", $empty"" etc to not disappear */ 3108 o_addchr(word, SPECIAL_VAR_SYMBOL); 3109 o_addchr(word, SPECIAL_VAR_SYMBOL); 3110 } 3111 } 3112 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); 3113 debug_print_strings("word appended to argv", command->argv); 3114 } 3115 3116 #if ENABLE_HUSH_LOOPS 3117 if (ctx->ctx_res_w == RES_FOR) { 3118 if (word->has_quoted_part 3119 || !is_well_formed_var_name(command->argv[0], '\0') 3120 ) { 3121 /* bash says just "not a valid identifier" */ 3122 syntax_error("not a valid identifier in for"); 3123 return 1; 3124 } 3125 /* Force FOR to have just one word (variable name) */ 3126 /* NB: basically, this makes hush see "for v in ..." 3127 * syntax as if it is "for v; in ...". FOR and IN become 3128 * two pipe structs in parse tree. */ 3129 done_pipe(ctx, PIPE_SEQ); 3130 } 3131 #endif 3132 #if ENABLE_HUSH_CASE 3133 /* Force CASE to have just one word */ 3134 if (ctx->ctx_res_w == RES_CASE) { 3135 done_pipe(ctx, PIPE_SEQ); 3136 } 3137 #endif 3138 3139 o_reset_to_empty_unquoted(word); 3140 3141 debug_printf_parse("done_word return 0\n"); 3142 return 0; 3143 } 3144 3145 3146 /* Peek ahead in the input to find out if we have a "&n" construct, 3147 * as in "2>&1", that represents duplicating a file descriptor. 3148 * Return: 3149 * REDIRFD_CLOSE if >&- "close fd" construct is seen, 3150 * REDIRFD_SYNTAX_ERR if syntax error, 3151 * REDIRFD_TO_FILE if no & was seen, 3152 * or the number found. 3153 */ 3154 #if BB_MMU 3155 #define parse_redir_right_fd(as_string, input) \ 3156 parse_redir_right_fd(input) 3157 #endif 3158 static int parse_redir_right_fd(o_string *as_string, struct in_str *input) 3159 { 3160 int ch, d, ok; 3161 3162 ch = i_peek(input); 3163 if (ch != '&') 3164 return REDIRFD_TO_FILE; 3165 3166 ch = i_getch(input); /* get the & */ 3167 nommu_addchr(as_string, ch); 3168 ch = i_peek(input); 3169 if (ch == '-') { 3170 ch = i_getch(input); 3171 nommu_addchr(as_string, ch); 3172 return REDIRFD_CLOSE; 3173 } 3174 d = 0; 3175 ok = 0; 3176 while (ch != EOF && isdigit(ch)) { 3177 d = d*10 + (ch-'0'); 3178 ok = 1; 3179 ch = i_getch(input); 3180 nommu_addchr(as_string, ch); 3181 ch = i_peek(input); 3182 } 3183 if (ok) return d; 3184 3185 //TODO: this is the place to catch ">&file" bashism (redirect both fd 1 and 2) 3186 3187 bb_error_msg("ambiguous redirect"); 3188 return REDIRFD_SYNTAX_ERR; 3189 } 3190 3191 /* Return code is 0 normal, 1 if a syntax error is detected 3192 */ 3193 static int parse_redirect(struct parse_context *ctx, 3194 int fd, 3195 redir_type style, 3196 struct in_str *input) 3197 { 3198 struct command *command = ctx->command; 3199 struct redir_struct *redir; 3200 struct redir_struct **redirp; 3201 int dup_num; 3202 3203 dup_num = REDIRFD_TO_FILE; 3204 if (style != REDIRECT_HEREDOC) { 3205 /* Check for a '>&1' type redirect */ 3206 dup_num = parse_redir_right_fd(&ctx->as_string, input); 3207 if (dup_num == REDIRFD_SYNTAX_ERR) 3208 return 1; 3209 } else { 3210 int ch = i_peek(input); 3211 dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ 3212 if (dup_num) { /* <<-... */ 3213 ch = i_getch(input); 3214 nommu_addchr(&ctx->as_string, ch); 3215 ch = i_peek(input); 3216 } 3217 } 3218 3219 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) { 3220 int ch = i_peek(input); 3221 if (ch == '|') { 3222 /* >|FILE redirect ("clobbering" >). 3223 * Since we do not support "set -o noclobber" yet, 3224 * >| and > are the same for now. Just eat |. 3225 */ 3226 ch = i_getch(input); 3227 nommu_addchr(&ctx->as_string, ch); 3228 } 3229 } 3230 3231 /* Create a new redir_struct and append it to the linked list */ 3232 redirp = &command->redirects; 3233 while ((redir = *redirp) != NULL) { 3234 redirp = &(redir->next); 3235 } 3236 *redirp = redir = xzalloc(sizeof(*redir)); 3237 /* redir->next = NULL; */ 3238 /* redir->rd_filename = NULL; */ 3239 redir->rd_type = style; 3240 redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd; 3241 3242 debug_printf_parse("redirect type %d %s\n", redir->rd_fd, 3243 redir_table[style].descrip); 3244 3245 redir->rd_dup = dup_num; 3246 if (style != REDIRECT_HEREDOC && dup_num != REDIRFD_TO_FILE) { 3247 /* Erik had a check here that the file descriptor in question 3248 * is legit; I postpone that to "run time" 3249 * A "-" representation of "close me" shows up as a -3 here */ 3250 debug_printf_parse("duplicating redirect '%d>&%d'\n", 3251 redir->rd_fd, redir->rd_dup); 3252 } else { 3253 /* Set ctx->pending_redirect, so we know what to do at the 3254 * end of the next parsed word. */ 3255 ctx->pending_redirect = redir; 3256 } 3257 return 0; 3258 } 3259 3260 /* If a redirect is immediately preceded by a number, that number is 3261 * supposed to tell which file descriptor to redirect. This routine 3262 * looks for such preceding numbers. In an ideal world this routine 3263 * needs to handle all the following classes of redirects... 3264 * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo 3265 * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo 3266 * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo 3267 * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo 3268 * 3269 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 3270 * "2.7 Redirection 3271 * ... If n is quoted, the number shall not be recognized as part of 3272 * the redirection expression. For example: 3273 * echo \2>a 3274 * writes the character 2 into file a" 3275 * We are getting it right by setting ->has_quoted_part on any \<char> 3276 * 3277 * A -1 return means no valid number was found, 3278 * the caller should use the appropriate default for this redirection. 3279 */ 3280 static int redirect_opt_num(o_string *o) 3281 { 3282 int num; 3283 3284 if (o->data == NULL) 3285 return -1; 3286 num = bb_strtou(o->data, NULL, 10); 3287 if (errno || num < 0) 3288 return -1; 3289 o_reset_to_empty_unquoted(o); 3290 return num; 3291 } 3292 3293 #if BB_MMU 3294 #define fetch_till_str(as_string, input, word, skip_tabs) \ 3295 fetch_till_str(input, word, skip_tabs) 3296 #endif 3297 static char *fetch_till_str(o_string *as_string, 3298 struct in_str *input, 3299 const char *word, 3300 int heredoc_flags) 3301 { 3302 o_string heredoc = NULL_O_STRING; 3303 unsigned past_EOL; 3304 int prev = 0; /* not \ */ 3305 int ch; 3306 3307 goto jump_in; 3308 while (1) { 3309 ch = i_getch(input); 3310 if (ch != EOF) 3311 nommu_addchr(as_string, ch); 3312 if ((ch == '\n' || ch == EOF) 3313 && ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') 3314 ) { 3315 if (strcmp(heredoc.data + past_EOL, word) == 0) { 3316 heredoc.data[past_EOL] = '\0'; 3317 debug_printf_parse("parsed heredoc '%s'\n", heredoc.data); 3318 return heredoc.data; 3319 } 3320 while (ch == '\n') { 3321 o_addchr(&heredoc, ch); 3322 prev = ch; 3323 jump_in: 3324 past_EOL = heredoc.length; 3325 do { 3326 ch = i_getch(input); 3327 if (ch != EOF) 3328 nommu_addchr(as_string, ch); 3329 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t'); 3330 } 3331 } 3332 if (ch == EOF) { 3333 o_free_unsafe(&heredoc); 3334 return NULL; 3335 } 3336 o_addchr(&heredoc, ch); 3337 nommu_addchr(as_string, ch); 3338 if (prev == '\\' && ch == '\\') 3339 /* Correctly handle foo\\<eol> (not a line cont.) */ 3340 prev = 0; /* not \ */ 3341 else 3342 prev = ch; 3343 } 3344 } 3345 3346 /* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs 3347 * and load them all. There should be exactly heredoc_cnt of them. 3348 */ 3349 static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_str *input) 3350 { 3351 struct pipe *pi = ctx->list_head; 3352 3353 while (pi && heredoc_cnt) { 3354 int i; 3355 struct command *cmd = pi->cmds; 3356 3357 debug_printf_parse("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n", 3358 pi->num_cmds, 3359 cmd->argv ? cmd->argv[0] : "NONE"); 3360 for (i = 0; i < pi->num_cmds; i++) { 3361 struct redir_struct *redir = cmd->redirects; 3362 3363 debug_printf_parse("fetch_heredocs: %d cmd argv0:'%s'\n", 3364 i, cmd->argv ? cmd->argv[0] : "NONE"); 3365 while (redir) { 3366 if (redir->rd_type == REDIRECT_HEREDOC) { 3367 char *p; 3368 3369 redir->rd_type = REDIRECT_HEREDOC2; 3370 /* redir->rd_dup is (ab)used to indicate <<- */ 3371 p = fetch_till_str(&ctx->as_string, input, 3372 redir->rd_filename, redir->rd_dup); 3373 if (!p) { 3374 syntax_error("unexpected EOF in here document"); 3375 return 1; 3376 } 3377 free(redir->rd_filename); 3378 redir->rd_filename = p; 3379 heredoc_cnt--; 3380 } 3381 redir = redir->next; 3382 } 3383 cmd++; 3384 } 3385 pi = pi->next; 3386 } 3387 #if 0 3388 /* Should be 0. If it isn't, it's a parse error */ 3389 if (heredoc_cnt) 3390 bb_error_msg_and_die("heredoc BUG 2"); 3391 #endif 3392 return 0; 3393 } 3394 3395 3396 static int run_list(struct pipe *pi); 3397 #if BB_MMU 3398 #define parse_stream(pstring, input, end_trigger) \ 3399 parse_stream(input, end_trigger) 3400 #endif 3401 static struct pipe *parse_stream(char **pstring, 3402 struct in_str *input, 3403 int end_trigger); 3404 3405 3406 #if !ENABLE_HUSH_FUNCTIONS 3407 #define parse_group(dest, ctx, input, ch) \ 3408 parse_group(ctx, input, ch) 3409 #endif 3410 static int parse_group(o_string *dest, struct parse_context *ctx, 3411 struct in_str *input, int ch) 3412 { 3413 /* dest contains characters seen prior to ( or {. 3414 * Typically it's empty, but for function defs, 3415 * it contains function name (without '()'). */ 3416 struct pipe *pipe_list; 3417 int endch; 3418 struct command *command = ctx->command; 3419 3420 debug_printf_parse("parse_group entered\n"); 3421 #if ENABLE_HUSH_FUNCTIONS 3422 if (ch == '(' && !dest->has_quoted_part) { 3423 if (dest->length) 3424 if (done_word(dest, ctx)) 3425 return 1; 3426 if (!command->argv) 3427 goto skip; /* (... */ 3428 if (command->argv[1]) { /* word word ... (... */ 3429 syntax_error_unexpected_ch('('); 3430 return 1; 3431 } 3432 /* it is "word(..." or "word (..." */ 3433 do 3434 ch = i_getch(input); 3435 while (ch == ' ' || ch == '\t'); 3436 if (ch != ')') { 3437 syntax_error_unexpected_ch(ch); 3438 return 1; 3439 } 3440 nommu_addchr(&ctx->as_string, ch); 3441 do 3442 ch = i_getch(input); 3443 while (ch == ' ' || ch == '\t' || ch == '\n'); 3444 if (ch != '{') { 3445 syntax_error_unexpected_ch(ch); 3446 return 1; 3447 } 3448 nommu_addchr(&ctx->as_string, ch); 3449 command->cmd_type = CMD_FUNCDEF; 3450 goto skip; 3451 } 3452 #endif 3453 3454 #if 0 /* Prevented by caller */ 3455 if (command->argv /* word [word]{... */ 3456 || dest->length /* word{... */ 3457 || dest->has_quoted_part /* ""{... */ 3458 ) { 3459 syntax_error(NULL); 3460 debug_printf_parse("parse_group return 1: " 3461 "syntax error, groups and arglists don't mix\n"); 3462 return 1; 3463 } 3464 #endif 3465 3466 #if ENABLE_HUSH_FUNCTIONS 3467 skip: 3468 #endif 3469 endch = '}'; 3470 if (ch == '(') { 3471 endch = ')'; 3472 command->cmd_type = CMD_SUBSHELL; 3473 } else { 3474 /* bash does not allow "{echo...", requires whitespace */ 3475 ch = i_getch(input); 3476 if (ch != ' ' && ch != '\t' && ch != '\n') { 3477 syntax_error_unexpected_ch(ch); 3478 return 1; 3479 } 3480 nommu_addchr(&ctx->as_string, ch); 3481 } 3482 3483 { 3484 #if BB_MMU 3485 # define as_string NULL 3486 #else 3487 char *as_string = NULL; 3488 #endif 3489 pipe_list = parse_stream(&as_string, input, endch); 3490 #if !BB_MMU 3491 if (as_string) 3492 o_addstr(&ctx->as_string, as_string); 3493 #endif 3494 /* empty ()/{} or parse error? */ 3495 if (!pipe_list || pipe_list == ERR_PTR) { 3496 /* parse_stream already emitted error msg */ 3497 if (!BB_MMU) 3498 free(as_string); 3499 debug_printf_parse("parse_group return 1: " 3500 "parse_stream returned %p\n", pipe_list); 3501 return 1; 3502 } 3503 command->group = pipe_list; 3504 #if !BB_MMU 3505 as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */ 3506 command->group_as_string = as_string; 3507 debug_printf_parse("end of group, remembering as:'%s'\n", 3508 command->group_as_string); 3509 #endif 3510 #undef as_string 3511 } 3512 debug_printf_parse("parse_group return 0\n"); 3513 return 0; 3514 /* command remains "open", available for possible redirects */ 3515 } 3516 3517 #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS 3518 /* Subroutines for copying $(...) and `...` things */ 3519 static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 3520 /* '...' */ 3521 static void add_till_single_quote(o_string *dest, struct in_str *input) 3522 { 3523 while (1) { 3524 int ch = i_getch(input); 3525 if (ch == EOF) { 3526 syntax_error_unterm_ch('\''); 3527 /*xfunc_die(); - redundant */ 3528 } 3529 if (ch == '\'') 3530 return; 3531 o_addchr(dest, ch); 3532 } 3533 } 3534 /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ 3535 static void add_till_double_quote(o_string *dest, struct in_str *input) 3536 { 3537 while (1) { 3538 int ch = i_getch(input); 3539 if (ch == EOF) { 3540 syntax_error_unterm_ch('"'); 3541 /*xfunc_die(); - redundant */ 3542 } 3543 if (ch == '"') 3544 return; 3545 if (ch == '\\') { /* \x. Copy both chars. */ 3546 o_addchr(dest, ch); 3547 ch = i_getch(input); 3548 } 3549 o_addchr(dest, ch); 3550 if (ch == '`') { 3551 add_till_backquote(dest, input, /*in_dquote:*/ 1); 3552 o_addchr(dest, ch); 3553 continue; 3554 } 3555 //if (ch == '$') ... 3556 } 3557 } 3558 /* Process `cmd` - copy contents until "`" is seen. Complicated by 3559 * \` quoting. 3560 * "Within the backquoted style of command substitution, backslash 3561 * shall retain its literal meaning, except when followed by: '$', '`', or '\'. 3562 * The search for the matching backquote shall be satisfied by the first 3563 * backquote found without a preceding backslash; during this search, 3564 * if a non-escaped backquote is encountered within a shell comment, 3565 * a here-document, an embedded command substitution of the $(command) 3566 * form, or a quoted string, undefined results occur. A single-quoted 3567 * or double-quoted string that begins, but does not end, within the 3568 * "`...`" sequence produces undefined results." 3569 * Example Output 3570 * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST 3571 */ 3572 static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) 3573 { 3574 while (1) { 3575 int ch = i_getch(input); 3576 if (ch == '`') 3577 return; 3578 if (ch == '\\') { 3579 /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ 3580 ch = i_getch(input); 3581 if (ch != '`' 3582 && ch != '$' 3583 && ch != '\\' 3584 && (!in_dquote || ch != '"') 3585 ) { 3586 o_addchr(dest, '\\'); 3587 } 3588 } 3589 if (ch == EOF) { 3590 syntax_error_unterm_ch('`'); 3591 /*xfunc_die(); - redundant */ 3592 } 3593 o_addchr(dest, ch); 3594 } 3595 } 3596 /* Process $(cmd) - copy contents until ")" is seen. Complicated by 3597 * quoting and nested ()s. 3598 * "With the $(command) style of command substitution, all characters 3599 * following the open parenthesis to the matching closing parenthesis 3600 * constitute the command. Any valid shell script can be used for command, 3601 * except a script consisting solely of redirections which produces 3602 * unspecified results." 3603 * Example Output 3604 * echo $(echo '(TEST)' BEST) (TEST) BEST 3605 * echo $(echo 'TEST)' BEST) TEST) BEST 3606 * echo $(echo \(\(TEST\) BEST) ((TEST) BEST 3607 * 3608 * Also adapted to eat ${var%...} and $((...)) constructs, since ... part 3609 * can contain arbitrary constructs, just like $(cmd). 3610 * In bash compat mode, it needs to also be able to stop on ':' or '/' 3611 * for ${var:N[:M]} and ${var/P[/R]} parsing. 3612 */ 3613 #define DOUBLE_CLOSE_CHAR_FLAG 0x80 3614 static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsigned end_ch) 3615 { 3616 int ch; 3617 char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; 3618 # if ENABLE_HUSH_BASH_COMPAT 3619 char end_char2 = end_ch >> 8; 3620 # endif 3621 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); 3622 3623 while (1) { 3624 ch = i_getch(input); 3625 if (ch == EOF) { 3626 syntax_error_unterm_ch(end_ch); 3627 /*xfunc_die(); - redundant */ 3628 } 3629 if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { 3630 if (!dbl) 3631 break; 3632 /* we look for closing )) of $((EXPR)) */ 3633 if (i_peek(input) == end_ch) { 3634 i_getch(input); /* eat second ')' */ 3635 break; 3636 } 3637 } 3638 o_addchr(dest, ch); 3639 if (ch == '(' || ch == '{') { 3640 ch = (ch == '(' ? ')' : '}'); 3641 add_till_closing_bracket(dest, input, ch); 3642 o_addchr(dest, ch); 3643 continue; 3644 } 3645 if (ch == '\'') { 3646 add_till_single_quote(dest, input); 3647 o_addchr(dest, ch); 3648 continue; 3649 } 3650 if (ch == '"') { 3651 add_till_double_quote(dest, input); 3652 o_addchr(dest, ch); 3653 continue; 3654 } 3655 if (ch == '`') { 3656 add_till_backquote(dest, input, /*in_dquote:*/ 0); 3657 o_addchr(dest, ch); 3658 continue; 3659 } 3660 if (ch == '\\') { 3661 /* \x. Copy verbatim. Important for \(, \) */ 3662 ch = i_getch(input); 3663 if (ch == EOF) { 3664 syntax_error_unterm_ch(')'); 3665 /*xfunc_die(); - redundant */ 3666 } 3667 o_addchr(dest, ch); 3668 continue; 3669 } 3670 } 3671 return ch; 3672 } 3673 #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS */ 3674 3675 /* Return code: 0 for OK, 1 for syntax error */ 3676 #if BB_MMU 3677 #define parse_dollar(as_string, dest, input, quote_mask) \ 3678 parse_dollar(dest, input, quote_mask) 3679 #define as_string NULL 3680 #endif 3681 static int parse_dollar(o_string *as_string, 3682 o_string *dest, 3683 struct in_str *input, unsigned char quote_mask) 3684 { 3685 int ch = i_peek(input); /* first character after the $ */ 3686 3687 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); 3688 if (isalpha(ch)) { 3689 ch = i_getch(input); 3690 nommu_addchr(as_string, ch); 3691 make_var: 3692 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3693 while (1) { 3694 debug_printf_parse(": '%c'\n", ch); 3695 o_addchr(dest, ch | quote_mask); 3696 quote_mask = 0; 3697 ch = i_peek(input); 3698 if (!isalnum(ch) && ch != '_') 3699 break; 3700 ch = i_getch(input); 3701 nommu_addchr(as_string, ch); 3702 } 3703 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3704 } else if (isdigit(ch)) { 3705 make_one_char_var: 3706 ch = i_getch(input); 3707 nommu_addchr(as_string, ch); 3708 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3709 debug_printf_parse(": '%c'\n", ch); 3710 o_addchr(dest, ch | quote_mask); 3711 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3712 } else switch (ch) { 3713 case '$': /* pid */ 3714 case '!': /* last bg pid */ 3715 case '?': /* last exit code */ 3716 case '#': /* number of args */ 3717 case '*': /* args */ 3718 case '@': /* args */ 3719 goto make_one_char_var; 3720 case '{': { 3721 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3722 3723 ch = i_getch(input); /* eat '{' */ 3724 nommu_addchr(as_string, ch); 3725 3726 ch = i_getch(input); /* first char after '{' */ 3727 /* It should be ${?}, or ${#var}, 3728 * or even ${?+subst} - operator acting on a special variable, 3729 * or the beginning of variable name. 3730 */ 3731 if (ch == EOF 3732 || (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch)) /* not one of those */ 3733 ) { 3734 bad_dollar_syntax: 3735 syntax_error_unterm_str("${name}"); 3736 debug_printf_parse("parse_dollar return 1: unterminated ${name}\n"); 3737 return 1; 3738 } 3739 nommu_addchr(as_string, ch); 3740 ch |= quote_mask; 3741 3742 /* It's possible to just call add_till_closing_bracket() at this point. 3743 * However, this regresses some of our testsuite cases 3744 * which check invalid constructs like ${%}. 3745 * Oh well... let's check that the var name part is fine... */ 3746 3747 while (1) { 3748 unsigned pos; 3749 3750 o_addchr(dest, ch); 3751 debug_printf_parse(": '%c'\n", ch); 3752 3753 ch = i_getch(input); 3754 nommu_addchr(as_string, ch); 3755 if (ch == '}') 3756 break; 3757 3758 if (!isalnum(ch) && ch != '_') { 3759 unsigned end_ch; 3760 unsigned char last_ch; 3761 /* handle parameter expansions 3762 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 3763 */ 3764 if (!strchr(VAR_SUBST_OPS, ch)) /* ${var<bad_char>... */ 3765 goto bad_dollar_syntax; 3766 3767 /* Eat everything until closing '}' (or ':') */ 3768 end_ch = '}'; 3769 if (ENABLE_HUSH_BASH_COMPAT 3770 && ch == ':' 3771 && !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input)) 3772 ) { 3773 /* It's ${var:N[:M]} thing */ 3774 end_ch = '}' * 0x100 + ':'; 3775 } 3776 if (ENABLE_HUSH_BASH_COMPAT 3777 && ch == '/' 3778 ) { 3779 /* It's ${var/[/]pattern[/repl]} thing */ 3780 if (i_peek(input) == '/') { /* ${var//pattern[/repl]}? */ 3781 i_getch(input); 3782 nommu_addchr(as_string, '/'); 3783 ch = '\\'; 3784 } 3785 end_ch = '}' * 0x100 + '/'; 3786 } 3787 o_addchr(dest, ch); 3788 again: 3789 if (!BB_MMU) 3790 pos = dest->length; 3791 #if ENABLE_HUSH_DOLLAR_OPS 3792 last_ch = add_till_closing_bracket(dest, input, end_ch); 3793 #else 3794 #error Simple code to only allow ${var} is not implemented 3795 #endif 3796 if (as_string) { 3797 o_addstr(as_string, dest->data + pos); 3798 o_addchr(as_string, last_ch); 3799 } 3800 3801 if (ENABLE_HUSH_BASH_COMPAT && (end_ch & 0xff00)) { 3802 /* close the first block: */ 3803 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3804 /* while parsing N from ${var:N[:M]} 3805 * or pattern from ${var/[/]pattern[/repl]} */ 3806 if ((end_ch & 0xff) == last_ch) { 3807 /* got ':' or '/'- parse the rest */ 3808 end_ch = '}'; 3809 goto again; 3810 } 3811 /* got '}' */ 3812 if (end_ch == '}' * 0x100 + ':') { 3813 /* it's ${var:N} - emulate :999999999 */ 3814 o_addstr(dest, "999999999"); 3815 } /* else: it's ${var/[/]pattern} */ 3816 } 3817 break; 3818 } 3819 } 3820 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3821 break; 3822 } 3823 #if ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_TICK 3824 case '(': { 3825 unsigned pos; 3826 3827 ch = i_getch(input); 3828 nommu_addchr(as_string, ch); 3829 # if ENABLE_SH_MATH_SUPPORT 3830 if (i_peek(input) == '(') { 3831 ch = i_getch(input); 3832 nommu_addchr(as_string, ch); 3833 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3834 o_addchr(dest, /*quote_mask |*/ '+'); 3835 if (!BB_MMU) 3836 pos = dest->length; 3837 add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); 3838 if (as_string) { 3839 o_addstr(as_string, dest->data + pos); 3840 o_addchr(as_string, ')'); 3841 o_addchr(as_string, ')'); 3842 } 3843 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3844 break; 3845 } 3846 # endif 3847 # if ENABLE_HUSH_TICK 3848 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3849 o_addchr(dest, quote_mask | '`'); 3850 if (!BB_MMU) 3851 pos = dest->length; 3852 add_till_closing_bracket(dest, input, ')'); 3853 if (as_string) { 3854 o_addstr(as_string, dest->data + pos); 3855 o_addchr(as_string, ')'); 3856 } 3857 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3858 # endif 3859 break; 3860 } 3861 #endif 3862 case '_': 3863 ch = i_getch(input); 3864 nommu_addchr(as_string, ch); 3865 ch = i_peek(input); 3866 if (isalnum(ch)) { /* it's $_name or $_123 */ 3867 ch = '_'; 3868 goto make_var; 3869 } 3870 /* else: it's $_ */ 3871 /* TODO: $_ and $-: */ 3872 /* $_ Shell or shell script name; or last argument of last command 3873 * (if last command wasn't a pipe; if it was, bash sets $_ to ""); 3874 * but in command's env, set to full pathname used to invoke it */ 3875 /* $- Option flags set by set builtin or shell options (-i etc) */ 3876 default: 3877 o_addQchr(dest, '$'); 3878 } 3879 debug_printf_parse("parse_dollar return 0\n"); 3880 return 0; 3881 #undef as_string 3882 } 3883 3884 #if BB_MMU 3885 # if ENABLE_HUSH_BASH_COMPAT 3886 #define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ 3887 encode_string(dest, input, dquote_end, process_bkslash) 3888 # else 3889 /* only ${var/pattern/repl} (its pattern part) needs additional mode */ 3890 #define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ 3891 encode_string(dest, input, dquote_end) 3892 # endif 3893 #define as_string NULL 3894 3895 #else /* !MMU */ 3896 3897 # if ENABLE_HUSH_BASH_COMPAT 3898 /* all parameters are needed, no macro tricks */ 3899 # else 3900 #define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ 3901 encode_string(as_string, dest, input, dquote_end) 3902 # endif 3903 #endif 3904 static int encode_string(o_string *as_string, 3905 o_string *dest, 3906 struct in_str *input, 3907 int dquote_end, 3908 int process_bkslash) 3909 { 3910 #if !ENABLE_HUSH_BASH_COMPAT 3911 const int process_bkslash = 1; 3912 #endif 3913 int ch; 3914 int next; 3915 3916 again: 3917 ch = i_getch(input); 3918 if (ch != EOF) 3919 nommu_addchr(as_string, ch); 3920 if (ch == dquote_end) { /* may be only '"' or EOF */ 3921 debug_printf_parse("encode_string return 0\n"); 3922 return 0; 3923 } 3924 /* note: can't move it above ch == dquote_end check! */ 3925 if (ch == EOF) { 3926 syntax_error_unterm_ch('"'); 3927 /*xfunc_die(); - redundant */ 3928 } 3929 next = '\0'; 3930 if (ch != '\n') { 3931 next = i_peek(input); 3932 } 3933 debug_printf_parse("\" ch=%c (%d) escape=%d\n", 3934 ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 3935 if (process_bkslash && ch == '\\') { 3936 if (next == EOF) { 3937 syntax_error("\\<eof>"); 3938 xfunc_die(); 3939 } 3940 /* bash: 3941 * "The backslash retains its special meaning [in "..."] 3942 * only when followed by one of the following characters: 3943 * $, `, ", \, or <newline>. A double quote may be quoted 3944 * within double quotes by preceding it with a backslash." 3945 * NB: in (unquoted) heredoc, above does not apply to ", 3946 * therefore we check for it by "next == dquote_end" cond. 3947 */ 3948 if (next == dquote_end || strchr("$`\\\n", next)) { 3949 ch = i_getch(input); /* eat next */ 3950 if (ch == '\n') 3951 goto again; /* skip \<newline> */ 3952 } /* else: ch remains == '\\', and we double it below: */ 3953 o_addqchr(dest, ch); /* \c if c is a glob char, else just c */ 3954 nommu_addchr(as_string, ch); 3955 goto again; 3956 } 3957 if (ch == '$') { 3958 if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) { 3959 debug_printf_parse("encode_string return 1: " 3960 "parse_dollar returned non-0\n"); 3961 return 1; 3962 } 3963 goto again; 3964 } 3965 #if ENABLE_HUSH_TICK 3966 if (ch == '`') { 3967 //unsigned pos = dest->length; 3968 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3969 o_addchr(dest, 0x80 | '`'); 3970 add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); 3971 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3972 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); 3973 goto again; 3974 } 3975 #endif 3976 o_addQchr(dest, ch); 3977 goto again; 3978 #undef as_string 3979 } 3980 3981 /* 3982 * Scan input until EOF or end_trigger char. 3983 * Return a list of pipes to execute, or NULL on EOF 3984 * or if end_trigger character is met. 3985 * On syntax error, exit is shell is not interactive, 3986 * reset parsing machinery and start parsing anew, 3987 * or return ERR_PTR. 3988 */ 3989 static struct pipe *parse_stream(char **pstring, 3990 struct in_str *input, 3991 int end_trigger) 3992 { 3993 struct parse_context ctx; 3994 o_string dest = NULL_O_STRING; 3995 int heredoc_cnt; 3996 3997 /* Single-quote triggers a bypass of the main loop until its mate is 3998 * found. When recursing, quote state is passed in via dest->o_expflags. 3999 */ 4000 debug_printf_parse("parse_stream entered, end_trigger='%c'\n", 4001 end_trigger ? end_trigger : 'X'); 4002 debug_enter(); 4003 4004 /* If very first arg is "" or '', dest.data may end up NULL. 4005 * Preventing this: */ 4006 o_addchr(&dest, '\0'); 4007 dest.length = 0; 4008 4009 /* We used to separate words on $IFS here. This was wrong. 4010 * $IFS is used only for word splitting when $var is expanded, 4011 * here we should use blank chars as separators, not $IFS 4012 */ 4013 4014 reset: /* we come back here only on syntax errors in interactive shell */ 4015 4016 #if ENABLE_HUSH_INTERACTIVE 4017 input->promptmode = 0; /* PS1 */ 4018 #endif 4019 if (MAYBE_ASSIGNMENT != 0) 4020 dest.o_assignment = MAYBE_ASSIGNMENT; 4021 initialize_context(&ctx); 4022 heredoc_cnt = 0; 4023 while (1) { 4024 const char *is_blank; 4025 const char *is_special; 4026 int ch; 4027 int next; 4028 int redir_fd; 4029 redir_type redir_style; 4030 4031 ch = i_getch(input); 4032 debug_printf_parse(": ch=%c (%d) escape=%d\n", 4033 ch, ch, !!(dest.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 4034 if (ch == EOF) { 4035 struct pipe *pi; 4036 4037 if (heredoc_cnt) { 4038 syntax_error_unterm_str("here document"); 4039 goto parse_error; 4040 } 4041 /* end_trigger == '}' case errors out earlier, 4042 * checking only ')' */ 4043 if (end_trigger == ')') { 4044 syntax_error_unterm_ch('('); /* exits */ 4045 /* goto parse_error; */ 4046 } 4047 4048 if (done_word(&dest, &ctx)) { 4049 goto parse_error; 4050 } 4051 o_free(&dest); 4052 done_pipe(&ctx, PIPE_SEQ); 4053 pi = ctx.list_head; 4054 /* If we got nothing... */ 4055 /* (this makes bare "&" cmd a no-op. 4056 * bash says: "syntax error near unexpected token '&'") */ 4057 if (pi->num_cmds == 0 4058 IF_HAS_KEYWORDS( && pi->res_word == RES_NONE) 4059 ) { 4060 free_pipe_list(pi); 4061 pi = NULL; 4062 } 4063 #if !BB_MMU 4064 debug_printf_parse("as_string '%s'\n", ctx.as_string.data); 4065 if (pstring) 4066 *pstring = ctx.as_string.data; 4067 else 4068 o_free_unsafe(&ctx.as_string); 4069 #endif 4070 debug_leave(); 4071 debug_printf_parse("parse_stream return %p\n", pi); 4072 return pi; 4073 } 4074 nommu_addchr(&ctx.as_string, ch); 4075 4076 next = '\0'; 4077 if (ch != '\n') 4078 next = i_peek(input); 4079 4080 is_special = "{}<>;&|()#'" /* special outside of "str" */ 4081 "\\$\"" IF_HUSH_TICK("`"); /* always special */ 4082 /* Are { and } special here? */ 4083 if (ctx.command->argv /* word [word]{... - non-special */ 4084 || dest.length /* word{... - non-special */ 4085 || dest.has_quoted_part /* ""{... - non-special */ 4086 || (next != ';' /* }; - special */ 4087 && next != ')' /* }) - special */ 4088 && next != '&' /* }& and }&& ... - special */ 4089 && next != '|' /* }|| ... - special */ 4090 && !strchr(defifs, next) /* {word - non-special */ 4091 ) 4092 ) { 4093 /* They are not special, skip "{}" */ 4094 is_special += 2; 4095 } 4096 is_special = strchr(is_special, ch); 4097 is_blank = strchr(defifs, ch); 4098 4099 if (!is_special && !is_blank) { /* ordinary char */ 4100 ordinary_char: 4101 o_addQchr(&dest, ch); 4102 if ((dest.o_assignment == MAYBE_ASSIGNMENT 4103 || dest.o_assignment == WORD_IS_KEYWORD) 4104 && ch == '=' 4105 && is_well_formed_var_name(dest.data, '=') 4106 ) { 4107 dest.o_assignment = DEFINITELY_ASSIGNMENT; 4108 } 4109 continue; 4110 } 4111 4112 if (is_blank) { 4113 if (done_word(&dest, &ctx)) { 4114 goto parse_error; 4115 } 4116 if (ch == '\n') { 4117 /* Is this a case when newline is simply ignored? 4118 * Some examples: 4119 * "cmd | <newline> cmd ..." 4120 * "case ... in <newline> word) ..." 4121 */ 4122 if (IS_NULL_CMD(ctx.command) 4123 && dest.length == 0 && !dest.has_quoted_part 4124 ) { 4125 /* This newline can be ignored. But... 4126 * Without check #1, interactive shell 4127 * ignores even bare <newline>, 4128 * and shows the continuation prompt: 4129 * ps1_prompt$ <enter> 4130 * ps2> _ <=== wrong, should be ps1 4131 * Without check #2, "cmd & <newline>" 4132 * is similarly mistreated. 4133 * (BTW, this makes "cmd & cmd" 4134 * and "cmd && cmd" non-orthogonal. 4135 * Really, ask yourself, why 4136 * "cmd && <newline>" doesn't start 4137 * cmd but waits for more input? 4138 * No reason...) 4139 */ 4140 struct pipe *pi = ctx.list_head; 4141 if (pi->num_cmds != 0 /* check #1 */ 4142 && pi->followup != PIPE_BG /* check #2 */ 4143 ) { 4144 continue; 4145 } 4146 } 4147 /* Treat newline as a command separator. */ 4148 done_pipe(&ctx, PIPE_SEQ); 4149 debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); 4150 if (heredoc_cnt) { 4151 if (fetch_heredocs(heredoc_cnt, &ctx, input)) { 4152 goto parse_error; 4153 } 4154 heredoc_cnt = 0; 4155 } 4156 dest.o_assignment = MAYBE_ASSIGNMENT; 4157 ch = ';'; 4158 /* note: if (is_blank) continue; 4159 * will still trigger for us */ 4160 } 4161 } 4162 4163 /* "cmd}" or "cmd }..." without semicolon or &: 4164 * } is an ordinary char in this case, even inside { cmd; } 4165 * Pathological example: { ""}; } should exec "}" cmd 4166 */ 4167 if (ch == '}') { 4168 if (!IS_NULL_CMD(ctx.command) /* cmd } */ 4169 || dest.length != 0 /* word} */ 4170 || dest.has_quoted_part /* ""} */ 4171 ) { 4172 goto ordinary_char; 4173 } 4174 if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */ 4175 goto skip_end_trigger; 4176 /* else: } does terminate a group */ 4177 } 4178 4179 if (end_trigger && end_trigger == ch 4180 && (ch != ';' || heredoc_cnt == 0) 4181 #if ENABLE_HUSH_CASE 4182 && (ch != ')' 4183 || ctx.ctx_res_w != RES_MATCH 4184 || (!dest.has_quoted_part && strcmp(dest.data, "esac") == 0) 4185 ) 4186 #endif 4187 ) { 4188 if (heredoc_cnt) { 4189 /* This is technically valid: 4190 * { cat <<HERE; }; echo Ok 4191 * heredoc 4192 * heredoc 4193 * HERE 4194 * but we don't support this. 4195 * We require heredoc to be in enclosing {}/(), 4196 * if any. 4197 */ 4198 syntax_error_unterm_str("here document"); 4199 goto parse_error; 4200 } 4201 if (done_word(&dest, &ctx)) { 4202 goto parse_error; 4203 } 4204 done_pipe(&ctx, PIPE_SEQ); 4205 dest.o_assignment = MAYBE_ASSIGNMENT; 4206 /* Do we sit outside of any if's, loops or case's? */ 4207 if (!HAS_KEYWORDS 4208 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) 4209 ) { 4210 o_free(&dest); 4211 #if !BB_MMU 4212 debug_printf_parse("as_string '%s'\n", ctx.as_string.data); 4213 if (pstring) 4214 *pstring = ctx.as_string.data; 4215 else 4216 o_free_unsafe(&ctx.as_string); 4217 #endif 4218 debug_leave(); 4219 debug_printf_parse("parse_stream return %p: " 4220 "end_trigger char found\n", 4221 ctx.list_head); 4222 return ctx.list_head; 4223 } 4224 } 4225 skip_end_trigger: 4226 if (is_blank) 4227 continue; 4228 4229 /* Catch <, > before deciding whether this word is 4230 * an assignment. a=1 2>z b=2: b=2 is still assignment */ 4231 switch (ch) { 4232 case '>': 4233 redir_fd = redirect_opt_num(&dest); 4234 if (done_word(&dest, &ctx)) { 4235 goto parse_error; 4236 } 4237 redir_style = REDIRECT_OVERWRITE; 4238 if (next == '>') { 4239 redir_style = REDIRECT_APPEND; 4240 ch = i_getch(input); 4241 nommu_addchr(&ctx.as_string, ch); 4242 } 4243 #if 0 4244 else if (next == '(') { 4245 syntax_error(">(process) not supported"); 4246 goto parse_error; 4247 } 4248 #endif 4249 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 4250 goto parse_error; 4251 continue; /* back to top of while (1) */ 4252 case '<': 4253 redir_fd = redirect_opt_num(&dest); 4254 if (done_word(&dest, &ctx)) { 4255 goto parse_error; 4256 } 4257 redir_style = REDIRECT_INPUT; 4258 if (next == '<') { 4259 redir_style = REDIRECT_HEREDOC; 4260 heredoc_cnt++; 4261 debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt); 4262 ch = i_getch(input); 4263 nommu_addchr(&ctx.as_string, ch); 4264 } else if (next == '>') { 4265 redir_style = REDIRECT_IO; 4266 ch = i_getch(input); 4267 nommu_addchr(&ctx.as_string, ch); 4268 } 4269 #if 0 4270 else if (next == '(') { 4271 syntax_error("<(process) not supported"); 4272 goto parse_error; 4273 } 4274 #endif 4275 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 4276 goto parse_error; 4277 continue; /* back to top of while (1) */ 4278 case '#': 4279 if (dest.length == 0 && !dest.has_quoted_part) { 4280 /* skip "#comment" */ 4281 while (1) { 4282 ch = i_peek(input); 4283 if (ch == EOF || ch == '\n') 4284 break; 4285 i_getch(input); 4286 /* note: we do not add it to &ctx.as_string */ 4287 } 4288 nommu_addchr(&ctx.as_string, '\n'); 4289 continue; /* back to top of while (1) */ 4290 } 4291 break; 4292 case '\\': 4293 if (next == '\n') { 4294 /* It's "\<newline>" */ 4295 #if !BB_MMU 4296 /* Remove trailing '\' from ctx.as_string */ 4297 ctx.as_string.data[--ctx.as_string.length] = '\0'; 4298 #endif 4299 ch = i_getch(input); /* eat it */ 4300 continue; /* back to top of while (1) */ 4301 } 4302 break; 4303 } 4304 4305 if (dest.o_assignment == MAYBE_ASSIGNMENT 4306 /* check that we are not in word in "a=1 2>word b=1": */ 4307 && !ctx.pending_redirect 4308 ) { 4309 /* ch is a special char and thus this word 4310 * cannot be an assignment */ 4311 dest.o_assignment = NOT_ASSIGNMENT; 4312 } 4313 4314 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ 4315 4316 switch (ch) { 4317 case '#': /* non-comment #: "echo a#b" etc */ 4318 o_addQchr(&dest, ch); 4319 break; 4320 case '\\': 4321 if (next == EOF) { 4322 syntax_error("\\<eof>"); 4323 xfunc_die(); 4324 } 4325 ch = i_getch(input); 4326 /* note: ch != '\n' (that case does not reach this place) */ 4327 o_addchr(&dest, '\\'); 4328 /*nommu_addchr(&ctx.as_string, '\\'); - already done */ 4329 o_addchr(&dest, ch); 4330 nommu_addchr(&ctx.as_string, ch); 4331 /* Example: echo Hello \2>file 4332 * we need to know that word 2 is quoted */ 4333 dest.has_quoted_part = 1; 4334 break; 4335 case '$': 4336 if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { 4337 debug_printf_parse("parse_stream parse error: " 4338 "parse_dollar returned non-0\n"); 4339 goto parse_error; 4340 } 4341 break; 4342 case '\'': 4343 dest.has_quoted_part = 1; 4344 while (1) { 4345 ch = i_getch(input); 4346 if (ch == EOF) { 4347 syntax_error_unterm_ch('\''); 4348 /*xfunc_die(); - redundant */ 4349 } 4350 nommu_addchr(&ctx.as_string, ch); 4351 if (ch == '\'') 4352 break; 4353 o_addqchr(&dest, ch); 4354 } 4355 break; 4356 case '"': 4357 dest.has_quoted_part = 1; 4358 if (dest.o_assignment == NOT_ASSIGNMENT) 4359 dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 4360 if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) 4361 goto parse_error; 4362 dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; 4363 break; 4364 #if ENABLE_HUSH_TICK 4365 case '`': { 4366 unsigned pos; 4367 4368 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4369 o_addchr(&dest, '`'); 4370 pos = dest.length; 4371 add_till_backquote(&dest, input, /*in_dquote:*/ 0); 4372 # if !BB_MMU 4373 o_addstr(&ctx.as_string, dest.data + pos); 4374 o_addchr(&ctx.as_string, '`'); 4375 # endif 4376 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4377 //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); 4378 break; 4379 } 4380 #endif 4381 case ';': 4382 #if ENABLE_HUSH_CASE 4383 case_semi: 4384 #endif 4385 if (done_word(&dest, &ctx)) { 4386 goto parse_error; 4387 } 4388 done_pipe(&ctx, PIPE_SEQ); 4389 #if ENABLE_HUSH_CASE 4390 /* Eat multiple semicolons, detect 4391 * whether it means something special */ 4392 while (1) { 4393 ch = i_peek(input); 4394 if (ch != ';') 4395 break; 4396 ch = i_getch(input); 4397 nommu_addchr(&ctx.as_string, ch); 4398 if (ctx.ctx_res_w == RES_CASE_BODY) { 4399 ctx.ctx_dsemicolon = 1; 4400 ctx.ctx_res_w = RES_MATCH; 4401 break; 4402 } 4403 } 4404 #endif 4405 new_cmd: 4406 /* We just finished a cmd. New one may start 4407 * with an assignment */ 4408 dest.o_assignment = MAYBE_ASSIGNMENT; 4409 break; 4410 case '&': 4411 if (done_word(&dest, &ctx)) { 4412 goto parse_error; 4413 } 4414 if (next == '&') { 4415 ch = i_getch(input); 4416 nommu_addchr(&ctx.as_string, ch); 4417 done_pipe(&ctx, PIPE_AND); 4418 } else { 4419 done_pipe(&ctx, PIPE_BG); 4420 } 4421 goto new_cmd; 4422 case '|': 4423 if (done_word(&dest, &ctx)) { 4424 goto parse_error; 4425 } 4426 #if ENABLE_HUSH_CASE 4427 if (ctx.ctx_res_w == RES_MATCH) 4428 break; /* we are in case's "word | word)" */ 4429 #endif 4430 if (next == '|') { /* || */ 4431 ch = i_getch(input); 4432 nommu_addchr(&ctx.as_string, ch); 4433 done_pipe(&ctx, PIPE_OR); 4434 } else { 4435 /* we could pick up a file descriptor choice here 4436 * with redirect_opt_num(), but bash doesn't do it. 4437 * "echo foo 2| cat" yields "foo 2". */ 4438 done_command(&ctx); 4439 #if !BB_MMU 4440 o_reset_to_empty_unquoted(&ctx.as_string); 4441 #endif 4442 } 4443 goto new_cmd; 4444 case '(': 4445 #if ENABLE_HUSH_CASE 4446 /* "case... in [(]word)..." - skip '(' */ 4447 if (ctx.ctx_res_w == RES_MATCH 4448 && ctx.command->argv == NULL /* not (word|(... */ 4449 && dest.length == 0 /* not word(... */ 4450 && dest.has_quoted_part == 0 /* not ""(... */ 4451 ) { 4452 continue; 4453 } 4454 #endif 4455 case '{': 4456 if (parse_group(&dest, &ctx, input, ch) != 0) { 4457 goto parse_error; 4458 } 4459 goto new_cmd; 4460 case ')': 4461 #if ENABLE_HUSH_CASE 4462 if (ctx.ctx_res_w == RES_MATCH) 4463 goto case_semi; 4464 #endif 4465 case '}': 4466 /* proper use of this character is caught by end_trigger: 4467 * if we see {, we call parse_group(..., end_trigger='}') 4468 * and it will match } earlier (not here). */ 4469 syntax_error_unexpected_ch(ch); 4470 goto parse_error; 4471 default: 4472 if (HUSH_DEBUG) 4473 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 4474 } 4475 } /* while (1) */ 4476 4477 parse_error: 4478 { 4479 struct parse_context *pctx; 4480 IF_HAS_KEYWORDS(struct parse_context *p2;) 4481 4482 /* Clean up allocated tree. 4483 * Sample for finding leaks on syntax error recovery path. 4484 * Run it from interactive shell, watch pmap `pidof hush`. 4485 * while if false; then false; fi; do break; fi 4486 * Samples to catch leaks at execution: 4487 * while if (true | {true;}); then echo ok; fi; do break; done 4488 * while if (true | {true;}); then echo ok; fi; do (if echo ok; break; then :; fi) | cat; break; done 4489 */ 4490 pctx = &ctx; 4491 do { 4492 /* Update pipe/command counts, 4493 * otherwise freeing may miss some */ 4494 done_pipe(pctx, PIPE_SEQ); 4495 debug_printf_clean("freeing list %p from ctx %p\n", 4496 pctx->list_head, pctx); 4497 debug_print_tree(pctx->list_head, 0); 4498 free_pipe_list(pctx->list_head); 4499 debug_printf_clean("freed list %p\n", pctx->list_head); 4500 #if !BB_MMU 4501 o_free_unsafe(&pctx->as_string); 4502 #endif 4503 IF_HAS_KEYWORDS(p2 = pctx->stack;) 4504 if (pctx != &ctx) { 4505 free(pctx); 4506 } 4507 IF_HAS_KEYWORDS(pctx = p2;) 4508 } while (HAS_KEYWORDS && pctx); 4509 /* Free text, clear all dest fields */ 4510 o_free(&dest); 4511 /* If we are not in top-level parse, we return, 4512 * our caller will propagate error. 4513 */ 4514 if (end_trigger != ';') { 4515 #if !BB_MMU 4516 if (pstring) 4517 *pstring = NULL; 4518 #endif 4519 debug_leave(); 4520 return ERR_PTR; 4521 } 4522 /* Discard cached input, force prompt */ 4523 input->p = NULL; 4524 IF_HUSH_INTERACTIVE(input->promptme = 1;) 4525 goto reset; 4526 } 4527 } 4528 4529 4530 /*** Execution routines ***/ 4531 4532 /* Expansion can recurse, need forward decls: */ 4533 #if !ENABLE_HUSH_BASH_COMPAT 4534 /* only ${var/pattern/repl} (its pattern part) needs additional mode */ 4535 #define expand_string_to_string(str, do_unbackslash) \ 4536 expand_string_to_string(str) 4537 #endif 4538 static char *expand_string_to_string(const char *str, int do_unbackslash); 4539 #if ENABLE_HUSH_TICK 4540 static int process_command_subs(o_string *dest, const char *s); 4541 #endif 4542 4543 /* expand_strvec_to_strvec() takes a list of strings, expands 4544 * all variable references within and returns a pointer to 4545 * a list of expanded strings, possibly with larger number 4546 * of strings. (Think VAR="a b"; echo $VAR). 4547 * This new list is allocated as a single malloc block. 4548 * NULL-terminated list of char* pointers is at the beginning of it, 4549 * followed by strings themselves. 4550 * Caller can deallocate entire list by single free(list). */ 4551 4552 /* A horde of its helpers come first: */ 4553 4554 static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) 4555 { 4556 while (--len >= 0) { 4557 char c = *str++; 4558 4559 #if ENABLE_HUSH_BRACE_EXPANSION 4560 if (c == '{' || c == '}') { 4561 /* { -> \{, } -> \} */ 4562 o_addchr(o, '\\'); 4563 /* And now we want to add { or } and continue: 4564 * o_addchr(o, c); 4565 * continue; 4566 * luckily, just falling throught achieves this. 4567 */ 4568 } 4569 #endif 4570 o_addchr(o, c); 4571 if (c == '\\') { 4572 /* \z -> \\\z; \<eol> -> \\<eol> */ 4573 o_addchr(o, '\\'); 4574 if (len) { 4575 len--; 4576 o_addchr(o, '\\'); 4577 o_addchr(o, *str++); 4578 } 4579 } 4580 } 4581 } 4582 4583 /* Store given string, finalizing the word and starting new one whenever 4584 * we encounter IFS char(s). This is used for expanding variable values. 4585 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 4586 static int expand_on_ifs(o_string *output, int n, const char *str) 4587 { 4588 while (1) { 4589 int word_len = strcspn(str, G.ifs); 4590 if (word_len) { 4591 if (!(output->o_expflags & EXP_FLAG_GLOB)) { 4592 o_addblock(output, str, word_len); 4593 } else { 4594 /* Protect backslashes against globbing up :) 4595 * Example: "v='\*'; echo b$v" prints "b\*" 4596 * (and does not try to glob on "*") 4597 */ 4598 o_addblock_duplicate_backslash(output, str, word_len); 4599 /*/ Why can't we do it easier? */ 4600 /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ 4601 /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ 4602 } 4603 str += word_len; 4604 } 4605 if (!*str) /* EOL - do not finalize word */ 4606 break; 4607 o_addchr(output, '\0'); 4608 debug_print_list("expand_on_ifs", output, n); 4609 n = o_save_ptr(output, n); 4610 str += strspn(str, G.ifs); /* skip ifs chars */ 4611 } 4612 debug_print_list("expand_on_ifs[1]", output, n); 4613 return n; 4614 } 4615 4616 /* Helper to expand $((...)) and heredoc body. These act as if 4617 * they are in double quotes, with the exception that they are not :). 4618 * Just the rules are similar: "expand only $var and `cmd`" 4619 * 4620 * Returns malloced string. 4621 * As an optimization, we return NULL if expansion is not needed. 4622 */ 4623 #if !ENABLE_HUSH_BASH_COMPAT 4624 /* only ${var/pattern/repl} (its pattern part) needs additional mode */ 4625 #define encode_then_expand_string(str, process_bkslash, do_unbackslash) \ 4626 encode_then_expand_string(str) 4627 #endif 4628 static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash) 4629 { 4630 char *exp_str; 4631 struct in_str input; 4632 o_string dest = NULL_O_STRING; 4633 4634 if (!strchr(str, '$') 4635 && !strchr(str, '\\') 4636 #if ENABLE_HUSH_TICK 4637 && !strchr(str, '`') 4638 #endif 4639 ) { 4640 return NULL; 4641 } 4642 4643 /* We need to expand. Example: 4644 * echo $(($a + `echo 1`)) $((1 + $((2)) )) 4645 */ 4646 setup_string_in_str(&input, str); 4647 encode_string(NULL, &dest, &input, EOF, process_bkslash); 4648 //bb_error_msg("'%s' -> '%s'", str, dest.data); 4649 exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); 4650 //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); 4651 o_free_unsafe(&dest); 4652 return exp_str; 4653 } 4654 4655 #if ENABLE_SH_MATH_SUPPORT 4656 static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) 4657 { 4658 arith_state_t math_state; 4659 arith_t res; 4660 char *exp_str; 4661 4662 math_state.lookupvar = get_local_var_value; 4663 math_state.setvar = set_local_var_from_halves; 4664 //math_state.endofname = endofname; 4665 exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 4666 res = arith(&math_state, exp_str ? exp_str : arg); 4667 free(exp_str); 4668 if (errmsg_p) 4669 *errmsg_p = math_state.errmsg; 4670 if (math_state.errmsg) 4671 die_if_script(math_state.errmsg); 4672 return res; 4673 } 4674 #endif 4675 4676 #if ENABLE_HUSH_BASH_COMPAT 4677 /* ${var/[/]pattern[/repl]} helpers */ 4678 static char *strstr_pattern(char *val, const char *pattern, int *size) 4679 { 4680 while (1) { 4681 char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF); 4682 debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end); 4683 if (end) { 4684 *size = end - val; 4685 return val; 4686 } 4687 if (*val == '\0') 4688 return NULL; 4689 /* Optimization: if "*pat" did not match the start of "string", 4690 * we know that "tring", "ring" etc will not match too: 4691 */ 4692 if (pattern[0] == '*') 4693 return NULL; 4694 val++; 4695 } 4696 } 4697 static char *replace_pattern(char *val, const char *pattern, const char *repl, char exp_op) 4698 { 4699 char *result = NULL; 4700 unsigned res_len = 0; 4701 unsigned repl_len = strlen(repl); 4702 4703 while (1) { 4704 int size; 4705 char *s = strstr_pattern(val, pattern, &size); 4706 if (!s) 4707 break; 4708 4709 result = xrealloc(result, res_len + (s - val) + repl_len + 1); 4710 memcpy(result + res_len, val, s - val); 4711 res_len += s - val; 4712 strcpy(result + res_len, repl); 4713 res_len += repl_len; 4714 debug_printf_varexp("val:'%s' s:'%s' result:'%s'\n", val, s, result); 4715 4716 val = s + size; 4717 if (exp_op == '/') 4718 break; 4719 } 4720 if (val[0] && result) { 4721 result = xrealloc(result, res_len + strlen(val) + 1); 4722 strcpy(result + res_len, val); 4723 debug_printf_varexp("val:'%s' result:'%s'\n", val, result); 4724 } 4725 debug_printf_varexp("result:'%s'\n", result); 4726 return result; 4727 } 4728 #endif 4729 4730 /* Helper: 4731 * Handles <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct. 4732 */ 4733 static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) 4734 { 4735 const char *val = NULL; 4736 char *to_be_freed = NULL; 4737 char *p = *pp; 4738 char *var; 4739 char first_char; 4740 char exp_op; 4741 char exp_save = exp_save; /* for compiler */ 4742 char *exp_saveptr; /* points to expansion operator */ 4743 char *exp_word = exp_word; /* for compiler */ 4744 char arg0; 4745 4746 *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */ 4747 var = arg; 4748 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; 4749 arg0 = arg[0]; 4750 first_char = arg[0] = arg0 & 0x7f; 4751 exp_op = 0; 4752 4753 if (first_char == '#' /* ${#... */ 4754 && arg[1] && !exp_saveptr /* not ${#} and not ${#<op_char>...} */ 4755 ) { 4756 /* It must be length operator: ${#var} */ 4757 var++; 4758 exp_op = 'L'; 4759 } else { 4760 /* Maybe handle parameter expansion */ 4761 if (exp_saveptr /* if 2nd char is one of expansion operators */ 4762 && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ 4763 ) { 4764 /* ${?:0}, ${#[:]%0} etc */ 4765 exp_saveptr = var + 1; 4766 } else { 4767 /* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */ 4768 exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS); 4769 } 4770 exp_op = exp_save = *exp_saveptr; 4771 if (exp_op) { 4772 exp_word = exp_saveptr + 1; 4773 if (exp_op == ':') { 4774 exp_op = *exp_word++; 4775 //TODO: try ${var:} and ${var:bogus} in non-bash config 4776 if (ENABLE_HUSH_BASH_COMPAT 4777 && (!exp_op || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op)) 4778 ) { 4779 /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ 4780 exp_op = ':'; 4781 exp_word--; 4782 } 4783 } 4784 *exp_saveptr = '\0'; 4785 } /* else: it's not an expansion op, but bare ${var} */ 4786 } 4787 4788 /* Look up the variable in question */ 4789 if (isdigit(var[0])) { 4790 /* parse_dollar should have vetted var for us */ 4791 int n = xatoi_positive(var); 4792 if (n < G.global_argc) 4793 val = G.global_argv[n]; 4794 /* else val remains NULL: $N with too big N */ 4795 } else { 4796 switch (var[0]) { 4797 case '$': /* pid */ 4798 val = utoa(G.root_pid); 4799 break; 4800 case '!': /* bg pid */ 4801 val = G.last_bg_pid ? utoa(G.last_bg_pid) : ""; 4802 break; 4803 case '?': /* exitcode */ 4804 val = utoa(G.last_exitcode); 4805 break; 4806 case '#': /* argc */ 4807 val = utoa(G.global_argc ? G.global_argc-1 : 0); 4808 break; 4809 default: 4810 val = get_local_var_value(var); 4811 } 4812 } 4813 4814 /* Handle any expansions */ 4815 if (exp_op == 'L') { 4816 debug_printf_expand("expand: length(%s)=", val); 4817 val = utoa(val ? strlen(val) : 0); 4818 debug_printf_expand("%s\n", val); 4819 } else if (exp_op) { 4820 if (exp_op == '%' || exp_op == '#') { 4821 /* Standard-mandated substring removal ops: 4822 * ${parameter%word} - remove smallest suffix pattern 4823 * ${parameter%%word} - remove largest suffix pattern 4824 * ${parameter#word} - remove smallest prefix pattern 4825 * ${parameter##word} - remove largest prefix pattern 4826 * 4827 * Word is expanded to produce a glob pattern. 4828 * Then var's value is matched to it and matching part removed. 4829 */ 4830 if (val && val[0]) { 4831 char *t; 4832 char *exp_exp_word; 4833 char *loc; 4834 unsigned scan_flags = pick_scan(exp_op, *exp_word); 4835 if (exp_op == *exp_word) /* ## or %% */ 4836 exp_word++; 4837 exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 4838 if (exp_exp_word) 4839 exp_word = exp_exp_word; 4840 /* HACK ALERT. We depend here on the fact that 4841 * G.global_argv and results of utoa and get_local_var_value 4842 * are actually in writable memory: 4843 * scan_and_match momentarily stores NULs there. */ 4844 t = (char*)val; 4845 loc = scan_and_match(t, exp_word, scan_flags); 4846 //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", 4847 // exp_op, t, exp_word, loc); 4848 free(exp_exp_word); 4849 if (loc) { /* match was found */ 4850 if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */ 4851 val = loc; /* take right part */ 4852 else /* %[%] */ 4853 val = to_be_freed = xstrndup(val, loc - val); /* left */ 4854 } 4855 } 4856 } 4857 #if ENABLE_HUSH_BASH_COMPAT 4858 else if (exp_op == '/' || exp_op == '\\') { 4859 /* It's ${var/[/]pattern[/repl]} thing. 4860 * Note that in encoded form it has TWO parts: 4861 * var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> 4862 * and if // is used, it is encoded as \: 4863 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> 4864 */ 4865 /* Empty variable always gives nothing: */ 4866 // "v=''; echo ${v/*/w}" prints "", not "w" 4867 if (val && val[0]) { 4868 /* pattern uses non-standard expansion. 4869 * repl should be unbackslashed and globbed 4870 * by the usual expansion rules: 4871 * >az; >bz; 4872 * v='a bz'; echo "${v/a*z/a*z}" prints "a*z" 4873 * v='a bz'; echo "${v/a*z/\z}" prints "\z" 4874 * v='a bz'; echo ${v/a*z/a*z} prints "az" 4875 * v='a bz'; echo ${v/a*z/\z} prints "z" 4876 * (note that a*z _pattern_ is never globbed!) 4877 */ 4878 char *pattern, *repl, *t; 4879 pattern = encode_then_expand_string(exp_word, /*process_bkslash:*/ 0, /*unbackslash:*/ 0); 4880 if (!pattern) 4881 pattern = xstrdup(exp_word); 4882 debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern); 4883 *p++ = SPECIAL_VAR_SYMBOL; 4884 exp_word = p; 4885 p = strchr(p, SPECIAL_VAR_SYMBOL); 4886 *p = '\0'; 4887 repl = encode_then_expand_string(exp_word, /*process_bkslash:*/ arg0 & 0x80, /*unbackslash:*/ 1); 4888 debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl); 4889 /* HACK ALERT. We depend here on the fact that 4890 * G.global_argv and results of utoa and get_local_var_value 4891 * are actually in writable memory: 4892 * replace_pattern momentarily stores NULs there. */ 4893 t = (char*)val; 4894 to_be_freed = replace_pattern(t, 4895 pattern, 4896 (repl ? repl : exp_word), 4897 exp_op); 4898 if (to_be_freed) /* at least one replace happened */ 4899 val = to_be_freed; 4900 free(pattern); 4901 free(repl); 4902 } 4903 } 4904 #endif 4905 else if (exp_op == ':') { 4906 #if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT 4907 /* It's ${var:N[:M]} bashism. 4908 * Note that in encoded form it has TWO parts: 4909 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> 4910 */ 4911 arith_t beg, len; 4912 const char *errmsg; 4913 4914 beg = expand_and_evaluate_arith(exp_word, &errmsg); 4915 if (errmsg) 4916 goto arith_err; 4917 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); 4918 *p++ = SPECIAL_VAR_SYMBOL; 4919 exp_word = p; 4920 p = strchr(p, SPECIAL_VAR_SYMBOL); 4921 *p = '\0'; 4922 len = expand_and_evaluate_arith(exp_word, &errmsg); 4923 if (errmsg) 4924 goto arith_err; 4925 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); 4926 if (len >= 0) { /* bash compat: len < 0 is illegal */ 4927 if (beg < 0) /* bash compat */ 4928 beg = 0; 4929 debug_printf_varexp("from val:'%s'\n", val); 4930 if (len == 0 || !val || beg >= strlen(val)) { 4931 arith_err: 4932 val = NULL; 4933 } else { 4934 /* Paranoia. What if user entered 9999999999999 4935 * which fits in arith_t but not int? */ 4936 if (len >= INT_MAX) 4937 len = INT_MAX; 4938 val = to_be_freed = xstrndup(val + beg, len); 4939 } 4940 debug_printf_varexp("val:'%s'\n", val); 4941 } else 4942 #endif 4943 { 4944 die_if_script("malformed ${%s:...}", var); 4945 val = NULL; 4946 } 4947 } else { /* one of "-=+?" */ 4948 /* Standard-mandated substitution ops: 4949 * ${var?word} - indicate error if unset 4950 * If var is unset, word (or a message indicating it is unset 4951 * if word is null) is written to standard error 4952 * and the shell exits with a non-zero exit status. 4953 * Otherwise, the value of var is substituted. 4954 * ${var-word} - use default value 4955 * If var is unset, word is substituted. 4956 * ${var=word} - assign and use default value 4957 * If var is unset, word is assigned to var. 4958 * In all cases, final value of var is substituted. 4959 * ${var+word} - use alternative value 4960 * If var is unset, null is substituted. 4961 * Otherwise, word is substituted. 4962 * 4963 * Word is subjected to tilde expansion, parameter expansion, 4964 * command substitution, and arithmetic expansion. 4965 * If word is not needed, it is not expanded. 4966 * 4967 * Colon forms (${var:-word}, ${var:=word} etc) do the same, 4968 * but also treat null var as if it is unset. 4969 */ 4970 int use_word = (!val || ((exp_save == ':') && !val[0])); 4971 if (exp_op == '+') 4972 use_word = !use_word; 4973 debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op, 4974 (exp_save == ':') ? "true" : "false", use_word); 4975 if (use_word) { 4976 to_be_freed = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 4977 if (to_be_freed) 4978 exp_word = to_be_freed; 4979 if (exp_op == '?') { 4980 /* mimic bash message */ 4981 die_if_script("%s: %s", 4982 var, 4983 exp_word[0] ? exp_word : "parameter null or not set" 4984 ); 4985 //TODO: how interactive bash aborts expansion mid-command? 4986 } else { 4987 val = exp_word; 4988 } 4989 4990 if (exp_op == '=') { 4991 /* ${var=[word]} or ${var:=[word]} */ 4992 if (isdigit(var[0]) || var[0] == '#') { 4993 /* mimic bash message */ 4994 die_if_script("$%s: cannot assign in this way", var); 4995 val = NULL; 4996 } else { 4997 char *new_var = xasprintf("%s=%s", var, val); 4998 set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 4999 } 5000 } 5001 } 5002 } /* one of "-=+?" */ 5003 5004 *exp_saveptr = exp_save; 5005 } /* if (exp_op) */ 5006 5007 arg[0] = arg0; 5008 5009 *pp = p; 5010 *to_be_freed_pp = to_be_freed; 5011 return val; 5012 } 5013 5014 /* Expand all variable references in given string, adding words to list[] 5015 * at n, n+1,... positions. Return updated n (so that list[n] is next one 5016 * to be filled). This routine is extremely tricky: has to deal with 5017 * variables/parameters with whitespace, $* and $@, and constructs like 5018 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ 5019 static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) 5020 { 5021 /* output->o_expflags & EXP_FLAG_SINGLEWORD (0x80) if we are in 5022 * expansion of right-hand side of assignment == 1-element expand. 5023 */ 5024 char cant_be_null = 0; /* only bit 0x80 matters */ 5025 char *p; 5026 5027 debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, 5028 !!(output->o_expflags & EXP_FLAG_SINGLEWORD)); 5029 debug_print_list("expand_vars_to_list", output, n); 5030 n = o_save_ptr(output, n); 5031 debug_print_list("expand_vars_to_list[0]", output, n); 5032 5033 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { 5034 char first_ch; 5035 char *to_be_freed = NULL; 5036 const char *val = NULL; 5037 #if ENABLE_HUSH_TICK 5038 o_string subst_result = NULL_O_STRING; 5039 #endif 5040 #if ENABLE_SH_MATH_SUPPORT 5041 char arith_buf[sizeof(arith_t)*3 + 2]; 5042 #endif 5043 o_addblock(output, arg, p - arg); 5044 debug_print_list("expand_vars_to_list[1]", output, n); 5045 arg = ++p; 5046 p = strchr(p, SPECIAL_VAR_SYMBOL); 5047 5048 /* Fetch special var name (if it is indeed one of them) 5049 * and quote bit, force the bit on if singleword expansion - 5050 * important for not getting v=$@ expand to many words. */ 5051 first_ch = arg[0] | (output->o_expflags & EXP_FLAG_SINGLEWORD); 5052 5053 /* Is this variable quoted and thus expansion can't be null? 5054 * "$@" is special. Even if quoted, it can still 5055 * expand to nothing (not even an empty string), 5056 * thus it is excluded. */ 5057 if ((first_ch & 0x7f) != '@') 5058 cant_be_null |= first_ch; 5059 5060 switch (first_ch & 0x7f) { 5061 /* Highest bit in first_ch indicates that var is double-quoted */ 5062 case '*': 5063 case '@': { 5064 int i; 5065 if (!G.global_argv[1]) 5066 break; 5067 i = 1; 5068 cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ 5069 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 5070 while (G.global_argv[i]) { 5071 n = expand_on_ifs(output, n, G.global_argv[i]); 5072 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); 5073 if (G.global_argv[i++][0] && G.global_argv[i]) { 5074 /* this argv[] is not empty and not last: 5075 * put terminating NUL, start new word */ 5076 o_addchr(output, '\0'); 5077 debug_print_list("expand_vars_to_list[2]", output, n); 5078 n = o_save_ptr(output, n); 5079 debug_print_list("expand_vars_to_list[3]", output, n); 5080 } 5081 } 5082 } else 5083 /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....' 5084 * and in this case should treat it like '$*' - see 'else...' below */ 5085 if (first_ch == ('@'|0x80) /* quoted $@ */ 5086 && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */ 5087 ) { 5088 while (1) { 5089 o_addQstr(output, G.global_argv[i]); 5090 if (++i >= G.global_argc) 5091 break; 5092 o_addchr(output, '\0'); 5093 debug_print_list("expand_vars_to_list[4]", output, n); 5094 n = o_save_ptr(output, n); 5095 } 5096 } else { /* quoted $* (or v="$@" case): add as one word */ 5097 while (1) { 5098 o_addQstr(output, G.global_argv[i]); 5099 if (!G.global_argv[++i]) 5100 break; 5101 if (G.ifs[0]) 5102 o_addchr(output, G.ifs[0]); 5103 } 5104 } 5105 break; 5106 } 5107 case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ 5108 /* "Empty variable", used to make "" etc to not disappear */ 5109 arg++; 5110 cant_be_null = 0x80; 5111 break; 5112 #if ENABLE_HUSH_TICK 5113 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */ 5114 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 5115 arg++; 5116 /* Can't just stuff it into output o_string, 5117 * expanded result may need to be globbed 5118 * and $IFS-splitted */ 5119 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); 5120 G.last_exitcode = process_command_subs(&subst_result, arg); 5121 debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data); 5122 val = subst_result.data; 5123 goto store_val; 5124 #endif 5125 #if ENABLE_SH_MATH_SUPPORT 5126 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ 5127 arith_t res; 5128 5129 arg++; /* skip '+' */ 5130 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 5131 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); 5132 res = expand_and_evaluate_arith(arg, NULL); 5133 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res); 5134 sprintf(arith_buf, ARITH_FMT, res); 5135 val = arith_buf; 5136 break; 5137 } 5138 #endif 5139 default: 5140 val = expand_one_var(&to_be_freed, arg, &p); 5141 IF_HUSH_TICK(store_val:) 5142 if (!(first_ch & 0x80)) { /* unquoted $VAR */ 5143 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, 5144 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5145 if (val && val[0]) { 5146 n = expand_on_ifs(output, n, val); 5147 val = NULL; 5148 } 5149 } else { /* quoted $VAR, val will be appended below */ 5150 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, 5151 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5152 } 5153 break; 5154 5155 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ 5156 5157 if (val && val[0]) { 5158 o_addQstr(output, val); 5159 } 5160 free(to_be_freed); 5161 5162 /* Restore NULL'ed SPECIAL_VAR_SYMBOL. 5163 * Do the check to avoid writing to a const string. */ 5164 if (*p != SPECIAL_VAR_SYMBOL) 5165 *p = SPECIAL_VAR_SYMBOL; 5166 5167 #if ENABLE_HUSH_TICK 5168 o_free(&subst_result); 5169 #endif 5170 arg = ++p; 5171 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ 5172 5173 if (arg[0]) { 5174 debug_print_list("expand_vars_to_list[a]", output, n); 5175 /* this part is literal, and it was already pre-quoted 5176 * if needed (much earlier), do not use o_addQstr here! */ 5177 o_addstr_with_NUL(output, arg); 5178 debug_print_list("expand_vars_to_list[b]", output, n); 5179 } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ 5180 && !(cant_be_null & 0x80) /* and all vars were not quoted. */ 5181 ) { 5182 n--; 5183 /* allow to reuse list[n] later without re-growth */ 5184 output->has_empty_slot = 1; 5185 } else { 5186 o_addchr(output, '\0'); 5187 } 5188 5189 return n; 5190 } 5191 5192 static char **expand_variables(char **argv, unsigned expflags) 5193 { 5194 int n; 5195 char **list; 5196 o_string output = NULL_O_STRING; 5197 5198 output.o_expflags = expflags; 5199 5200 n = 0; 5201 while (*argv) { 5202 n = expand_vars_to_list(&output, n, *argv); 5203 argv++; 5204 } 5205 debug_print_list("expand_variables", &output, n); 5206 5207 /* output.data (malloced in one block) gets returned in "list" */ 5208 list = o_finalize_list(&output, n); 5209 debug_print_strings("expand_variables[1]", list); 5210 return list; 5211 } 5212 5213 static char **expand_strvec_to_strvec(char **argv) 5214 { 5215 return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); 5216 } 5217 5218 #if ENABLE_HUSH_BASH_COMPAT 5219 static char **expand_strvec_to_strvec_singleword_noglob(char **argv) 5220 { 5221 return expand_variables(argv, EXP_FLAG_SINGLEWORD); 5222 } 5223 #endif 5224 5225 /* Used for expansion of right hand of assignments, 5226 * $((...)), heredocs, variable espansion parts. 5227 * 5228 * NB: should NOT do globbing! 5229 * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" 5230 */ 5231 static char *expand_string_to_string(const char *str, int do_unbackslash) 5232 { 5233 #if !ENABLE_HUSH_BASH_COMPAT 5234 const int do_unbackslash = 1; 5235 #endif 5236 char *argv[2], **list; 5237 5238 debug_printf_expand("string_to_string<='%s'\n", str); 5239 /* This is generally an optimization, but it also 5240 * handles "", which otherwise trips over !list[0] check below. 5241 * (is this ever happens that we actually get str="" here?) 5242 */ 5243 if (!strchr(str, SPECIAL_VAR_SYMBOL) && !strchr(str, '\\')) { 5244 //TODO: Can use on strings with \ too, just unbackslash() them? 5245 debug_printf_expand("string_to_string(fast)=>'%s'\n", str); 5246 return xstrdup(str); 5247 } 5248 5249 argv[0] = (char*)str; 5250 argv[1] = NULL; 5251 list = expand_variables(argv, do_unbackslash 5252 ? EXP_FLAG_ESC_GLOB_CHARS | EXP_FLAG_SINGLEWORD 5253 : EXP_FLAG_SINGLEWORD 5254 ); 5255 if (HUSH_DEBUG) 5256 if (!list[0] || list[1]) 5257 bb_error_msg_and_die("BUG in varexp2"); 5258 /* actually, just move string 2*sizeof(char*) bytes back */ 5259 overlapping_strcpy((char*)list, list[0]); 5260 if (do_unbackslash) 5261 unbackslash((char*)list); 5262 debug_printf_expand("string_to_string=>'%s'\n", (char*)list); 5263 return (char*)list; 5264 } 5265 5266 /* Used for "eval" builtin */ 5267 static char* expand_strvec_to_string(char **argv) 5268 { 5269 char **list; 5270 5271 list = expand_variables(argv, EXP_FLAG_SINGLEWORD); 5272 /* Convert all NULs to spaces */ 5273 if (list[0]) { 5274 int n = 1; 5275 while (list[n]) { 5276 if (HUSH_DEBUG) 5277 if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) 5278 bb_error_msg_and_die("BUG in varexp3"); 5279 /* bash uses ' ' regardless of $IFS contents */ 5280 list[n][-1] = ' '; 5281 n++; 5282 } 5283 } 5284 overlapping_strcpy((char*)list, list[0]); 5285 debug_printf_expand("strvec_to_string='%s'\n", (char*)list); 5286 return (char*)list; 5287 } 5288 5289 static char **expand_assignments(char **argv, int count) 5290 { 5291 int i; 5292 char **p; 5293 5294 G.expanded_assignments = p = NULL; 5295 /* Expand assignments into one string each */ 5296 for (i = 0; i < count; i++) { 5297 G.expanded_assignments = p = add_string_to_strings(p, expand_string_to_string(argv[i], /*unbackslash:*/ 1)); 5298 } 5299 G.expanded_assignments = NULL; 5300 return p; 5301 } 5302 5303 5304 #if BB_MMU 5305 /* never called */ 5306 void re_execute_shell(char ***to_free, const char *s, 5307 char *g_argv0, char **g_argv, 5308 char **builtin_argv) NORETURN; 5309 5310 static void reset_traps_to_defaults(void) 5311 { 5312 /* This function is always called in a child shell 5313 * after fork (not vfork, NOMMU doesn't use this function). 5314 */ 5315 unsigned sig; 5316 unsigned mask; 5317 5318 /* Child shells are not interactive. 5319 * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling. 5320 * Testcase: (while :; do :; done) + ^Z should background. 5321 * Same goes for SIGTERM, SIGHUP, SIGINT. 5322 */ 5323 if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) 5324 return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ 5325 5326 /* Switching off SPECIAL_INTERACTIVE_SIGS. 5327 * Stupid. It can be done with *single* &= op, but we can't use 5328 * the fact that G.blocked_set is implemented as a bitmask 5329 * in libc... */ 5330 mask = (SPECIAL_INTERACTIVE_SIGS >> 1); 5331 sig = 1; 5332 while (1) { 5333 if (mask & 1) { 5334 /* Careful. Only if no trap or trap is not "" */ 5335 if (!G.traps || !G.traps[sig] || G.traps[sig][0]) 5336 sigdelset(&G.blocked_set, sig); 5337 } 5338 mask >>= 1; 5339 if (!mask) 5340 break; 5341 sig++; 5342 } 5343 /* Our homegrown sig mask is saner to work with :) */ 5344 G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; 5345 5346 /* Resetting all traps to default except empty ones */ 5347 mask = G.non_DFL_mask; 5348 if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { 5349 if (!G.traps[sig] || !G.traps[sig][0]) 5350 continue; 5351 free(G.traps[sig]); 5352 G.traps[sig] = NULL; 5353 /* There is no signal for 0 (EXIT) */ 5354 if (sig == 0) 5355 continue; 5356 /* There was a trap handler, we just removed it. 5357 * But if sig still has non-DFL handling, 5358 * we should not unblock the sig. */ 5359 if (mask & 1) 5360 continue; 5361 sigdelset(&G.blocked_set, sig); 5362 } 5363 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 5364 } 5365 5366 #else /* !BB_MMU */ 5367 5368 static void re_execute_shell(char ***to_free, const char *s, 5369 char *g_argv0, char **g_argv, 5370 char **builtin_argv) NORETURN; 5371 static void re_execute_shell(char ***to_free, const char *s, 5372 char *g_argv0, char **g_argv, 5373 char **builtin_argv) 5374 { 5375 # define NOMMU_HACK_FMT ("-$%x:%x:%x:%x:%x:%llx" IF_HUSH_LOOPS(":%x")) 5376 /* delims + 2 * (number of bytes in printed hex numbers) */ 5377 char param_buf[sizeof(NOMMU_HACK_FMT) + 2 * (sizeof(int)*6 + sizeof(long long)*1)]; 5378 char *heredoc_argv[4]; 5379 struct variable *cur; 5380 # if ENABLE_HUSH_FUNCTIONS 5381 struct function *funcp; 5382 # endif 5383 char **argv, **pp; 5384 unsigned cnt; 5385 unsigned long long empty_trap_mask; 5386 5387 if (!g_argv0) { /* heredoc */ 5388 argv = heredoc_argv; 5389 argv[0] = (char *) G.argv0_for_re_execing; 5390 argv[1] = (char *) "-<"; 5391 argv[2] = (char *) s; 5392 argv[3] = NULL; 5393 pp = &argv[3]; /* used as pointer to empty environment */ 5394 goto do_exec; 5395 } 5396 5397 cnt = 0; 5398 pp = builtin_argv; 5399 if (pp) while (*pp++) 5400 cnt++; 5401 5402 empty_trap_mask = 0; 5403 if (G.traps) { 5404 int sig; 5405 for (sig = 1; sig < NSIG; sig++) { 5406 if (G.traps[sig] && !G.traps[sig][0]) 5407 empty_trap_mask |= 1LL << sig; 5408 } 5409 } 5410 5411 sprintf(param_buf, NOMMU_HACK_FMT 5412 , (unsigned) G.root_pid 5413 , (unsigned) G.root_ppid 5414 , (unsigned) G.last_bg_pid 5415 , (unsigned) G.last_exitcode 5416 , cnt 5417 , empty_trap_mask 5418 IF_HUSH_LOOPS(, G.depth_of_loop) 5419 ); 5420 # undef NOMMU_HACK_FMT 5421 /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<etc...> <vars...> <funcs...> 5422 * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL 5423 */ 5424 cnt += 6; 5425 for (cur = G.top_var; cur; cur = cur->next) { 5426 if (!cur->flg_export || cur->flg_read_only) 5427 cnt += 2; 5428 } 5429 # if ENABLE_HUSH_FUNCTIONS 5430 for (funcp = G.top_func; funcp; funcp = funcp->next) 5431 cnt += 3; 5432 # endif 5433 pp = g_argv; 5434 while (*pp++) 5435 cnt++; 5436 *to_free = argv = pp = xzalloc(sizeof(argv[0]) * cnt); 5437 *pp++ = (char *) G.argv0_for_re_execing; 5438 *pp++ = param_buf; 5439 for (cur = G.top_var; cur; cur = cur->next) { 5440 if (strcmp(cur->varstr, hush_version_str) == 0) 5441 continue; 5442 if (cur->flg_read_only) { 5443 *pp++ = (char *) "-R"; 5444 *pp++ = cur->varstr; 5445 } else if (!cur->flg_export) { 5446 *pp++ = (char *) "-V"; 5447 *pp++ = cur->varstr; 5448 } 5449 } 5450 # if ENABLE_HUSH_FUNCTIONS 5451 for (funcp = G.top_func; funcp; funcp = funcp->next) { 5452 *pp++ = (char *) "-F"; 5453 *pp++ = funcp->name; 5454 *pp++ = funcp->body_as_string; 5455 } 5456 # endif 5457 /* We can pass activated traps here. Say, -Tnn:trap_string 5458 * 5459 * However, POSIX says that subshells reset signals with traps 5460 * to SIG_DFL. 5461 * I tested bash-3.2 and it not only does that with true subshells 5462 * of the form ( list ), but with any forked children shells. 5463 * I set trap "echo W" WINCH; and then tried: 5464 * 5465 * { echo 1; sleep 20; echo 2; } & 5466 * while true; do echo 1; sleep 20; echo 2; break; done & 5467 * true | { echo 1; sleep 20; echo 2; } | cat 5468 * 5469 * In all these cases sending SIGWINCH to the child shell 5470 * did not run the trap. If I add trap "echo V" WINCH; 5471 * _inside_ group (just before echo 1), it works. 5472 * 5473 * I conclude it means we don't need to pass active traps here. 5474 * Even if we would use signal handlers instead of signal masking 5475 * in order to implement trap handling, 5476 * exec syscall below resets signals to SIG_DFL for us. 5477 */ 5478 *pp++ = (char *) "-c"; 5479 *pp++ = (char *) s; 5480 if (builtin_argv) { 5481 while (*++builtin_argv) 5482 *pp++ = *builtin_argv; 5483 *pp++ = (char *) ""; 5484 } 5485 *pp++ = g_argv0; 5486 while (*g_argv) 5487 *pp++ = *g_argv++; 5488 /* *pp = NULL; - is already there */ 5489 pp = environ; 5490 5491 do_exec: 5492 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); 5493 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 5494 execve(bb_busybox_exec_path, argv, pp); 5495 /* Fallback. Useful for init=/bin/hush usage etc */ 5496 if (argv[0][0] == '/') 5497 execve(argv[0], argv, pp); 5498 xfunc_error_retval = 127; 5499 bb_error_msg_and_die("can't re-execute the shell"); 5500 } 5501 #endif /* !BB_MMU */ 5502 5503 5504 static int run_and_free_list(struct pipe *pi); 5505 5506 /* Executing from string: eval, sh -c '...' 5507 * or from file: /etc/profile, . file, sh <script>, sh (intereactive) 5508 * end_trigger controls how often we stop parsing 5509 * NUL: parse all, execute, return 5510 * ';': parse till ';' or newline, execute, repeat till EOF 5511 */ 5512 static void parse_and_run_stream(struct in_str *inp, int end_trigger) 5513 { 5514 /* Why we need empty flag? 5515 * An obscure corner case "false; ``; echo $?": 5516 * empty command in `` should still set $? to 0. 5517 * But we can't just set $? to 0 at the start, 5518 * this breaks "false; echo `echo $?`" case. 5519 */ 5520 bool empty = 1; 5521 while (1) { 5522 struct pipe *pipe_list; 5523 5524 pipe_list = parse_stream(NULL, inp, end_trigger); 5525 if (!pipe_list) { /* EOF */ 5526 if (empty) 5527 G.last_exitcode = 0; 5528 break; 5529 } 5530 debug_print_tree(pipe_list, 0); 5531 debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); 5532 run_and_free_list(pipe_list); 5533 empty = 0; 5534 } 5535 } 5536 5537 static void parse_and_run_string(const char *s) 5538 { 5539 struct in_str input; 5540 setup_string_in_str(&input, s); 5541 parse_and_run_stream(&input, '\0'); 5542 } 5543 5544 static void parse_and_run_file(FILE *f) 5545 { 5546 struct in_str input; 5547 setup_file_in_str(&input, f); 5548 parse_and_run_stream(&input, ';'); 5549 } 5550 5551 #if ENABLE_HUSH_TICK 5552 static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) 5553 { 5554 pid_t pid; 5555 int channel[2]; 5556 # if !BB_MMU 5557 char **to_free = NULL; 5558 # endif 5559 5560 xpipe(channel); 5561 pid = BB_MMU ? xfork() : xvfork(); 5562 if (pid == 0) { /* child */ 5563 disable_restore_tty_pgrp_on_exit(); 5564 /* Process substitution is not considered to be usual 5565 * 'command execution'. 5566 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. 5567 */ 5568 bb_signals(0 5569 + (1 << SIGTSTP) 5570 + (1 << SIGTTIN) 5571 + (1 << SIGTTOU) 5572 , SIG_IGN); 5573 CLEAR_RANDOM_T(&G.random_gen); /* or else $RANDOM repeats in child */ 5574 close(channel[0]); /* NB: close _first_, then move fd! */ 5575 xmove_fd(channel[1], 1); 5576 /* Prevent it from trying to handle ctrl-z etc */ 5577 IF_HUSH_JOB(G.run_list_level = 1;) 5578 /* Awful hack for `trap` or $(trap). 5579 * 5580 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html 5581 * contains an example where "trap" is executed in a subshell: 5582 * 5583 * save_traps=$(trap) 5584 * ... 5585 * eval "$save_traps" 5586 * 5587 * Standard does not say that "trap" in subshell shall print 5588 * parent shell's traps. It only says that its output 5589 * must have suitable form, but then, in the above example 5590 * (which is not supposed to be normative), it implies that. 5591 * 5592 * bash (and probably other shell) does implement it 5593 * (traps are reset to defaults, but "trap" still shows them), 5594 * but as a result, "trap" logic is hopelessly messed up: 5595 * 5596 * # trap 5597 * trap -- 'echo Ho' SIGWINCH <--- we have a handler 5598 * # (trap) <--- trap is in subshell - no output (correct, traps are reset) 5599 * # true | trap <--- trap is in subshell - no output (ditto) 5600 * # echo `true | trap` <--- in subshell - output (but traps are reset!) 5601 * trap -- 'echo Ho' SIGWINCH 5602 * # echo `(trap)` <--- in subshell in subshell - output 5603 * trap -- 'echo Ho' SIGWINCH 5604 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! 5605 * trap -- 'echo Ho' SIGWINCH 5606 * 5607 * The rules when to forget and when to not forget traps 5608 * get really complex and nonsensical. 5609 * 5610 * Our solution: ONLY bare $(trap) or `trap` is special. 5611 */ 5612 s = skip_whitespace(s); 5613 if (strncmp(s, "trap", 4) == 0 5614 && skip_whitespace(s + 4)[0] == '\0' 5615 ) { 5616 static const char *const argv[] = { NULL, NULL }; 5617 builtin_trap((char**)argv); 5618 exit(0); /* not _exit() - we need to fflush */ 5619 } 5620 # if BB_MMU 5621 reset_traps_to_defaults(); 5622 parse_and_run_string(s); 5623 _exit(G.last_exitcode); 5624 # else 5625 /* We re-execute after vfork on NOMMU. This makes this script safe: 5626 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >BIG 5627 * huge=`cat BIG` # was blocking here forever 5628 * echo OK 5629 */ 5630 re_execute_shell(&to_free, 5631 s, 5632 G.global_argv[0], 5633 G.global_argv + 1, 5634 NULL); 5635 # endif 5636 } 5637 5638 /* parent */ 5639 *pid_p = pid; 5640 # if ENABLE_HUSH_FAST 5641 G.count_SIGCHLD++; 5642 //bb_error_msg("[%d] fork in generate_stream_from_string:" 5643 // " G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", 5644 // getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 5645 # endif 5646 enable_restore_tty_pgrp_on_exit(); 5647 # if !BB_MMU 5648 free(to_free); 5649 # endif 5650 close(channel[1]); 5651 close_on_exec_on(channel[0]); 5652 return xfdopen_for_read(channel[0]); 5653 } 5654 5655 /* Return code is exit status of the process that is run. */ 5656 static int process_command_subs(o_string *dest, const char *s) 5657 { 5658 FILE *fp; 5659 struct in_str pipe_str; 5660 pid_t pid; 5661 int status, ch, eol_cnt; 5662 5663 fp = generate_stream_from_string(s, &pid); 5664 5665 /* Now send results of command back into original context */ 5666 setup_file_in_str(&pipe_str, fp); 5667 eol_cnt = 0; 5668 while ((ch = i_getch(&pipe_str)) != EOF) { 5669 if (ch == '\n') { 5670 eol_cnt++; 5671 continue; 5672 } 5673 while (eol_cnt) { 5674 o_addchr(dest, '\n'); 5675 eol_cnt--; 5676 } 5677 o_addQchr(dest, ch); 5678 } 5679 5680 debug_printf("done reading from `cmd` pipe, closing it\n"); 5681 fclose(fp); 5682 /* We need to extract exitcode. Test case 5683 * "true; echo `sleep 1; false` $?" 5684 * should print 1 */ 5685 safe_waitpid(pid, &status, 0); 5686 debug_printf("child exited. returning its exitcode:%d\n", WEXITSTATUS(status)); 5687 return WEXITSTATUS(status); 5688 } 5689 #endif /* ENABLE_HUSH_TICK */ 5690 5691 5692 static void setup_heredoc(struct redir_struct *redir) 5693 { 5694 struct fd_pair pair; 5695 pid_t pid; 5696 int len, written; 5697 /* the _body_ of heredoc (misleading field name) */ 5698 const char *heredoc = redir->rd_filename; 5699 char *expanded; 5700 #if !BB_MMU 5701 char **to_free; 5702 #endif 5703 5704 expanded = NULL; 5705 if (!(redir->rd_dup & HEREDOC_QUOTED)) { 5706 expanded = encode_then_expand_string(heredoc, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 5707 if (expanded) 5708 heredoc = expanded; 5709 } 5710 len = strlen(heredoc); 5711 5712 close(redir->rd_fd); /* often saves dup2+close in xmove_fd */ 5713 xpiped_pair(pair); 5714 xmove_fd(pair.rd, redir->rd_fd); 5715 5716 /* Try writing without forking. Newer kernels have 5717 * dynamically growing pipes. Must use non-blocking write! */ 5718 ndelay_on(pair.wr); 5719 while (1) { 5720 written = write(pair.wr, heredoc, len); 5721 if (written <= 0) 5722 break; 5723 len -= written; 5724 if (len == 0) { 5725 close(pair.wr); 5726 free(expanded); 5727 return; 5728 } 5729 heredoc += written; 5730 } 5731 ndelay_off(pair.wr); 5732 5733 /* Okay, pipe buffer was not big enough */ 5734 /* Note: we must not create a stray child (bastard? :) 5735 * for the unsuspecting parent process. Child creates a grandchild 5736 * and exits before parent execs the process which consumes heredoc 5737 * (that exec happens after we return from this function) */ 5738 #if !BB_MMU 5739 to_free = NULL; 5740 #endif 5741 pid = xvfork(); 5742 if (pid == 0) { 5743 /* child */ 5744 disable_restore_tty_pgrp_on_exit(); 5745 pid = BB_MMU ? xfork() : xvfork(); 5746 if (pid != 0) 5747 _exit(0); 5748 /* grandchild */ 5749 close(redir->rd_fd); /* read side of the pipe */ 5750 #if BB_MMU 5751 full_write(pair.wr, heredoc, len); /* may loop or block */ 5752 _exit(0); 5753 #else 5754 /* Delegate blocking writes to another process */ 5755 xmove_fd(pair.wr, STDOUT_FILENO); 5756 re_execute_shell(&to_free, heredoc, NULL, NULL, NULL); 5757 #endif 5758 } 5759 /* parent */ 5760 #if ENABLE_HUSH_FAST 5761 G.count_SIGCHLD++; 5762 //bb_error_msg("[%d] fork in setup_heredoc: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 5763 #endif 5764 enable_restore_tty_pgrp_on_exit(); 5765 #if !BB_MMU 5766 free(to_free); 5767 #endif 5768 close(pair.wr); 5769 free(expanded); 5770 wait(NULL); /* wait till child has died */ 1277 5771 } 1278 5772 1279 5773 /* squirrel != NULL means we squirrel away copies of stdin, stdout, 1280 5774 * and stderr if they are redirected. */ 1281 static int setup_redirects(struct c hild_prog*prog, int squirrel[])5775 static int setup_redirects(struct command *prog, int squirrel[]) 1282 5776 { 1283 5777 int openfd, mode; … … 1285 5779 1286 5780 for (redir = prog->redirects; redir; redir = redir->next) { 1287 if (redir->dup == -1 && redir->word.gl_pathv == NULL) { 1288 /* something went wrong in the parse. Pretend it didn't happen */ 5781 if (redir->rd_type == REDIRECT_HEREDOC2) { 5782 /* rd_fd<<HERE case */ 5783 if (squirrel && redir->rd_fd < 3 5784 && squirrel[redir->rd_fd] < 0 5785 ) { 5786 squirrel[redir->rd_fd] = dup(redir->rd_fd); 5787 } 5788 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 5789 * of the heredoc */ 5790 debug_printf_parse("set heredoc '%s'\n", 5791 redir->rd_filename); 5792 setup_heredoc(redir); 1289 5793 continue; 1290 5794 } 1291 if (redir->dup == -1) { 1292 mode = redir_table[redir->type].mode; 1293 openfd = open_or_warn(redir->word.gl_pathv[0], mode); 5795 5796 if (redir->rd_dup == REDIRFD_TO_FILE) { 5797 /* rd_fd<*>file case (<*> is <,>,>>,<>) */ 5798 char *p; 5799 if (redir->rd_filename == NULL) { 5800 /* Something went wrong in the parse. 5801 * Pretend it didn't happen */ 5802 bb_error_msg("bug in redirect parse"); 5803 continue; 5804 } 5805 mode = redir_table[redir->rd_type].mode; 5806 p = expand_string_to_string(redir->rd_filename, /*unbackslash:*/ 1); 5807 openfd = open_or_warn(p, mode); 5808 free(p); 1294 5809 if (openfd < 0) { 1295 5810 /* this could get lost if stderr has been redirected, but 1296 bash and ash both lose it as well (though zsh doesn't!) */ 5811 * bash and ash both lose it as well (though zsh doesn't!) */ 5812 //what the above comment tries to say? 1297 5813 return 1; 1298 5814 } 1299 5815 } else { 1300 openfd = redir->dup; 1301 } 1302 1303 if (openfd != redir->fd) { 1304 if (squirrel && redir->fd < 3) { 1305 squirrel[redir->fd] = dup(redir->fd); 1306 } 1307 if (openfd == -3) { 1308 close(openfd); 5816 /* rd_fd<*>rd_dup or rd_fd<*>- cases */ 5817 openfd = redir->rd_dup; 5818 } 5819 5820 if (openfd != redir->rd_fd) { 5821 if (squirrel && redir->rd_fd < 3 5822 && squirrel[redir->rd_fd] < 0 5823 ) { 5824 squirrel[redir->rd_fd] = dup(redir->rd_fd); 5825 } 5826 if (openfd == REDIRFD_CLOSE) { 5827 /* "n>-" means "close me" */ 5828 close(redir->rd_fd); 1309 5829 } else { 1310 dup2(openfd, redir->fd);1311 if (redir-> dup == -1)5830 xdup2(openfd, redir->rd_fd); 5831 if (redir->rd_dup == REDIRFD_TO_FILE) 1312 5832 close(openfd); 1313 5833 } … … 1329 5849 } 1330 5850 1331 /* never returns */ 1332 /* XXX no exit() here. If you don't exec, use _exit instead. 5851 static char *find_in_path(const char *arg) 5852 { 5853 char *ret = NULL; 5854 const char *PATH = get_local_var_value("PATH"); 5855 5856 if (!PATH) 5857 return NULL; 5858 5859 while (1) { 5860 const char *end = strchrnul(PATH, ':'); 5861 int sz = end - PATH; /* must be int! */ 5862 5863 free(ret); 5864 if (sz != 0) { 5865 ret = xasprintf("%.*s/%s", sz, PATH, arg); 5866 } else { 5867 /* We have xxx::yyyy in $PATH, 5868 * it means "use current dir" */ 5869 ret = xstrdup(arg); 5870 } 5871 if (access(ret, F_OK) == 0) 5872 break; 5873 5874 if (*end == '\0') { 5875 free(ret); 5876 return NULL; 5877 } 5878 PATH = end + 1; 5879 } 5880 5881 return ret; 5882 } 5883 5884 static const struct built_in_command *find_builtin_helper(const char *name, 5885 const struct built_in_command *x, 5886 const struct built_in_command *end) 5887 { 5888 while (x != end) { 5889 if (strcmp(name, x->b_cmd) != 0) { 5890 x++; 5891 continue; 5892 } 5893 debug_printf_exec("found builtin '%s'\n", name); 5894 return x; 5895 } 5896 return NULL; 5897 } 5898 static const struct built_in_command *find_builtin1(const char *name) 5899 { 5900 return find_builtin_helper(name, bltins1, &bltins1[ARRAY_SIZE(bltins1)]); 5901 } 5902 static const struct built_in_command *find_builtin(const char *name) 5903 { 5904 const struct built_in_command *x = find_builtin1(name); 5905 if (x) 5906 return x; 5907 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); 5908 } 5909 5910 #if ENABLE_HUSH_FUNCTIONS 5911 static struct function **find_function_slot(const char *name) 5912 { 5913 struct function **funcpp = &G.top_func; 5914 while (*funcpp) { 5915 if (strcmp(name, (*funcpp)->name) == 0) { 5916 break; 5917 } 5918 funcpp = &(*funcpp)->next; 5919 } 5920 return funcpp; 5921 } 5922 5923 static const struct function *find_function(const char *name) 5924 { 5925 const struct function *funcp = *find_function_slot(name); 5926 if (funcp) 5927 debug_printf_exec("found function '%s'\n", name); 5928 return funcp; 5929 } 5930 5931 /* Note: takes ownership on name ptr */ 5932 static struct function *new_function(char *name) 5933 { 5934 struct function **funcpp = find_function_slot(name); 5935 struct function *funcp = *funcpp; 5936 5937 if (funcp != NULL) { 5938 struct command *cmd = funcp->parent_cmd; 5939 debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd); 5940 if (!cmd) { 5941 debug_printf_exec("freeing & replacing function '%s'\n", funcp->name); 5942 free(funcp->name); 5943 /* Note: if !funcp->body, do not free body_as_string! 5944 * This is a special case of "-F name body" function: 5945 * body_as_string was not malloced! */ 5946 if (funcp->body) { 5947 free_pipe_list(funcp->body); 5948 # if !BB_MMU 5949 free(funcp->body_as_string); 5950 # endif 5951 } 5952 } else { 5953 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name); 5954 cmd->argv[0] = funcp->name; 5955 cmd->group = funcp->body; 5956 # if !BB_MMU 5957 cmd->group_as_string = funcp->body_as_string; 5958 # endif 5959 } 5960 } else { 5961 debug_printf_exec("remembering new function '%s'\n", name); 5962 funcp = *funcpp = xzalloc(sizeof(*funcp)); 5963 /*funcp->next = NULL;*/ 5964 } 5965 5966 funcp->name = name; 5967 return funcp; 5968 } 5969 5970 static void unset_func(const char *name) 5971 { 5972 struct function **funcpp = find_function_slot(name); 5973 struct function *funcp = *funcpp; 5974 5975 if (funcp != NULL) { 5976 debug_printf_exec("freeing function '%s'\n", funcp->name); 5977 *funcpp = funcp->next; 5978 /* funcp is unlinked now, deleting it. 5979 * Note: if !funcp->body, the function was created by 5980 * "-F name body", do not free ->body_as_string 5981 * and ->name as they were not malloced. */ 5982 if (funcp->body) { 5983 free_pipe_list(funcp->body); 5984 free(funcp->name); 5985 # if !BB_MMU 5986 free(funcp->body_as_string); 5987 # endif 5988 } 5989 free(funcp); 5990 } 5991 } 5992 5993 # if BB_MMU 5994 #define exec_function(to_free, funcp, argv) \ 5995 exec_function(funcp, argv) 5996 # endif 5997 static void exec_function(char ***to_free, 5998 const struct function *funcp, 5999 char **argv) NORETURN; 6000 static void exec_function(char ***to_free, 6001 const struct function *funcp, 6002 char **argv) 6003 { 6004 # if BB_MMU 6005 int n = 1; 6006 6007 argv[0] = G.global_argv[0]; 6008 G.global_argv = argv; 6009 while (*++argv) 6010 n++; 6011 G.global_argc = n; 6012 /* On MMU, funcp->body is always non-NULL */ 6013 n = run_list(funcp->body); 6014 fflush_all(); 6015 _exit(n); 6016 # else 6017 re_execute_shell(to_free, 6018 funcp->body_as_string, 6019 G.global_argv[0], 6020 argv + 1, 6021 NULL); 6022 # endif 6023 } 6024 6025 static int run_function(const struct function *funcp, char **argv) 6026 { 6027 int rc; 6028 save_arg_t sv; 6029 smallint sv_flg; 6030 6031 save_and_replace_G_args(&sv, argv); 6032 6033 /* "we are in function, ok to use return" */ 6034 sv_flg = G.flag_return_in_progress; 6035 G.flag_return_in_progress = -1; 6036 # if ENABLE_HUSH_LOCAL 6037 G.func_nest_level++; 6038 # endif 6039 6040 /* On MMU, funcp->body is always non-NULL */ 6041 # if !BB_MMU 6042 if (!funcp->body) { 6043 /* Function defined by -F */ 6044 parse_and_run_string(funcp->body_as_string); 6045 rc = G.last_exitcode; 6046 } else 6047 # endif 6048 { 6049 rc = run_list(funcp->body); 6050 } 6051 6052 # if ENABLE_HUSH_LOCAL 6053 { 6054 struct variable *var; 6055 struct variable **var_pp; 6056 6057 var_pp = &G.top_var; 6058 while ((var = *var_pp) != NULL) { 6059 if (var->func_nest_level < G.func_nest_level) { 6060 var_pp = &var->next; 6061 continue; 6062 } 6063 /* Unexport */ 6064 if (var->flg_export) 6065 bb_unsetenv(var->varstr); 6066 /* Remove from global list */ 6067 *var_pp = var->next; 6068 /* Free */ 6069 if (!var->max_len) 6070 free(var->varstr); 6071 free(var); 6072 } 6073 G.func_nest_level--; 6074 } 6075 # endif 6076 G.flag_return_in_progress = sv_flg; 6077 6078 restore_G_args(&sv, argv); 6079 6080 return rc; 6081 } 6082 #endif /* ENABLE_HUSH_FUNCTIONS */ 6083 6084 6085 #if BB_MMU 6086 #define exec_builtin(to_free, x, argv) \ 6087 exec_builtin(x, argv) 6088 #else 6089 #define exec_builtin(to_free, x, argv) \ 6090 exec_builtin(to_free, argv) 6091 #endif 6092 static void exec_builtin(char ***to_free, 6093 const struct built_in_command *x, 6094 char **argv) NORETURN; 6095 static void exec_builtin(char ***to_free, 6096 const struct built_in_command *x, 6097 char **argv) 6098 { 6099 #if BB_MMU 6100 int rcode = x->b_function(argv); 6101 fflush_all(); 6102 _exit(rcode); 6103 #else 6104 /* On NOMMU, we must never block! 6105 * Example: { sleep 99 | read line; } & echo Ok 6106 */ 6107 re_execute_shell(to_free, 6108 argv[0], 6109 G.global_argv[0], 6110 G.global_argv + 1, 6111 argv); 6112 #endif 6113 } 6114 6115 6116 static void execvp_or_die(char **argv) NORETURN; 6117 static void execvp_or_die(char **argv) 6118 { 6119 debug_printf_exec("execing '%s'\n", argv[0]); 6120 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6121 execvp(argv[0], argv); 6122 bb_perror_msg("can't execute '%s'", argv[0]); 6123 _exit(127); /* bash compat */ 6124 } 6125 6126 #if ENABLE_HUSH_MODE_X 6127 static void dump_cmd_in_x_mode(char **argv) 6128 { 6129 if (G_x_mode && argv) { 6130 /* We want to output the line in one write op */ 6131 char *buf, *p; 6132 int len; 6133 int n; 6134 6135 len = 3; 6136 n = 0; 6137 while (argv[n]) 6138 len += strlen(argv[n++]) + 1; 6139 buf = xmalloc(len); 6140 buf[0] = '+'; 6141 p = buf + 1; 6142 n = 0; 6143 while (argv[n]) 6144 p += sprintf(p, " %s", argv[n++]); 6145 *p++ = '\n'; 6146 *p = '\0'; 6147 fputs(buf, stderr); 6148 free(buf); 6149 } 6150 } 6151 #else 6152 # define dump_cmd_in_x_mode(argv) ((void)0) 6153 #endif 6154 6155 #if BB_MMU 6156 #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ 6157 pseudo_exec_argv(argv, assignment_cnt, argv_expanded) 6158 #define pseudo_exec(nommu_save, command, argv_expanded) \ 6159 pseudo_exec(command, argv_expanded) 6160 #endif 6161 6162 /* Called after [v]fork() in run_pipe, or from builtin_exec. 6163 * Never returns. 6164 * Don't exit() here. If you don't exec, use _exit instead. 1333 6165 * The at_exit handlers apparently confuse the calling process, 1334 6166 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 1335 static void pseudo_exec_argv( char **argv)1336 { 1337 int i, rcode;1338 char *p; 1339 const struct built_in_command *x;1340 1341 for (i = 0; is_assignment(argv[i]); i++){1342 debug_printf_exec("pid %d environment modification: %s\n",1343 getpid(), argv[i]); 1344 // FIXME: vfork case?? 1345 p = expand_string_to_string(argv[i]);1346 putenv(p); 1347 }1348 argv += i;1349 /* If a variable is assigned in a forest, and nobody listens,1350 * was it ever really set?1351 */1352 if (argv[0] == NULL) {6167 static void pseudo_exec_argv(nommu_save_t *nommu_save, 6168 char **argv, int assignment_cnt, 6169 char **argv_expanded) NORETURN; 6170 static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, 6171 char **argv, int assignment_cnt, 6172 char **argv_expanded) 6173 { 6174 char **new_env; 6175 6176 new_env = expand_assignments(argv, assignment_cnt); 6177 dump_cmd_in_x_mode(new_env); 6178 6179 if (!argv[assignment_cnt]) { 6180 /* Case when we are here: ... | var=val | ... 6181 * (note that we do not exit early, i.e., do not optimize out 6182 * expand_assignments(): think about ... | var=`sleep 1` | ... 6183 */ 6184 free_strings(new_env); 1353 6185 _exit(EXIT_SUCCESS); 1354 6186 } 1355 6187 1356 argv = expand_strvec_to_strvec(argv); 1357 1358 /* 1359 * Check if the command matches any of the builtins. 6188 #if BB_MMU 6189 set_vars_and_save_old(new_env); 6190 free(new_env); /* optional */ 6191 /* we can also destroy set_vars_and_save_old's return value, 6192 * to save memory */ 6193 #else 6194 nommu_save->new_env = new_env; 6195 nommu_save->old_vars = set_vars_and_save_old(new_env); 6196 #endif 6197 6198 if (argv_expanded) { 6199 argv = argv_expanded; 6200 } else { 6201 argv = expand_strvec_to_strvec(argv + assignment_cnt); 6202 #if !BB_MMU 6203 nommu_save->argv = argv; 6204 #endif 6205 } 6206 dump_cmd_in_x_mode(argv); 6207 6208 #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU 6209 if (strchr(argv[0], '/') != NULL) 6210 goto skip; 6211 #endif 6212 6213 /* Check if the command matches any of the builtins. 1360 6214 * Depending on context, this might be redundant. But it's 1361 6215 * easier to waste a few CPU cycles than it is to figure out 1362 6216 * if this is one of those cases. 1363 6217 */ 1364 for (x = bltins; x->cmd; x++) { 1365 if (strcmp(argv[0], x->cmd) == 0) { 1366 debug_printf_exec("running builtin '%s'\n", argv[0]); 1367 rcode = x->function(argv); 1368 fflush(stdout); 1369 _exit(rcode); 1370 } 1371 } 1372 6218 { 6219 /* On NOMMU, it is more expensive to re-execute shell 6220 * just in order to run echo or test builtin. 6221 * It's better to skip it here and run corresponding 6222 * non-builtin later. */ 6223 const struct built_in_command *x; 6224 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]); 6225 if (x) { 6226 exec_builtin(&nommu_save->argv_from_re_execing, x, argv); 6227 } 6228 } 6229 #if ENABLE_HUSH_FUNCTIONS 6230 /* Check if the command matches any functions */ 6231 { 6232 const struct function *funcp = find_function(argv[0]); 6233 if (funcp) { 6234 exec_function(&nommu_save->argv_from_re_execing, funcp, argv); 6235 } 6236 } 6237 #endif 6238 6239 #if ENABLE_FEATURE_SH_STANDALONE 1373 6240 /* Check if the command matches any busybox applets */ 1374 #if ENABLE_FEATURE_SH_STANDALONE 1375 if (strchr(argv[0], '/') == NULL) { 1376 const struct bb_applet *a = find_applet_by_name(argv[0]); 1377 if (a) { 1378 if (a->noexec) { 1379 current_applet = a; 6241 { 6242 int a = find_applet_by_name(argv[0]); 6243 if (a >= 0) { 6244 # if BB_MMU /* see above why on NOMMU it is not allowed */ 6245 if (APPLET_IS_NOEXEC(a)) { 1380 6246 debug_printf_exec("running applet '%s'\n", argv[0]); 1381 // is it ok that run_current_applet_and_exit() does exit(), not _exit()? 1382 run_current_applet_and_exit(argv);1383 } 1384 /* re-exec ourselves with the new arguments */6247 run_applet_no_and_exit(a, argv); 6248 } 6249 # endif 6250 /* Re-exec ourselves */ 1385 6251 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 1386 execvp(bb_busybox_exec_path, argv); 6252 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6253 execv(bb_busybox_exec_path, argv); 1387 6254 /* If they called chroot or otherwise made the binary no longer 1388 6255 * executable, fall through */ … … 1391 6258 #endif 1392 6259 1393 debug_printf_exec("execing '%s'\n", argv[0]); 1394 execvp(argv[0], argv); 1395 bb_perror_msg("cannot exec '%s'", argv[0]); 1396 _exit(1); 1397 } 1398 1399 static void pseudo_exec(struct child_prog *child) 1400 { 1401 // FIXME: buggy wrt NOMMU! Must not modify any global data 1402 // until it does exec/_exit, but currently it does. 1403 int rcode; 1404 1405 if (child->argv) { 1406 pseudo_exec_argv(child->argv); 1407 } 1408 1409 if (child->group) { 1410 // FIXME: do not modify globals! Think vfork! 1411 #if ENABLE_HUSH_INTERACTIVE 1412 debug_printf_exec("pseudo_exec: setting interactive_fd=0\n"); 1413 interactive_fd = 0; /* crucial!!!! */ 1414 #endif 1415 debug_printf_exec("pseudo_exec: run_list_real\n"); 1416 rcode = run_list_real(child->group); 6260 #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU 6261 skip: 6262 #endif 6263 execvp_or_die(argv); 6264 } 6265 6266 /* Called after [v]fork() in run_pipe 6267 */ 6268 static void pseudo_exec(nommu_save_t *nommu_save, 6269 struct command *command, 6270 char **argv_expanded) NORETURN; 6271 static void pseudo_exec(nommu_save_t *nommu_save, 6272 struct command *command, 6273 char **argv_expanded) 6274 { 6275 if (command->argv) { 6276 pseudo_exec_argv(nommu_save, command->argv, 6277 command->assignment_cnt, argv_expanded); 6278 } 6279 6280 if (command->group) { 6281 /* Cases when we are here: 6282 * ( list ) 6283 * { list } & 6284 * ... | ( list ) | ... 6285 * ... | { list } | ... 6286 */ 6287 #if BB_MMU 6288 int rcode; 6289 debug_printf_exec("pseudo_exec: run_list\n"); 6290 reset_traps_to_defaults(); 6291 rcode = run_list(command->group); 1417 6292 /* OK to leak memory by not calling free_pipe_list, 1418 6293 * since this process is about to exit */ 1419 6294 _exit(rcode); 1420 } 1421 1422 /* Can happen. See what bash does with ">foo" by itself. */ 1423 debug_printf("trying to pseudo_exec null command\n"); 6295 #else 6296 re_execute_shell(&nommu_save->argv_from_re_execing, 6297 command->group_as_string, 6298 G.global_argv[0], 6299 G.global_argv + 1, 6300 NULL); 6301 #endif 6302 } 6303 6304 /* Case when we are here: ... | >file */ 6305 debug_printf_exec("pseudo_exec'ed null command\n"); 1424 6306 _exit(EXIT_SUCCESS); 1425 6307 } … … 1437 6319 if (pi->cmdtext) 1438 6320 return pi->cmdtext; 1439 argv = pi->progs[0].argv; 1440 if (!argv || !argv[0]) 1441 return (pi->cmdtext = xzalloc(1)); 6321 argv = pi->cmds[0].argv; 6322 if (!argv || !argv[0]) { 6323 pi->cmdtext = xzalloc(1); 6324 return pi->cmdtext; 6325 } 1442 6326 1443 6327 len = 0; 1444 do len += strlen(*argv) + 1; while (*++argv); 1445 pi->cmdtext = p = xmalloc(len); 1446 argv = pi->progs[0].argv; 6328 do { 6329 len += strlen(*argv) + 1; 6330 } while (*++argv); 6331 p = xmalloc(len); 6332 pi->cmdtext = p; 6333 argv = pi->cmds[0].argv; 1447 6334 do { 1448 6335 len = strlen(*argv); … … 1457 6344 static void insert_bg_job(struct pipe *pi) 1458 6345 { 1459 struct pipe * thejob;6346 struct pipe *job, **jobp; 1460 6347 int i; 1461 6348 1462 6349 /* Linear search for the ID of the job to use */ 1463 6350 pi->jobid = 1; 1464 for (thejob = job_list; thejob; thejob = thejob->next) 1465 if (thejob->jobid >= pi->jobid) 1466 pi->jobid = thejob->jobid + 1; 1467 1468 /* Add thejob to the list of running jobs */ 1469 if (!job_list) { 1470 thejob = job_list = xmalloc(sizeof(*thejob)); 6351 for (job = G.job_list; job; job = job->next) 6352 if (job->jobid >= pi->jobid) 6353 pi->jobid = job->jobid + 1; 6354 6355 /* Add job to the list of running jobs */ 6356 jobp = &G.job_list; 6357 while ((job = *jobp) != NULL) 6358 jobp = &job->next; 6359 job = *jobp = xmalloc(sizeof(*job)); 6360 6361 *job = *pi; /* physical copy */ 6362 job->next = NULL; 6363 job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds); 6364 /* Cannot copy entire pi->cmds[] vector! This causes double frees */ 6365 for (i = 0; i < pi->num_cmds; i++) { 6366 job->cmds[i].pid = pi->cmds[i].pid; 6367 /* all other fields are not used and stay zero */ 6368 } 6369 job->cmdtext = xstrdup(get_cmdtext(pi)); 6370 6371 if (G_interactive_fd) 6372 printf("[%d] %d %s\n", job->jobid, job->cmds[0].pid, job->cmdtext); 6373 G.last_jobid = job->jobid; 6374 } 6375 6376 static void remove_bg_job(struct pipe *pi) 6377 { 6378 struct pipe *prev_pipe; 6379 6380 if (pi == G.job_list) { 6381 G.job_list = pi->next; 1471 6382 } else { 1472 for (thejob = job_list; thejob->next; thejob = thejob->next) 1473 continue; 1474 thejob->next = xmalloc(sizeof(*thejob)); 1475 thejob = thejob->next; 1476 } 1477 1478 /* Physically copy the struct job */ 1479 memcpy(thejob, pi, sizeof(struct pipe)); 1480 thejob->progs = xzalloc(sizeof(pi->progs[0]) * pi->num_progs); 1481 /* We cannot copy entire pi->progs[] vector! Double free()s will happen */ 1482 for (i = 0; i < pi->num_progs; i++) { 1483 // TODO: do we really need to have so many fields which are just dead weight 1484 // at execution stage? 1485 thejob->progs[i].pid = pi->progs[i].pid; 1486 /* all other fields are not used and stay zero */ 1487 } 1488 thejob->next = NULL; 1489 thejob->cmdtext = xstrdup(get_cmdtext(pi)); 1490 1491 /* We don't wait for background thejobs to return -- append it 1492 to the list of backgrounded thejobs and leave it alone */ 1493 printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext); 1494 last_bg_pid = thejob->progs[0].pid; 1495 last_jobid = thejob->jobid; 1496 } 1497 1498 static void remove_bg_job(struct pipe *pi) 1499 { 1500 struct pipe *prev_pipe; 1501 1502 if (pi == job_list) { 1503 job_list = pi->next; 1504 } else { 1505 prev_pipe = job_list; 6383 prev_pipe = G.job_list; 1506 6384 while (prev_pipe->next != pi) 1507 6385 prev_pipe = prev_pipe->next; 1508 6386 prev_pipe->next = pi->next; 1509 6387 } 1510 if ( job_list)1511 last_jobid =job_list->jobid;6388 if (G.job_list) 6389 G.last_jobid = G.job_list->jobid; 1512 6390 else 1513 last_jobid = 0;1514 } 1515 1516 /* remove a backgrounded job */6391 G.last_jobid = 0; 6392 } 6393 6394 /* Remove a backgrounded job */ 1517 6395 static void delete_finished_bg_job(struct pipe *pi) 1518 6396 { 1519 6397 remove_bg_job(pi); 1520 pi->stopped_progs = 0; 1521 free_pipe(pi, 0); 1522 free(pi); 6398 free_pipe(pi); 1523 6399 } 1524 6400 #endif /* JOB */ 1525 6401 1526 /* Check sto see if any processes have exited -- if they1527 1528 static int checkjobs(struct pipe *fg_pipe)6402 /* Check to see if any processes have exited -- if they 6403 * have, figure out why and see if a job has completed */ 6404 static int checkjobs(struct pipe *fg_pipe) 1529 6405 { 1530 6406 int attributes; 1531 6407 int status; 1532 6408 #if ENABLE_HUSH_JOB 1533 int prognum = 0;1534 6409 struct pipe *pi; 1535 6410 #endif … … 1537 6412 int rcode = 0; 1538 6413 6414 debug_printf_jobs("checkjobs %p\n", fg_pipe); 6415 1539 6416 attributes = WUNTRACED; 1540 if (fg_pipe == NULL) {6417 if (fg_pipe == NULL) 1541 6418 attributes |= WNOHANG; 1542 } 6419 6420 errno = 0; 6421 #if ENABLE_HUSH_FAST 6422 if (G.handled_SIGCHLD == G.count_SIGCHLD) { 6423 //bb_error_msg("[%d] checkjobs: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d children?:%d fg_pipe:%p", 6424 //getpid(), G.count_SIGCHLD, G.handled_SIGCHLD, G.we_have_children, fg_pipe); 6425 /* There was neither fork nor SIGCHLD since last waitpid */ 6426 /* Avoid doing waitpid syscall if possible */ 6427 if (!G.we_have_children) { 6428 errno = ECHILD; 6429 return -1; 6430 } 6431 if (fg_pipe == NULL) { /* is WNOHANG set? */ 6432 /* We have children, but they did not exit 6433 * or stop yet (we saw no SIGCHLD) */ 6434 return 0; 6435 } 6436 /* else: !WNOHANG, waitpid will block, can't short-circuit */ 6437 } 6438 #endif 1543 6439 1544 6440 /* Do we do this right? … … 1548 6444 * bash-3.00# echo $? 1549 6445 * 1 <========== bg pipe is not fully done, but exitcode is already known! 6446 * [hush 1.14.0: yes we do it right] 1550 6447 */ 1551 1552 //FIXME: non-interactive bash does not continue even if all processes in fg pipe1553 //are stopped. Testcase: "cat | cat" in a script (not on command line)1554 // + killall -STOP cat1555 1556 6448 wait_more: 1557 while ((childpid = waitpid(-1, &status, attributes)) > 0) { 1558 const int dead = WIFEXITED(status) || WIFSIGNALED(status); 1559 1560 #ifdef DEBUG_SHELL_JOBS 6449 while (1) { 6450 int i; 6451 int dead; 6452 6453 #if ENABLE_HUSH_FAST 6454 i = G.count_SIGCHLD; 6455 #endif 6456 childpid = waitpid(-1, &status, attributes); 6457 if (childpid <= 0) { 6458 if (childpid && errno != ECHILD) 6459 bb_perror_msg("waitpid"); 6460 #if ENABLE_HUSH_FAST 6461 else { /* Until next SIGCHLD, waitpid's are useless */ 6462 G.we_have_children = (childpid == 0); 6463 G.handled_SIGCHLD = i; 6464 //bb_error_msg("[%d] checkjobs: waitpid returned <= 0, G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 6465 } 6466 #endif 6467 break; 6468 } 6469 dead = WIFEXITED(status) || WIFSIGNALED(status); 6470 6471 #if DEBUG_JOBS 1561 6472 if (WIFSTOPPED(status)) 1562 6473 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n", … … 1571 6482 /* Were we asked to wait for fg pipe? */ 1572 6483 if (fg_pipe) { 1573 int i; 1574 for (i = 0; i < fg_pipe->num_progs; i++) { 1575 debug_printf_jobs("check pid %d\n", fg_pipe->progs[i].pid); 1576 if (fg_pipe->progs[i].pid == childpid) { 1577 /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ 1578 if (dead) { 1579 fg_pipe->progs[i].pid = 0; 1580 fg_pipe->running_progs--; 1581 if (i == fg_pipe->num_progs-1) 1582 /* last process gives overall exitstatus */ 1583 rcode = WEXITSTATUS(status); 1584 } else { 1585 fg_pipe->progs[i].is_stopped = 1; 1586 fg_pipe->stopped_progs++; 6484 i = fg_pipe->num_cmds; 6485 while (--i >= 0) { 6486 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); 6487 if (fg_pipe->cmds[i].pid != childpid) 6488 continue; 6489 if (dead) { 6490 int ex; 6491 fg_pipe->cmds[i].pid = 0; 6492 fg_pipe->alive_cmds--; 6493 ex = WEXITSTATUS(status); 6494 /* bash prints killer signal's name for *last* 6495 * process in pipe (prints just newline for SIGINT). 6496 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) 6497 */ 6498 if (WIFSIGNALED(status)) { 6499 int sig = WTERMSIG(status); 6500 if (i == fg_pipe->num_cmds-1) 6501 printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); 6502 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 6503 * Maybe we need to use sig | 128? */ 6504 ex = sig + 128; 1587 6505 } 1588 debug_printf_jobs("fg_pipe: running_progs %d stopped_progs %d\n", 1589 fg_pipe->running_progs, fg_pipe->stopped_progs); 1590 if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) { 1591 /* All processes in fg pipe have exited/stopped */ 6506 fg_pipe->cmds[i].cmd_exitcode = ex; 6507 } else { 6508 fg_pipe->cmds[i].is_stopped = 1; 6509 fg_pipe->stopped_cmds++; 6510 } 6511 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", 6512 fg_pipe->alive_cmds, fg_pipe->stopped_cmds); 6513 if (fg_pipe->alive_cmds == fg_pipe->stopped_cmds) { 6514 /* All processes in fg pipe have exited or stopped */ 6515 i = fg_pipe->num_cmds; 6516 while (--i >= 0) { 6517 rcode = fg_pipe->cmds[i].cmd_exitcode; 6518 /* usually last process gives overall exitstatus, 6519 * but with "set -o pipefail", last *failed* process does */ 6520 if (G.o_opt[OPT_O_PIPEFAIL] == 0 || rcode != 0) 6521 break; 6522 } 6523 IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) 6524 /* Note: *non-interactive* bash does not continue if all processes in fg pipe 6525 * are stopped. Testcase: "cat | cat" in a script (not on command line!) 6526 * and "killall -STOP cat" */ 6527 if (G_interactive_fd) { 1592 6528 #if ENABLE_HUSH_JOB 1593 if (fg_pipe-> running_progs)6529 if (fg_pipe->alive_cmds != 0) 1594 6530 insert_bg_job(fg_pipe); 1595 6531 #endif 1596 6532 return rcode; 1597 6533 } 1598 /* There are still running processes in the fg pipe */1599 goto wait_more;6534 if (fg_pipe->alive_cmds == 0) 6535 return rcode; 1600 6536 } 1601 } 1602 /* fall through to searching process in bg pipes */ 6537 /* There are still running processes in the fg pipe */ 6538 goto wait_more; /* do waitpid again */ 6539 } 6540 /* it wasnt fg_pipe, look for process in bg pipes */ 1603 6541 } 1604 6542 … … 1606 6544 /* We asked to wait for bg or orphaned children */ 1607 6545 /* No need to remember exitcode in this case */ 1608 for (pi = job_list; pi; pi = pi->next) { 1609 prognum = 0; 1610 while (prognum < pi->num_progs) { 1611 if (pi->progs[prognum].pid == childpid) 6546 for (pi = G.job_list; pi; pi = pi->next) { 6547 for (i = 0; i < pi->num_cmds; i++) { 6548 if (pi->cmds[i].pid == childpid) 1612 6549 goto found_pi_and_prognum; 1613 prognum++; 1614 } 1615 } 1616 #endif 1617 6550 } 6551 } 1618 6552 /* Happens when shell is used as init process (init=/bin/sh) */ 1619 6553 debug_printf("checkjobs: pid %d was not in our list!\n", childpid); 1620 goto wait_more; 1621 1622 #if ENABLE_HUSH_JOB 6554 continue; /* do waitpid again */ 6555 1623 6556 found_pi_and_prognum: 1624 6557 if (dead) { 1625 6558 /* child exited */ 1626 pi->progs[prognum].pid = 0; 1627 pi->running_progs--; 1628 if (!pi->running_progs) { 1629 printf(JOB_STATUS_FORMAT, pi->jobid, 6559 pi->cmds[i].pid = 0; 6560 pi->alive_cmds--; 6561 if (!pi->alive_cmds) { 6562 if (G_interactive_fd) 6563 printf(JOB_STATUS_FORMAT, pi->jobid, 1630 6564 "Done", pi->cmdtext); 1631 6565 delete_finished_bg_job(pi); … … 1633 6567 } else { 1634 6568 /* child stopped */ 1635 pi->stopped_progs++; 1636 pi->progs[prognum].is_stopped = 1; 1637 } 1638 #endif 1639 } 1640 1641 /* wait found no children or failed */ 1642 1643 if (childpid && errno != ECHILD) 1644 bb_perror_msg("waitpid"); 6569 pi->cmds[i].is_stopped = 1; 6570 pi->stopped_cmds++; 6571 } 6572 #endif 6573 } /* while (waitpid succeeds)... */ 6574 1645 6575 return rcode; 1646 6576 } 1647 6577 1648 6578 #if ENABLE_HUSH_JOB 1649 static int checkjobs_and_fg_shell(struct pipe *fg_pipe)6579 static int checkjobs_and_fg_shell(struct pipe *fg_pipe) 1650 6580 { 1651 6581 pid_t p; 1652 6582 int rcode = checkjobs(fg_pipe); 1653 /* Job finished, move the shell to the foreground */ 1654 p = getpgid(0); /* pgid of our process */ 1655 debug_printf_jobs("fg'ing ourself: getpgid(0)=%d\n", (int)p); 1656 if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY) 1657 bb_perror_msg("tcsetpgrp-4a"); 6583 if (G_saved_tty_pgrp) { 6584 /* Job finished, move the shell to the foreground */ 6585 p = getpgrp(); /* our process group id */ 6586 debug_printf_jobs("fg'ing ourself: getpgrp()=%d\n", (int)p); 6587 tcsetpgrp(G_interactive_fd, p); 6588 } 1658 6589 return rcode; 1659 6590 } 1660 6591 #endif 1661 6592 1662 /* run_pipe_real() starts all the jobs, but doesn't wait for anything1663 * to finish.See checkjobs().6593 /* Start all the jobs, but don't wait for anything to finish. 6594 * See checkjobs(). 1664 6595 * 1665 * return code is normally -1, when the caller has to wait for children6596 * Return code is normally -1, when the caller has to wait for children 1666 6597 * to finish to determine the exit status of the pipe. If the pipe 1667 6598 * is a simple builtin command, however, the action is done by the 1668 * time run_pipe _realreturns, and the exit code is provided as the6599 * time run_pipe returns, and the exit code is provided as the 1669 6600 * return value. 1670 *1671 * The input of the pipe is always stdin, the output is always1672 * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,1673 * because it tries to avoid running the command substitution in1674 * subshell, when that is in fact necessary. The subshell process1675 * now has its stdout directed to the input of the appropriate pipe,1676 * so this routine is noticeably simpler.1677 6601 * 1678 6602 * Returns -1 only if started some children. IOW: we have to 1679 6603 * mask out retvals of builtins etc with 0xff! 6604 * 6605 * The only case when we do not need to [v]fork is when the pipe 6606 * is single, non-backgrounded, non-subshell command. Examples: 6607 * cmd ; ... { list } ; ... 6608 * cmd && ... { list } && ... 6609 * cmd || ... { list } || ... 6610 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], 6611 * or (if SH_STANDALONE) an applet, and we can run the { list } 6612 * with run_list. If it isn't one of these, we fork and exec cmd. 6613 * 6614 * Cases when we must fork: 6615 * non-single: cmd | cmd 6616 * backgrounded: cmd & { list } & 6617 * subshell: ( list ) [&] 1680 6618 */ 1681 static int run_pipe_real(struct pipe *pi) 1682 { 1683 int i; 1684 int nextin, nextout; 1685 int pipefds[2]; /* pipefds[0] is for reading */ 1686 struct child_prog *child; 1687 const struct built_in_command *x; 1688 char *p; 6619 #if !ENABLE_HUSH_MODE_X 6620 #define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, argv_expanded) \ 6621 redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) 6622 #endif 6623 static int redirect_and_varexp_helper(char ***new_env_p, 6624 struct variable **old_vars_p, 6625 struct command *command, 6626 int squirrel[3], 6627 char **argv_expanded) 6628 { 6629 /* setup_redirects acts on file descriptors, not FILEs. 6630 * This is perfect for work that comes after exec(). 6631 * Is it really safe for inline use? Experimentally, 6632 * things seem to work. */ 6633 int rcode = setup_redirects(command, squirrel); 6634 if (rcode == 0) { 6635 char **new_env = expand_assignments(command->argv, command->assignment_cnt); 6636 *new_env_p = new_env; 6637 dump_cmd_in_x_mode(new_env); 6638 dump_cmd_in_x_mode(argv_expanded); 6639 if (old_vars_p) 6640 *old_vars_p = set_vars_and_save_old(new_env); 6641 } 6642 return rcode; 6643 } 6644 static NOINLINE int run_pipe(struct pipe *pi) 6645 { 6646 static const char *const null_ptr = NULL; 6647 6648 int cmd_no; 6649 int next_infd; 6650 struct command *command; 6651 char **argv_expanded; 6652 char **argv; 1689 6653 /* it is not always needed, but we aim to smaller code */ 1690 6654 int squirrel[] = { -1, -1, -1 }; 1691 6655 int rcode; 1692 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); 1693 1694 debug_printf_exec("run_pipe_real start: single_fg=%d\n", single_fg); 1695 1696 nextin = 0; 6656 6657 debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); 6658 debug_enter(); 6659 6660 /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*" 6661 * Result should be 3 lines: q w e, qwe, q w e 6662 */ 6663 G.ifs = get_local_var_value("IFS"); 6664 if (!G.ifs) 6665 G.ifs = defifs; 6666 6667 IF_HUSH_JOB(pi->pgrp = -1;) 6668 pi->stopped_cmds = 0; 6669 command = &pi->cmds[0]; 6670 argv_expanded = NULL; 6671 6672 if (pi->num_cmds != 1 6673 || pi->followup == PIPE_BG 6674 || command->cmd_type == CMD_SUBSHELL 6675 ) { 6676 goto must_fork; 6677 } 6678 6679 pi->alive_cmds = 1; 6680 6681 debug_printf_exec(": group:%p argv:'%s'\n", 6682 command->group, command->argv ? command->argv[0] : "NONE"); 6683 6684 if (command->group) { 6685 #if ENABLE_HUSH_FUNCTIONS 6686 if (command->cmd_type == CMD_FUNCDEF) { 6687 /* "executing" func () { list } */ 6688 struct function *funcp; 6689 6690 funcp = new_function(command->argv[0]); 6691 /* funcp->name is already set to argv[0] */ 6692 funcp->body = command->group; 6693 # if !BB_MMU 6694 funcp->body_as_string = command->group_as_string; 6695 command->group_as_string = NULL; 6696 # endif 6697 command->group = NULL; 6698 command->argv[0] = NULL; 6699 debug_printf_exec("cmd %p has child func at %p\n", command, funcp); 6700 funcp->parent_cmd = command; 6701 command->child_func = funcp; 6702 6703 debug_printf_exec("run_pipe: return EXIT_SUCCESS\n"); 6704 debug_leave(); 6705 return EXIT_SUCCESS; 6706 } 6707 #endif 6708 /* { list } */ 6709 debug_printf("non-subshell group\n"); 6710 rcode = 1; /* exitcode if redir failed */ 6711 if (setup_redirects(command, squirrel) == 0) { 6712 debug_printf_exec(": run_list\n"); 6713 rcode = run_list(command->group) & 0xff; 6714 } 6715 restore_redirects(squirrel); 6716 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 6717 debug_leave(); 6718 debug_printf_exec("run_pipe: return %d\n", rcode); 6719 return rcode; 6720 } 6721 6722 argv = command->argv ? command->argv : (char **) &null_ptr; 6723 { 6724 const struct built_in_command *x; 6725 #if ENABLE_HUSH_FUNCTIONS 6726 const struct function *funcp; 6727 #else 6728 enum { funcp = 0 }; 6729 #endif 6730 char **new_env = NULL; 6731 struct variable *old_vars = NULL; 6732 6733 if (argv[command->assignment_cnt] == NULL) { 6734 /* Assignments, but no command */ 6735 /* Ensure redirects take effect (that is, create files). 6736 * Try "a=t >file" */ 6737 #if 0 /* A few cases in testsuite fail with this code. FIXME */ 6738 rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, squirrel, /*argv_expanded:*/ NULL); 6739 /* Set shell variables */ 6740 if (new_env) { 6741 argv = new_env; 6742 while (*argv) { 6743 set_local_var(*argv, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 6744 /* Do we need to flag set_local_var() errors? 6745 * "assignment to readonly var" and "putenv error" 6746 */ 6747 argv++; 6748 } 6749 } 6750 /* Redirect error sets $? to 1. Otherwise, 6751 * if evaluating assignment value set $?, retain it. 6752 * Try "false; q=`exit 2`; echo $?" - should print 2: */ 6753 if (rcode == 0) 6754 rcode = G.last_exitcode; 6755 /* Exit, _skipping_ variable restoring code: */ 6756 goto clean_up_and_ret0; 6757 6758 #else /* Older, bigger, but more correct code */ 6759 6760 rcode = setup_redirects(command, squirrel); 6761 restore_redirects(squirrel); 6762 /* Set shell variables */ 6763 if (G_x_mode) 6764 bb_putchar_stderr('+'); 6765 while (*argv) { 6766 char *p = expand_string_to_string(*argv, /*unbackslash:*/ 1); 6767 if (G_x_mode) 6768 fprintf(stderr, " %s", p); 6769 debug_printf_exec("set shell var:'%s'->'%s'\n", 6770 *argv, p); 6771 set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 6772 /* Do we need to flag set_local_var() errors? 6773 * "assignment to readonly var" and "putenv error" 6774 */ 6775 argv++; 6776 } 6777 if (G_x_mode) 6778 bb_putchar_stderr('\n'); 6779 /* Redirect error sets $? to 1. Otherwise, 6780 * if evaluating assignment value set $?, retain it. 6781 * Try "false; q=`exit 2`; echo $?" - should print 2: */ 6782 if (rcode == 0) 6783 rcode = G.last_exitcode; 6784 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 6785 debug_leave(); 6786 debug_printf_exec("run_pipe: return %d\n", rcode); 6787 return rcode; 6788 #endif 6789 } 6790 6791 /* Expand the rest into (possibly) many strings each */ 6792 if (0) {} 6793 #if ENABLE_HUSH_BASH_COMPAT 6794 else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { 6795 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); 6796 } 6797 #endif 6798 else { 6799 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); 6800 } 6801 6802 /* if someone gives us an empty string: `cmd with empty output` */ 6803 if (!argv_expanded[0]) { 6804 free(argv_expanded); 6805 debug_leave(); 6806 return G.last_exitcode; 6807 } 6808 6809 x = find_builtin(argv_expanded[0]); 6810 #if ENABLE_HUSH_FUNCTIONS 6811 funcp = NULL; 6812 if (!x) 6813 funcp = find_function(argv_expanded[0]); 6814 #endif 6815 if (x || funcp) { 6816 if (!funcp) { 6817 if (x->b_function == builtin_exec && argv_expanded[1] == NULL) { 6818 debug_printf("exec with redirects only\n"); 6819 rcode = setup_redirects(command, NULL); 6820 goto clean_up_and_ret1; 6821 } 6822 } 6823 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); 6824 if (rcode == 0) { 6825 if (!funcp) { 6826 debug_printf_exec(": builtin '%s' '%s'...\n", 6827 x->b_cmd, argv_expanded[1]); 6828 rcode = x->b_function(argv_expanded) & 0xff; 6829 fflush_all(); 6830 } 6831 #if ENABLE_HUSH_FUNCTIONS 6832 else { 6833 # if ENABLE_HUSH_LOCAL 6834 struct variable **sv; 6835 sv = G.shadowed_vars_pp; 6836 G.shadowed_vars_pp = &old_vars; 6837 # endif 6838 debug_printf_exec(": function '%s' '%s'...\n", 6839 funcp->name, argv_expanded[1]); 6840 rcode = run_function(funcp, argv_expanded) & 0xff; 6841 # if ENABLE_HUSH_LOCAL 6842 G.shadowed_vars_pp = sv; 6843 # endif 6844 } 6845 #endif 6846 } 6847 clean_up_and_ret: 6848 unset_vars(new_env); 6849 add_vars(old_vars); 6850 /* clean_up_and_ret0: */ 6851 restore_redirects(squirrel); 6852 clean_up_and_ret1: 6853 free(argv_expanded); 6854 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 6855 debug_leave(); 6856 debug_printf_exec("run_pipe return %d\n", rcode); 6857 return rcode; 6858 } 6859 6860 if (ENABLE_FEATURE_SH_STANDALONE) { 6861 int n = find_applet_by_name(argv_expanded[0]); 6862 if (n >= 0 && APPLET_IS_NOFORK(n)) { 6863 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); 6864 if (rcode == 0) { 6865 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 6866 argv_expanded[0], argv_expanded[1]); 6867 rcode = run_nofork_applet(n, argv_expanded); 6868 } 6869 goto clean_up_and_ret; 6870 } 6871 } 6872 /* It is neither builtin nor applet. We must fork. */ 6873 } 6874 6875 must_fork: 6876 /* NB: argv_expanded may already be created, and that 6877 * might include `cmd` runs! Do not rerun it! We *must* 6878 * use argv_expanded if it's non-NULL */ 6879 6880 /* Going to fork a child per each pipe member */ 6881 pi->alive_cmds = 0; 6882 next_infd = 0; 6883 6884 cmd_no = 0; 6885 while (cmd_no < pi->num_cmds) { 6886 struct fd_pair pipefds; 6887 #if !BB_MMU 6888 volatile nommu_save_t nommu_save; 6889 nommu_save.new_env = NULL; 6890 nommu_save.old_vars = NULL; 6891 nommu_save.argv = NULL; 6892 nommu_save.argv_from_re_execing = NULL; 6893 #endif 6894 command = &pi->cmds[cmd_no]; 6895 cmd_no++; 6896 if (command->argv) { 6897 debug_printf_exec(": pipe member '%s' '%s'...\n", 6898 command->argv[0], command->argv[1]); 6899 } else { 6900 debug_printf_exec(": pipe member with no argv\n"); 6901 } 6902 6903 /* pipes are inserted between pairs of commands */ 6904 pipefds.rd = 0; 6905 pipefds.wr = 1; 6906 if (cmd_no < pi->num_cmds) 6907 xpiped_pair(pipefds); 6908 6909 command->pid = BB_MMU ? fork() : vfork(); 6910 if (!command->pid) { /* child */ 1697 6911 #if ENABLE_HUSH_JOB 1698 pi->pgrp = -1; 1699 #endif 1700 pi->running_progs = 1; 1701 pi->stopped_progs = 0; 1702 1703 /* Check if this is a simple builtin (not part of a pipe). 1704 * Builtins within pipes have to fork anyway, and are handled in 1705 * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. 1706 */ 1707 child = &(pi->progs[0]); 1708 if (single_fg && child->group && child->subshell == 0) { 1709 debug_printf("non-subshell grouping\n"); 1710 setup_redirects(child, squirrel); 1711 debug_printf_exec(": run_list_real\n"); 1712 rcode = run_list_real(child->group); 1713 restore_redirects(squirrel); 1714 debug_printf_exec("run_pipe_real return %d\n", rcode); 1715 return rcode; // do we need to add '... & 0xff' ? 1716 } 1717 1718 if (single_fg && child->argv != NULL) { 1719 char **argv_expanded; 1720 char **argv = child->argv; 1721 1722 for (i = 0; is_assignment(argv[i]); i++) 1723 continue; 1724 if (i != 0 && argv[i] == NULL) { 1725 /* assignments, but no command: set the local environment */ 1726 for (i = 0; argv[i] != NULL; i++) { 1727 debug_printf("local environment set: %s\n", argv[i]); 1728 p = expand_string_to_string(argv[i]); 1729 set_local_var(p, 0); 1730 } 1731 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1732 } 1733 for (i = 0; is_assignment(argv[i]); i++) { 1734 p = expand_string_to_string(argv[i]); 1735 //sp: child->sp--; 1736 putenv(p); 1737 } 1738 for (x = bltins; x->cmd; x++) { 1739 if (strcmp(argv[i], x->cmd) == 0) { 1740 if (x->function == builtin_exec && argv[i+1] == NULL) { 1741 debug_printf("magic exec\n"); 1742 setup_redirects(child, NULL); 1743 return EXIT_SUCCESS; 1744 } 1745 debug_printf("builtin inline %s\n", argv[0]); 1746 /* XXX setup_redirects acts on file descriptors, not FILEs. 1747 * This is perfect for work that comes after exec(). 1748 * Is it really safe for inline use? Experimentally, 1749 * things seem to work with glibc. */ 1750 setup_redirects(child, squirrel); 1751 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); 1752 //sp: if (child->sp) /* btw we can do it unconditionally... */ 1753 argv_expanded = expand_strvec_to_strvec(argv + i); 1754 rcode = x->function(argv_expanded) & 0xff; 1755 free(argv_expanded); 1756 restore_redirects(squirrel); 1757 debug_printf_exec("run_pipe_real return %d\n", rcode); 1758 return rcode; 1759 } 1760 } 1761 #if ENABLE_FEATURE_SH_STANDALONE 1762 { 1763 const struct bb_applet *a = find_applet_by_name(argv[i]); 1764 if (a && a->nofork) { 1765 setup_redirects(child, squirrel); 1766 save_nofork_data(&nofork_save); 1767 argv_expanded = argv + i; 1768 //sp: if (child->sp) 1769 argv_expanded = expand_strvec_to_strvec(argv + i); 1770 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); 1771 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded) & 0xff; 1772 free(argv_expanded); 1773 restore_redirects(squirrel); 1774 debug_printf_exec("run_pipe_real return %d\n", rcode); 1775 return rcode; 1776 } 1777 } 1778 #endif 1779 } 1780 1781 /* Going to fork a child per each pipe member */ 1782 pi->running_progs = 0; 1783 1784 /* Disable job control signals for shell (parent) and 1785 * for initial child code after fork */ 1786 set_jobctrl_sighandler(SIG_IGN); 1787 1788 for (i = 0; i < pi->num_progs; i++) { 1789 child = &(pi->progs[i]); 1790 if (child->argv) 1791 debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); 1792 else 1793 debug_printf_exec(": pipe member with no argv\n"); 1794 1795 /* pipes are inserted between pairs of commands */ 1796 if ((i + 1) < pi->num_progs) { 1797 pipe(pipefds); 1798 nextout = pipefds[1]; 1799 } else { 1800 nextout = 1; 1801 pipefds[0] = -1; 1802 } 1803 1804 /* XXX test for failed fork()? */ 1805 #if BB_MMU 1806 child->pid = fork(); 1807 #else 1808 child->pid = vfork(); 1809 #endif 1810 if (!child->pid) { /* child */ 6912 disable_restore_tty_pgrp_on_exit(); 6913 CLEAR_RANDOM_T(&G.random_gen); /* or else $RANDOM repeats in child */ 6914 1811 6915 /* Every child adds itself to new process group 1812 * with pgid == pid of first child in pipe */ 1813 #if ENABLE_HUSH_JOB 1814 if (run_list_level == 1 && interactive_fd) { 1815 /* Don't do pgrp restore anymore on fatal signals */ 1816 set_fatal_sighandler(SIG_DFL); 1817 if (pi->pgrp < 0) /* true for 1st process only */ 1818 pi->pgrp = getpid(); 1819 if (setpgid(0, pi->pgrp) == 0 && pi->followup != PIPE_BG) { 6916 * with pgid == pid_of_first_child_in_pipe */ 6917 if (G.run_list_level == 1 && G_interactive_fd) { 6918 pid_t pgrp; 6919 pgrp = pi->pgrp; 6920 if (pgrp < 0) /* true for 1st process only */ 6921 pgrp = getpid(); 6922 if (setpgid(0, pgrp) == 0 6923 && pi->followup != PIPE_BG 6924 && G_saved_tty_pgrp /* we have ctty */ 6925 ) { 1820 6926 /* We do it in *every* child, not just first, 1821 6927 * to avoid races */ 1822 tcsetpgrp( interactive_fd, pi->pgrp);6928 tcsetpgrp(G_interactive_fd, pgrp); 1823 6929 } 1824 6930 } 1825 6931 #endif 1826 /* in non-interactive case fatal sigs are already SIG_DFL */ 1827 close_all(); 1828 if (nextin != 0) { 1829 dup2(nextin, 0); 1830 close(nextin); 1831 } 1832 if (nextout != 1) { 1833 dup2(nextout, 1); 1834 close(nextout); 1835 } 1836 if (pipefds[0] != -1) { 1837 close(pipefds[0]); /* opposite end of our output pipe */ 1838 } 6932 if (pi->alive_cmds == 0 && pi->followup == PIPE_BG) { 6933 /* 1st cmd in backgrounded pipe 6934 * should have its stdin /dev/null'ed */ 6935 close(0); 6936 if (open(bb_dev_null, O_RDONLY)) 6937 xopen("/", O_RDONLY); 6938 } else { 6939 xmove_fd(next_infd, 0); 6940 } 6941 xmove_fd(pipefds.wr, 1); 6942 if (pipefds.rd > 1) 6943 close(pipefds.rd); 1839 6944 /* Like bash, explicit redirects override pipes, 1840 6945 * and the pipe fd is available for dup'ing. */ 1841 setup_redirects(child, NULL); 6946 if (setup_redirects(command, NULL)) 6947 _exit(1); 1842 6948 1843 6949 /* Restore default handlers just prior to exec */ 1844 set_jobctrl_sighandler(SIG_DFL); 1845 set_misc_sighandler(SIG_DFL); 1846 signal(SIGCHLD, SIG_DFL); 1847 pseudo_exec(child); 1848 } 1849 1850 pi->running_progs++; 1851 6950 /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */ 6951 6952 /* Stores to nommu_save list of env vars putenv'ed 6953 * (NOMMU, on MMU we don't need that) */ 6954 /* cast away volatility... */ 6955 pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); 6956 /* pseudo_exec() does not return */ 6957 } 6958 6959 /* parent or error */ 6960 #if ENABLE_HUSH_FAST 6961 G.count_SIGCHLD++; 6962 //bb_error_msg("[%d] fork in run_pipe: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 6963 #endif 6964 enable_restore_tty_pgrp_on_exit(); 6965 #if !BB_MMU 6966 /* Clean up after vforked child */ 6967 free(nommu_save.argv); 6968 free(nommu_save.argv_from_re_execing); 6969 unset_vars(nommu_save.new_env); 6970 add_vars(nommu_save.old_vars); 6971 #endif 6972 free(argv_expanded); 6973 argv_expanded = NULL; 6974 if (command->pid < 0) { /* [v]fork failed */ 6975 /* Clearly indicate, was it fork or vfork */ 6976 bb_perror_msg(BB_MMU ? "vfork"+1 : "vfork"); 6977 } else { 6978 pi->alive_cmds++; 1852 6979 #if ENABLE_HUSH_JOB 1853 /* Second and next children need to know pid of first one */ 1854 if (pi->pgrp < 0) 1855 pi->pgrp = child->pid; 1856 #endif 1857 if (nextin != 0) 1858 close(nextin); 1859 if (nextout != 1) 1860 close(nextout); 1861 1862 /* If there isn't another process, nextin is garbage 1863 but it doesn't matter */ 1864 nextin = pipefds[0]; 1865 } 1866 debug_printf_exec("run_pipe_real return -1\n"); 6980 /* Second and next children need to know pid of first one */ 6981 if (pi->pgrp < 0) 6982 pi->pgrp = command->pid; 6983 #endif 6984 } 6985 6986 if (cmd_no > 1) 6987 close(next_infd); 6988 if (cmd_no < pi->num_cmds) 6989 close(pipefds.wr); 6990 /* Pass read (output) pipe end to next iteration */ 6991 next_infd = pipefds.rd; 6992 } 6993 6994 if (!pi->alive_cmds) { 6995 debug_leave(); 6996 debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n"); 6997 return 1; 6998 } 6999 7000 debug_leave(); 7001 debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds); 1867 7002 return -1; 1868 7003 } 1869 1870 #ifndef debug_print_tree1871 static void debug_print_tree(struct pipe *pi, int lvl)1872 {1873 static const char *PIPE[] = {1874 [PIPE_SEQ] = "SEQ",1875 [PIPE_AND] = "AND",1876 [PIPE_OR ] = "OR" ,1877 [PIPE_BG ] = "BG" ,1878 };1879 static const char *RES[] = {1880 [RES_NONE ] = "NONE" ,1881 #if ENABLE_HUSH_IF1882 [RES_IF ] = "IF" ,1883 [RES_THEN ] = "THEN" ,1884 [RES_ELIF ] = "ELIF" ,1885 [RES_ELSE ] = "ELSE" ,1886 [RES_FI ] = "FI" ,1887 #endif1888 #if ENABLE_HUSH_LOOPS1889 [RES_FOR ] = "FOR" ,1890 [RES_WHILE] = "WHILE",1891 [RES_UNTIL] = "UNTIL",1892 [RES_DO ] = "DO" ,1893 [RES_DONE ] = "DONE" ,1894 [RES_IN ] = "IN" ,1895 #endif1896 [RES_XXXX ] = "XXXX" ,1897 [RES_SNTX ] = "SNTX" ,1898 };1899 1900 int pin, prn;1901 1902 pin = 0;1903 while (pi) {1904 fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "",1905 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]);1906 prn = 0;1907 while (prn < pi->num_progs) {1908 struct child_prog *child = &pi->progs[prn];1909 char **argv = child->argv;1910 1911 fprintf(stderr, "%*s prog %d", lvl*2, "", prn);1912 if (child->group) {1913 fprintf(stderr, " group %s: (argv=%p)\n",1914 (child->subshell ? "()" : "{}"),1915 argv);1916 debug_print_tree(child->group, lvl+1);1917 prn++;1918 continue;1919 }1920 if (argv) while (*argv) {1921 fprintf(stderr, " '%s'", *argv);1922 argv++;1923 }1924 fprintf(stderr, "\n");1925 prn++;1926 }1927 pi = pi->next;1928 pin++;1929 }1930 }1931 #endif1932 7004 1933 7005 /* NB: called by pseudo_exec, and therefore must not modify any 1934 7006 * global data until exec/_exit (we can be a child after vfork!) */ 1935 static int run_list_real(struct pipe *pi) 1936 { 1937 struct pipe *rpipe; 7007 static int run_list(struct pipe *pi) 7008 { 7009 #if ENABLE_HUSH_CASE 7010 char *case_word = NULL; 7011 #endif 1938 7012 #if ENABLE_HUSH_LOOPS 1939 char *for_varname= NULL;7013 struct pipe *loop_top = NULL; 1940 7014 char **for_lcur = NULL; 1941 7015 char **for_list = NULL; 1942 int flag_rep = 0; 1943 #endif 1944 int save_num_progs; 1945 int flag_skip = 1; 1946 int rcode = 0; /* probably for gcc only */ 1947 int flag_restore = 0; 7016 #endif 7017 smallint last_followup; 7018 smalluint rcode; 7019 #if ENABLE_HUSH_IF || ENABLE_HUSH_CASE 7020 smalluint cond_code = 0; 7021 #else 7022 enum { cond_code = 0 }; 7023 #endif 7024 #if HAS_KEYWORDS 7025 smallint rword; /* RES_foo */ 7026 smallint last_rword; /* ditto */ 7027 #endif 7028 7029 debug_printf_exec("run_list start lvl %d\n", G.run_list_level); 7030 debug_enter(); 7031 7032 #if ENABLE_HUSH_LOOPS 7033 /* Check syntax for "for" */ 7034 { 7035 struct pipe *cpipe; 7036 for (cpipe = pi; cpipe; cpipe = cpipe->next) { 7037 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) 7038 continue; 7039 /* current word is FOR or IN (BOLD in comments below) */ 7040 if (cpipe->next == NULL) { 7041 syntax_error("malformed for"); 7042 debug_leave(); 7043 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); 7044 return 1; 7045 } 7046 /* "FOR v; do ..." and "for v IN a b; do..." are ok */ 7047 if (cpipe->next->res_word == RES_DO) 7048 continue; 7049 /* next word is not "do". It must be "in" then ("FOR v in ...") */ 7050 if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ 7051 || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ 7052 ) { 7053 syntax_error("malformed for"); 7054 debug_leave(); 7055 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); 7056 return 1; 7057 } 7058 } 7059 } 7060 #endif 7061 7062 /* Past this point, all code paths should jump to ret: label 7063 * in order to return, no direct "return" statements please. 7064 * This helps to ensure that no memory is leaked. */ 7065 7066 #if ENABLE_HUSH_JOB 7067 G.run_list_level++; 7068 #endif 7069 7070 #if HAS_KEYWORDS 7071 rword = RES_NONE; 7072 last_rword = RES_XXXX; 7073 #endif 7074 last_followup = PIPE_SEQ; 7075 rcode = G.last_exitcode; 7076 7077 /* Go through list of pipes, (maybe) executing them. */ 7078 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { 7079 if (G.flag_SIGINT) 7080 break; 7081 7082 IF_HAS_KEYWORDS(rword = pi->res_word;) 7083 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", 7084 rword, cond_code, last_rword); 7085 #if ENABLE_HUSH_LOOPS 7086 if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) 7087 && loop_top == NULL /* avoid bumping G.depth_of_loop twice */ 7088 ) { 7089 /* start of a loop: remember where loop starts */ 7090 loop_top = pi; 7091 G.depth_of_loop++; 7092 } 7093 #endif 7094 /* Still in the same "if...", "then..." or "do..." branch? */ 7095 if (IF_HAS_KEYWORDS(rword == last_rword &&) 1) { 7096 if ((rcode == 0 && last_followup == PIPE_OR) 7097 || (rcode != 0 && last_followup == PIPE_AND) 7098 ) { 7099 /* It is "<true> || CMD" or "<false> && CMD" 7100 * and we should not execute CMD */ 7101 debug_printf_exec("skipped cmd because of || or &&\n"); 7102 last_followup = pi->followup; 7103 continue; 7104 } 7105 } 7106 last_followup = pi->followup; 7107 IF_HAS_KEYWORDS(last_rword = rword;) 1948 7108 #if ENABLE_HUSH_IF 1949 int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ 1950 #else 1951 enum { if_code = 0, next_if_code = 0 }; 1952 #endif 1953 reserved_style rword; 1954 reserved_style skip_more_for_this_rword = RES_XXXX; 1955 1956 debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1); 1957 7109 if (cond_code) { 7110 if (rword == RES_THEN) { 7111 /* if false; then ... fi has exitcode 0! */ 7112 G.last_exitcode = rcode = EXIT_SUCCESS; 7113 /* "if <false> THEN cmd": skip cmd */ 7114 continue; 7115 } 7116 } else { 7117 if (rword == RES_ELSE || rword == RES_ELIF) { 7118 /* "if <true> then ... ELSE/ELIF cmd": 7119 * skip cmd and all following ones */ 7120 break; 7121 } 7122 } 7123 #endif 1958 7124 #if ENABLE_HUSH_LOOPS 1959 /* check syntax for "for" */ 1960 for (rpipe = pi; rpipe; rpipe = rpipe->next) { 1961 if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR) 1962 && (rpipe->next == NULL) 1963 ) { 1964 syntax("malformed for"); /* no IN or no commands after IN */ 1965 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); 1966 return 1; 1967 } 1968 if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL) 1969 || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN) 1970 ) { 1971 /* TODO: what is tested in the first condition? */ 1972 syntax("malformed for"); /* 2nd condition: not followed by IN */ 1973 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); 1974 return 1; 1975 } 1976 } 1977 #else 1978 rpipe = NULL; 1979 #endif 1980 7125 if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */ 7126 if (!for_lcur) { 7127 /* first loop through for */ 7128 7129 static const char encoded_dollar_at[] ALIGN1 = { 7130 SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0' 7131 }; /* encoded representation of "$@" */ 7132 static const char *const encoded_dollar_at_argv[] = { 7133 encoded_dollar_at, NULL 7134 }; /* argv list with one element: "$@" */ 7135 char **vals; 7136 7137 vals = (char**)encoded_dollar_at_argv; 7138 if (pi->next->res_word == RES_IN) { 7139 /* if no variable values after "in" we skip "for" */ 7140 if (!pi->next->cmds[0].argv) { 7141 G.last_exitcode = rcode = EXIT_SUCCESS; 7142 debug_printf_exec(": null FOR: exitcode EXIT_SUCCESS\n"); 7143 break; 7144 } 7145 vals = pi->next->cmds[0].argv; 7146 } /* else: "for var; do..." -> assume "$@" list */ 7147 /* create list of variable values */ 7148 debug_print_strings("for_list made from", vals); 7149 for_list = expand_strvec_to_strvec(vals); 7150 for_lcur = for_list; 7151 debug_print_strings("for_list", for_list); 7152 } 7153 if (!*for_lcur) { 7154 /* "for" loop is over, clean up */ 7155 free(for_list); 7156 for_list = NULL; 7157 for_lcur = NULL; 7158 break; 7159 } 7160 /* Insert next value from for_lcur */ 7161 /* note: *for_lcur already has quotes removed, $var expanded, etc */ 7162 set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); 7163 continue; 7164 } 7165 if (rword == RES_IN) { 7166 continue; /* "for v IN list;..." - "in" has no cmds anyway */ 7167 } 7168 if (rword == RES_DONE) { 7169 continue; /* "done" has no cmds too */ 7170 } 7171 #endif 7172 #if ENABLE_HUSH_CASE 7173 if (rword == RES_CASE) { 7174 case_word = expand_strvec_to_string(pi->cmds->argv); 7175 continue; 7176 } 7177 if (rword == RES_MATCH) { 7178 char **argv; 7179 7180 if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */ 7181 break; 7182 /* all prev words didn't match, does this one match? */ 7183 argv = pi->cmds->argv; 7184 while (*argv) { 7185 char *pattern = expand_string_to_string(*argv, /*unbackslash:*/ 1); 7186 /* TODO: which FNM_xxx flags to use? */ 7187 cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); 7188 free(pattern); 7189 if (cond_code == 0) { /* match! we will execute this branch */ 7190 free(case_word); /* make future "word)" stop */ 7191 case_word = NULL; 7192 break; 7193 } 7194 argv++; 7195 } 7196 continue; 7197 } 7198 if (rword == RES_CASE_BODY) { /* inside of a case branch */ 7199 if (cond_code != 0) 7200 continue; /* not matched yet, skip this pipe */ 7201 } 7202 #endif 7203 /* Just pressing <enter> in shell should check for jobs. 7204 * OTOH, in non-interactive shell this is useless 7205 * and only leads to extra job checks */ 7206 if (pi->num_cmds == 0) { 7207 if (G_interactive_fd) 7208 goto check_jobs_and_continue; 7209 continue; 7210 } 7211 7212 /* After analyzing all keywords and conditions, we decided 7213 * to execute this pipe. NB: have to do checkjobs(NULL) 7214 * after run_pipe to collect any background children, 7215 * even if list execution is to be stopped. */ 7216 debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); 7217 { 7218 int r; 7219 #if ENABLE_HUSH_LOOPS 7220 G.flag_break_continue = 0; 7221 #endif 7222 rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ 7223 if (r != -1) { 7224 /* We ran a builtin, function, or group. 7225 * rcode is already known 7226 * and we don't need to wait for anything. */ 7227 G.last_exitcode = rcode; 7228 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 7229 check_and_run_traps(0); 7230 #if ENABLE_HUSH_LOOPS 7231 /* Was it "break" or "continue"? */ 7232 if (G.flag_break_continue) { 7233 smallint fbc = G.flag_break_continue; 7234 /* We might fall into outer *loop*, 7235 * don't want to break it too */ 7236 if (loop_top) { 7237 G.depth_break_continue--; 7238 if (G.depth_break_continue == 0) 7239 G.flag_break_continue = 0; 7240 /* else: e.g. "continue 2" should *break* once, *then* continue */ 7241 } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */ 7242 if (G.depth_break_continue != 0 || fbc == BC_BREAK) 7243 goto check_jobs_and_break; 7244 /* "continue": simulate end of loop */ 7245 rword = RES_DONE; 7246 continue; 7247 } 7248 #endif 7249 #if ENABLE_HUSH_FUNCTIONS 7250 if (G.flag_return_in_progress == 1) { 7251 /* same as "goto check_jobs_and_break" */ 7252 checkjobs(NULL); 7253 break; 7254 } 7255 #endif 7256 } else if (pi->followup == PIPE_BG) { 7257 /* What does bash do with attempts to background builtins? */ 7258 /* even bash 3.2 doesn't do that well with nested bg: 7259 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 7260 * I'm NOT treating inner &'s as jobs */ 7261 check_and_run_traps(0); 1981 7262 #if ENABLE_HUSH_JOB 1982 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done". 1983 * We are saving state before entering outermost list ("while...done") 1984 * so that ctrl-Z will correctly background _entire_ outermost list, 1985 * not just a part of it (like "sleep 1 | exit 2") */ 1986 if (++run_list_level == 1 && interactive_fd) { 1987 if (sigsetjmp(toplevel_jb, 1)) { 1988 /* ctrl-Z forked and we are parent; or ctrl-C. 1989 * Sighandler has longjmped us here */ 1990 signal(SIGINT, SIG_IGN); 1991 signal(SIGTSTP, SIG_IGN); 1992 /* Restore level (we can be coming from deep inside 1993 * nested levels) */ 1994 run_list_level = 1; 1995 #if ENABLE_FEATURE_SH_STANDALONE 1996 if (nofork_save.saved) { /* if save area is valid */ 1997 debug_printf_jobs("exiting nofork early\n"); 1998 restore_nofork_data(&nofork_save); 1999 } 2000 #endif 2001 if (ctrl_z_flag) { 2002 /* ctrl-Z has forked and stored pid of the child in pi->pid. 2003 * Remember this child as background job */ 2004 insert_bg_job(pi); 7263 if (G.run_list_level == 1) 7264 insert_bg_job(pi); 7265 #endif 7266 /* Last command's pid goes to $! */ 7267 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; 7268 G.last_exitcode = rcode = EXIT_SUCCESS; 7269 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); 2005 7270 } else { 2006 /* ctrl-C. We just stop doing whatever we were doing */2007 putchar('\n');2008 }2009 rcode = 0;2010 goto ret;2011 }2012 /* ctrl-Z handler will store pid etc in pi */2013 toplevel_list = pi;2014 ctrl_z_flag = 0;2015 #if ENABLE_FEATURE_SH_STANDALONE2016 nofork_save.saved = 0; /* in case we will run a nofork later */2017 #endif2018 signal_SA_RESTART(SIGTSTP, handler_ctrl_z);2019 signal(SIGINT, handler_ctrl_c);2020 }2021 #endif2022 2023 for (; pi; pi = flag_restore ? rpipe : pi->next) {2024 rword = pi->res_word;2025 #if ENABLE_HUSH_LOOPS2026 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {2027 flag_restore = 0;2028 if (!rpipe) {2029 flag_rep = 0;2030 rpipe = pi;2031 }2032 }2033 #endif2034 debug_printf_exec(": rword=%d if_code=%d next_if_code=%d skip_more=%d\n",2035 rword, if_code, next_if_code, skip_more_for_this_rword);2036 if (rword == skip_more_for_this_rword && flag_skip) {2037 if (pi->followup == PIPE_SEQ)2038 flag_skip = 0;2039 continue;2040 }2041 flag_skip = 1;2042 skip_more_for_this_rword = RES_XXXX;2043 #if ENABLE_HUSH_IF2044 if (rword == RES_THEN || rword == RES_ELSE)2045 if_code = next_if_code;2046 if (rword == RES_THEN && if_code)2047 continue;2048 if (rword == RES_ELSE && !if_code)2049 continue;2050 if (rword == RES_ELIF && !if_code)2051 break;2052 #endif2053 #if ENABLE_HUSH_LOOPS2054 if (rword == RES_FOR && pi->num_progs) {2055 if (!for_lcur) {2056 /* if no variable values after "in" we skip "for" */2057 if (!pi->next->progs->argv)2058 continue;2059 /* create list of variable values */2060 for_list = expand_strvec_to_strvec(pi->next->progs->argv);2061 for_lcur = for_list;2062 for_varname = pi->progs->argv[0];2063 pi->progs->argv[0] = NULL;2064 flag_rep = 1;2065 }2066 free(pi->progs->argv[0]);2067 if (!*for_lcur) {2068 free(for_list);2069 for_lcur = NULL;2070 flag_rep = 0;2071 pi->progs->argv[0] = for_varname;2072 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];2073 continue;2074 }2075 /* insert next value from for_lcur */2076 /* vda: does it need escaping? */2077 pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);2078 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];2079 }2080 if (rword == RES_IN)2081 continue;2082 if (rword == RES_DO) {2083 if (!flag_rep)2084 continue;2085 }2086 if (rword == RES_DONE) {2087 if (flag_rep) {2088 flag_restore = 1;2089 } else {2090 rpipe = NULL;2091 }2092 }2093 #endif2094 if (pi->num_progs == 0)2095 continue;2096 save_num_progs = pi->num_progs; /* save number of programs */2097 debug_printf_exec(": run_pipe_real with %d members\n", pi->num_progs);2098 rcode = run_pipe_real(pi);2099 if (rcode != -1) {2100 /* We only ran a builtin: rcode was set by the return value2101 * of run_pipe_real(), and we don't need to wait for anything. */2102 } else if (pi->followup == PIPE_BG) {2103 /* What does bash do with attempts to background builtins? */2104 /* Even bash 3.2 doesn't do that well with nested bg:2105 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".2106 * I'm NOT treating inner &'s as jobs */2107 7271 #if ENABLE_HUSH_JOB 2108 if (run_list_level == 1) 2109 insert_bg_job(pi); 2110 #endif 2111 rcode = EXIT_SUCCESS; 2112 } else { 2113 #if ENABLE_HUSH_JOB 2114 /* Paranoia, just "interactive_fd" should be enough? */ 2115 if (run_list_level == 1 && interactive_fd) { 2116 /* waits for completion, then fg's main shell */ 2117 rcode = checkjobs_and_fg_shell(pi); 2118 } else 2119 #endif 2120 { 2121 /* this one just waits for completion */ 2122 rcode = checkjobs(pi); 2123 } 2124 debug_printf_exec(": checkjobs returned %d\n", rcode); 2125 } 2126 debug_printf_exec(": setting last_return_code=%d\n", rcode); 2127 last_return_code = rcode; 2128 pi->num_progs = save_num_progs; /* restore number of programs */ 7272 if (G.run_list_level == 1 && G_interactive_fd) { 7273 /* Waits for completion, then fg's main shell */ 7274 rcode = checkjobs_and_fg_shell(pi); 7275 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); 7276 check_and_run_traps(0); 7277 } else 7278 #endif 7279 { /* This one just waits for completion */ 7280 rcode = checkjobs(pi); 7281 debug_printf_exec(": checkjobs exitcode %d\n", rcode); 7282 check_and_run_traps(0); 7283 } 7284 G.last_exitcode = rcode; 7285 } 7286 } 7287 7288 /* Analyze how result affects subsequent commands */ 2129 7289 #if ENABLE_HUSH_IF 2130 7290 if (rword == RES_IF || rword == RES_ELIF) 2131 next_if_code = rcode; /* can be overwritten a number of times */7291 cond_code = rcode; 2132 7292 #endif 2133 7293 #if ENABLE_HUSH_LOOPS 2134 if (rword == RES_WHILE) 2135 flag_rep = !last_return_code; 2136 if (rword == RES_UNTIL) 2137 flag_rep = last_return_code; 2138 #endif 2139 if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR) 2140 || (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND) 2141 ) { 2142 skip_more_for_this_rword = rword; 2143 } 7294 /* Beware of "while false; true; do ..."! */ 7295 if (pi->next && pi->next->res_word == RES_DO) { 7296 if (rword == RES_WHILE) { 7297 if (rcode) { 7298 /* "while false; do...done" - exitcode 0 */ 7299 G.last_exitcode = rcode = EXIT_SUCCESS; 7300 debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n"); 7301 goto check_jobs_and_break; 7302 } 7303 } 7304 if (rword == RES_UNTIL) { 7305 if (!rcode) { 7306 debug_printf_exec(": until expr is true: breaking\n"); 7307 check_jobs_and_break: 7308 checkjobs(NULL); 7309 break; 7310 } 7311 } 7312 } 7313 #endif 7314 7315 check_jobs_and_continue: 2144 7316 checkjobs(NULL); 2145 } 7317 } /* for (pi) */ 2146 7318 2147 7319 #if ENABLE_HUSH_JOB 2148 if (ctrl_z_flag) {2149 /* ctrl-Z forked somewhere in the past, we are the child, 2150 * and now we completed running the list. Exit. */ 2151 exit(rcode);2152 }2153 ret: 2154 if (!--run_list_level && interactive_fd) { 2155 signal(SIGTSTP, SIG_IGN); 2156 signal(SIGINT, SIG_IGN);2157 } 2158 #endif 2159 debug_printf_exec("run_list _real lvl %d return %d\n",run_list_level + 1, rcode);7320 G.run_list_level--; 7321 #endif 7322 #if ENABLE_HUSH_LOOPS 7323 if (loop_top) 7324 G.depth_of_loop--; 7325 free(for_list); 7326 #endif 7327 #if ENABLE_HUSH_CASE 7328 free(case_word); 7329 #endif 7330 debug_leave(); 7331 debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode); 2160 7332 return rcode; 2161 7333 } 2162 7334 2163 /* return code is the exit status of the pipe */ 2164 static int free_pipe(struct pipe *pi, int indent) 2165 { 2166 char **p; 2167 struct child_prog *child; 2168 struct redir_struct *r, *rnext; 2169 int a, i, ret_code = 0; 2170 2171 if (pi->stopped_progs > 0) 2172 return ret_code; 2173 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); 2174 for (i = 0; i < pi->num_progs; i++) { 2175 child = &pi->progs[i]; 2176 debug_printf_clean("%s command %d:\n", indenter(indent), i); 2177 if (child->argv) { 2178 for (a = 0, p = child->argv; *p; a++, p++) { 2179 debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p); 2180 } 2181 globfree(&child->glob_result); 2182 child->argv = NULL; 2183 } else if (child->group) { 2184 debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), child->subshell); 2185 ret_code = free_pipe_list(child->group, indent+3); 2186 debug_printf_clean("%s end group\n", indenter(indent)); 2187 } else { 2188 debug_printf_clean("%s (nil)\n", indenter(indent)); 2189 } 2190 for (r = child->redirects; r; r = rnext) { 2191 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip); 2192 if (r->dup == -1) { 2193 /* guard against the case >$FOO, where foo is unset or blank */ 2194 if (r->word.gl_pathv) { 2195 debug_printf_clean(" %s\n", *r->word.gl_pathv); 2196 globfree(&r->word); 2197 } 2198 } else { 2199 debug_printf_clean("&%d\n", r->dup); 2200 } 2201 rnext = r->next; 2202 free(r); 2203 } 2204 child->redirects = NULL; 2205 } 2206 free(pi->progs); /* children are an array, they get freed all at once */ 2207 pi->progs = NULL; 7335 /* Select which version we will use */ 7336 static int run_and_free_list(struct pipe *pi) 7337 { 7338 int rcode = 0; 7339 debug_printf_exec("run_and_free_list entered\n"); 7340 if (!G.n_mode) { 7341 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); 7342 rcode = run_list(pi); 7343 } 7344 /* free_pipe_list has the side effect of clearing memory. 7345 * In the long run that function can be merged with run_list, 7346 * but doing that now would hobble the debugging effort. */ 7347 free_pipe_list(pi); 7348 debug_printf_exec("run_and_free_list return %d\n", rcode); 7349 return rcode; 7350 } 7351 7352 7353 /* Called a few times only (or even once if "sh -c") */ 7354 static void init_sigmasks(void) 7355 { 7356 unsigned sig; 7357 unsigned mask; 7358 sigset_t old_blocked_set; 7359 7360 if (!G.inherited_set_is_saved) { 7361 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); 7362 G.inherited_set = G.blocked_set; 7363 } 7364 old_blocked_set = G.blocked_set; 7365 7366 mask = (1 << SIGQUIT); 7367 if (G_interactive_fd) { 7368 mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS; 7369 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ 7370 mask |= SPECIAL_JOB_SIGS; 7371 } 7372 G.non_DFL_mask = mask; 7373 7374 sig = 0; 7375 while (mask) { 7376 if (mask & 1) 7377 sigaddset(&G.blocked_set, sig); 7378 mask >>= 1; 7379 sig++; 7380 } 7381 sigdelset(&G.blocked_set, SIGCHLD); 7382 7383 if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0) 7384 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 7385 7386 /* POSIX allows shell to re-enable SIGCHLD 7387 * even if it was SIG_IGN on entry */ 7388 #if ENABLE_HUSH_FAST 7389 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 7390 if (!G.inherited_set_is_saved) 7391 signal(SIGCHLD, SIGCHLD_handler); 7392 #else 7393 if (!G.inherited_set_is_saved) 7394 signal(SIGCHLD, SIG_DFL); 7395 #endif 7396 7397 G.inherited_set_is_saved = 1; 7398 } 7399 2208 7400 #if ENABLE_HUSH_JOB 2209 free(pi->cmdtext); 2210 pi->cmdtext = NULL; 2211 #endif 2212 return ret_code; 2213 } 2214 2215 static int free_pipe_list(struct pipe *head, int indent) 2216 { 2217 int rcode = 0; /* if list has no members */ 2218 struct pipe *pi, *next; 2219 2220 for (pi = head; pi; pi = next) { 2221 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); 2222 rcode = free_pipe(pi, indent); 2223 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); 2224 next = pi->next; 2225 /*pi->next = NULL;*/ 2226 free(pi); 2227 } 2228 return rcode; 2229 } 2230 2231 /* Select which version we will use */ 2232 static int run_list(struct pipe *pi) 2233 { 2234 int rcode = 0; 2235 debug_printf_exec("run_list entered\n"); 2236 if (fake_mode == 0) { 2237 debug_printf_exec(": run_list_real with %d members\n", pi->num_progs); 2238 rcode = run_list_real(pi); 2239 } 2240 /* free_pipe_list has the side effect of clearing memory. 2241 * In the long run that function can be merged with run_list_real, 2242 * but doing that now would hobble the debugging effort. */ 2243 free_pipe_list(pi, 0); 2244 debug_printf_exec("run_list return %d\n", rcode); 2245 return rcode; 2246 } 2247 2248 /* The API for glob is arguably broken. This routine pushes a non-matching 2249 * string into the output structure, removing non-backslashed backslashes. 2250 * If someone can prove me wrong, by performing this function within the 2251 * original glob(3) api, feel free to rewrite this routine into oblivion. 2252 * Return code (0 vs. GLOB_NOSPACE) matches glob(3). 2253 * XXX broken if the last character is '\\', check that before calling. 2254 */ 2255 static int globhack(const char *src, int flags, glob_t *pglob) 2256 { 2257 int cnt = 0, pathc; 2258 const char *s; 2259 char *dest; 2260 for (cnt = 1, s = src; s && *s; s++) { 2261 if (*s == '\\') s++; 2262 cnt++; 2263 } 2264 dest = xmalloc(cnt); 2265 if (!(flags & GLOB_APPEND)) { 2266 pglob->gl_pathv = NULL; 2267 pglob->gl_pathc = 0; 2268 pglob->gl_offs = 0; 2269 pglob->gl_offs = 0; 2270 } 2271 pathc = ++pglob->gl_pathc; 2272 pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv)); 2273 pglob->gl_pathv[pathc-1] = dest; 2274 pglob->gl_pathv[pathc] = NULL; 2275 for (s = src; s && *s; s++, dest++) { 2276 if (*s == '\\') s++; 2277 *dest = *s; 2278 } 2279 *dest = '\0'; 2280 return 0; 2281 } 2282 2283 /* XXX broken if the last character is '\\', check that before calling */ 2284 static int glob_needed(const char *s) 2285 { 2286 for (; *s; s++) { 2287 if (*s == '\\') s++; 2288 if (strchr("*[?", *s)) return 1; 2289 } 2290 return 0; 2291 } 2292 2293 static int xglob(o_string *dest, int flags, glob_t *pglob) 2294 { 2295 int gr; 2296 2297 /* short-circuit for null word */ 2298 /* we can code this better when the debug_printf's are gone */ 2299 if (dest->length == 0) { 2300 if (dest->nonnull) { 2301 /* bash man page calls this an "explicit" null */ 2302 gr = globhack(dest->data, flags, pglob); 2303 debug_printf("globhack returned %d\n", gr); 2304 } else { 2305 return 0; 2306 } 2307 } else if (glob_needed(dest->data)) { 2308 gr = glob(dest->data, flags, NULL, pglob); 2309 debug_printf("glob returned %d\n", gr); 2310 if (gr == GLOB_NOMATCH) { 2311 /* quote removal, or more accurately, backslash removal */ 2312 gr = globhack(dest->data, flags, pglob); 2313 debug_printf("globhack returned %d\n", gr); 2314 } 2315 } else { 2316 gr = globhack(dest->data, flags, pglob); 2317 debug_printf("globhack returned %d\n", gr); 2318 } 2319 if (gr == GLOB_NOSPACE) 2320 bb_error_msg_and_die("out of memory during glob"); 2321 if (gr != 0) { /* GLOB_ABORTED ? */ 2322 bb_error_msg("glob(3) error %d", gr); 2323 } 2324 /* globprint(glob_target); */ 2325 return gr; 2326 } 2327 2328 /* expand_strvec_to_strvec() takes a list of strings, expands 2329 * all variable references within and returns a pointer to 2330 * a list of expanded strings, possibly with larger number 2331 * of strings. (Think VAR="a b"; echo $VAR). 2332 * This new list is allocated as a single malloc block. 2333 * NULL-terminated list of char* pointers is at the beginning of it, 2334 * followed by strings themself. 2335 * Caller can deallocate entire list by single free(list). */ 2336 2337 /* Helpers first: 2338 * count_XXX estimates size of the block we need. It's okay 2339 * to over-estimate sizes a bit, if it makes code simpler */ 2340 static int count_ifs(const char *str) 2341 { 2342 int cnt = 0; 2343 debug_printf_expand("count_ifs('%s') ifs='%s'", str, ifs); 2344 while (1) { 2345 str += strcspn(str, ifs); 2346 if (!*str) break; 2347 str++; /* str += strspn(str, ifs); */ 2348 cnt++; /* cnt += strspn(str, ifs); - but this code is larger */ 2349 } 2350 debug_printf_expand(" return %d\n", cnt); 2351 return cnt; 2352 } 2353 2354 static void count_var_expansion_space(int *countp, int *lenp, char *arg) 2355 { 2356 char first_ch; 2357 int i; 2358 int len = *lenp; 2359 int count = *countp; 2360 const char *val; 2361 char *p; 2362 2363 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) { 2364 len += p - arg; 2365 arg = ++p; 2366 p = strchr(p, SPECIAL_VAR_SYMBOL); 2367 first_ch = arg[0]; 2368 2369 switch (first_ch & 0x7f) { 2370 /* high bit in 1st_ch indicates that var is double-quoted */ 2371 case '$': /* pid */ 2372 case '!': /* bg pid */ 2373 case '?': /* exitcode */ 2374 case '#': /* argc */ 2375 len += sizeof(int)*3 + 1; /* enough for int */ 7401 /* helper */ 7402 static void maybe_set_to_sigexit(int sig) 7403 { 7404 void (*handler)(int); 7405 /* non_DFL_mask'ed signals are, well, masked, 7406 * no need to set handler for them. 7407 */ 7408 if (!((G.non_DFL_mask >> sig) & 1)) { 7409 handler = signal(sig, sigexit); 7410 if (handler == SIG_IGN) /* oops... restore back to IGN! */ 7411 signal(sig, handler); 7412 } 7413 } 7414 /* Set handlers to restore tty pgrp and exit */ 7415 static void set_fatal_handlers(void) 7416 { 7417 /* We _must_ restore tty pgrp on fatal signals */ 7418 if (HUSH_DEBUG) { 7419 maybe_set_to_sigexit(SIGILL ); 7420 maybe_set_to_sigexit(SIGFPE ); 7421 maybe_set_to_sigexit(SIGBUS ); 7422 maybe_set_to_sigexit(SIGSEGV); 7423 maybe_set_to_sigexit(SIGTRAP); 7424 } /* else: hush is perfect. what SEGV? */ 7425 maybe_set_to_sigexit(SIGABRT); 7426 /* bash 3.2 seems to handle these just like 'fatal' ones */ 7427 maybe_set_to_sigexit(SIGPIPE); 7428 maybe_set_to_sigexit(SIGALRM); 7429 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. 7430 * if we aren't interactive... but in this case 7431 * we never want to restore pgrp on exit, and this fn is not called */ 7432 /*maybe_set_to_sigexit(SIGHUP );*/ 7433 /*maybe_set_to_sigexit(SIGTERM);*/ 7434 /*maybe_set_to_sigexit(SIGINT );*/ 7435 } 7436 #endif 7437 7438 static int set_mode(int state, char mode, const char *o_opt) 7439 { 7440 int idx; 7441 switch (mode) { 7442 case 'n': 7443 G.n_mode = state; 7444 break; 7445 case 'x': 7446 IF_HUSH_MODE_X(G_x_mode = state;) 7447 break; 7448 case 'o': 7449 if (!o_opt) { 7450 /* "set -+o" without parameter. 7451 * in bash, set -o produces this output: 7452 * pipefail off 7453 * and set +o: 7454 * set +o pipefail 7455 * We always use the second form. 7456 */ 7457 const char *p = o_opt_strings; 7458 idx = 0; 7459 while (*p) { 7460 printf("set %co %s\n", (G.o_opt[idx] ? '-' : '+'), p); 7461 idx++; 7462 p += strlen(p) + 1; 7463 } 2376 7464 break; 2377 case '*': 2378 case '@': 2379 for (i = 1; i < global_argc; i++) { 2380 len += strlen(global_argv[i]) + 1; 2381 count++; 2382 if (!(first_ch & 0x80)) 2383 count += count_ifs(global_argv[i]); 2384 } 7465 } 7466 idx = index_in_strings(o_opt_strings, o_opt); 7467 if (idx >= 0) { 7468 G.o_opt[idx] = state; 2385 7469 break; 2386 default: 2387 *p = '\0'; 2388 arg[0] = first_ch & 0x7f; 2389 if (isdigit(arg[0])) { 2390 i = xatoi_u(arg); 2391 val = NULL; 2392 if (i < global_argc) 2393 val = global_argv[i]; 2394 } else 2395 val = lookup_param(arg); 2396 arg[0] = first_ch; 2397 *p = SPECIAL_VAR_SYMBOL; 2398 2399 if (val) { 2400 len += strlen(val) + 1; 2401 if (!(first_ch & 0x80)) 2402 count += count_ifs(val); 2403 } 2404 } 2405 arg = ++p; 2406 } 2407 2408 len += strlen(arg) + 1; 2409 count++; 2410 *lenp = len; 2411 *countp = count; 2412 } 2413 2414 /* Store given string, finalizing the word and starting new one whenever 2415 * we encounter ifs char(s). This is used for expanding variable values. 2416 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 2417 static int expand_on_ifs(char **list, int n, char **posp, const char *str) 2418 { 2419 char *pos = *posp; 2420 while (1) { 2421 int word_len = strcspn(str, ifs); 2422 if (word_len) { 2423 memcpy(pos, str, word_len); /* store non-ifs chars */ 2424 pos += word_len; 2425 str += word_len; 2426 } 2427 if (!*str) /* EOL - do not finalize word */ 2428 break; 2429 *pos++ = '\0'; 2430 if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' " 2431 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2432 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2433 list[n++] = pos; 2434 str += strspn(str, ifs); /* skip ifs chars */ 2435 } 2436 *posp = pos; 2437 return n; 2438 } 2439 2440 /* Expand all variable references in given string, adding words to list[] 2441 * at n, n+1,... positions. Return updated n (so that list[n] is next one 2442 * to be filled). This routine is extremely tricky: has to deal with 2443 * variables/parameters with whitespace, $* and $@, and constructs like 2444 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ 2445 /* NB: another bug is that we cannot detect empty strings yet: 2446 * "" or $empty"" expands to zero words, has to expand to empty word */ 2447 static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask) 2448 { 2449 /* or_mask is either 0 (normal case) or 0x80 2450 * (expansion of right-hand side of assignment == 1-element expand) */ 2451 2452 char first_ch, ored_ch; 2453 int i; 2454 const char *val; 2455 char *p; 2456 char *pos = *posp; 2457 2458 ored_ch = 0; 2459 2460 if (n) debug_printf_expand("expand_vars_to_list finalized list[%d]=%p '%s' " 2461 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2462 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2463 list[n++] = pos; 2464 2465 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) { 2466 memcpy(pos, arg, p - arg); 2467 pos += (p - arg); 2468 arg = ++p; 2469 p = strchr(p, SPECIAL_VAR_SYMBOL); 2470 2471 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ 2472 ored_ch |= first_ch; 2473 val = NULL; 2474 switch (first_ch & 0x7f) { 2475 /* Highest bit in first_ch indicates that var is double-quoted */ 2476 case '$': /* pid */ 2477 /* FIXME: (echo $$) should still print pid of main shell */ 2478 val = utoa(getpid()); 2479 break; 2480 case '!': /* bg pid */ 2481 val = last_bg_pid ? utoa(last_bg_pid) : (char*)""; 2482 break; 2483 case '?': /* exitcode */ 2484 val = utoa(last_return_code); 2485 break; 2486 case '#': /* argc */ 2487 val = utoa(global_argc ? global_argc-1 : 0); 2488 break; 2489 case '*': 2490 case '@': 2491 i = 1; 2492 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 2493 while (i < global_argc) { 2494 n = expand_on_ifs(list, n, &pos, global_argv[i]); 2495 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1); 2496 if (global_argv[i++][0] && i < global_argc) { 2497 /* this argv[] is not empty and not last: 2498 * put terminating NUL, start new word */ 2499 *pos++ = '\0'; 2500 if (n) debug_printf_expand("expand_vars_to_list 2 finalized list[%d]=%p '%s' " 2501 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2502 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2503 list[n++] = pos; 2504 } 2505 } 2506 } else 2507 /* If or_mask is nonzero, we handle assignment 'a=....$@.....' 2508 * and in this case should theat it like '$*' */ 2509 if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ 2510 while (1) { 2511 strcpy(pos, global_argv[i]); 2512 pos += strlen(global_argv[i]); 2513 if (++i >= global_argc) 2514 break; 2515 *pos++ = '\0'; 2516 if (n) debug_printf_expand("expand_vars_to_list 3 finalized list[%d]=%p '%s' " 2517 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2518 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2519 list[n++] = pos; 2520 } 2521 } else { /* quoted $*: add as one word */ 2522 while (1) { 2523 strcpy(pos, global_argv[i]); 2524 pos += strlen(global_argv[i]); 2525 if (++i >= global_argc) 2526 break; 2527 if (ifs[0]) 2528 *pos++ = ifs[0]; 2529 } 2530 } 2531 break; 2532 default: 2533 *p = '\0'; 2534 arg[0] = first_ch & 0x7f; 2535 if (isdigit(arg[0])) { 2536 i = xatoi_u(arg); 2537 val = NULL; 2538 if (i < global_argc) 2539 val = global_argv[i]; 2540 } else 2541 val = lookup_param(arg); 2542 arg[0] = first_ch; 2543 *p = SPECIAL_VAR_SYMBOL; 2544 if (!(first_ch & 0x80)) { /* unquoted $VAR */ 2545 if (val) { 2546 n = expand_on_ifs(list, n, &pos, val); 2547 val = NULL; 2548 } 2549 } /* else: quoted $VAR, val will be appended at pos */ 2550 } 2551 if (val) { 2552 strcpy(pos, val); 2553 pos += strlen(val); 2554 } 2555 arg = ++p; 2556 } 2557 debug_printf_expand("expand_vars_to_list adding tail '%s' at %p\n", arg, pos); 2558 strcpy(pos, arg); 2559 pos += strlen(arg) + 1; 2560 if (pos == list[n-1] + 1) { /* expansion is empty */ 2561 if (!(ored_ch & 0x80)) { /* all vars were not quoted... */ 2562 debug_printf_expand("expand_vars_to_list list[%d] empty, going back\n", n); 2563 pos--; 2564 n--; 2565 } 2566 } 2567 2568 *posp = pos; 2569 return n; 2570 } 2571 2572 static char **expand_variables(char **argv, char or_mask) 2573 { 2574 int n; 2575 int count = 1; 2576 int len = 0; 2577 char *pos, **v, **list; 2578 2579 v = argv; 2580 if (!*v) debug_printf_expand("count_var_expansion_space: " 2581 "argv[0]=NULL count=%d len=%d alloc_space=%d\n", 2582 count, len, sizeof(char*) * count + len); 2583 while (*v) { 2584 count_var_expansion_space(&count, &len, *v); 2585 debug_printf_expand("count_var_expansion_space: " 2586 "'%s' count=%d len=%d alloc_space=%d\n", 2587 *v, count, len, sizeof(char*) * count + len); 2588 v++; 2589 } 2590 len += sizeof(char*) * count; /* total to alloc */ 2591 list = xmalloc(len); 2592 pos = (char*)(list + count); 2593 debug_printf_expand("list=%p, list[0] should be %p\n", list, pos); 2594 n = 0; 2595 v = argv; 2596 while (*v) 2597 n = expand_vars_to_list(list, n, &pos, *v++, or_mask); 2598 2599 if (n) debug_printf_expand("finalized list[%d]=%p '%s' " 2600 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2601 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2602 list[n] = NULL; 2603 2604 #ifdef DEBUG_EXPAND 2605 { 2606 int m = 0; 2607 while (m <= n) { 2608 debug_printf_expand("list[%d]=%p '%s'\n", m, list[m], list[m]); 2609 m++; 2610 } 2611 debug_printf_expand("used_space=%d\n", pos - (char*)list); 2612 } 2613 #endif 2614 if (ENABLE_HUSH_DEBUG) 2615 if (pos - (char*)list > len) 2616 bb_error_msg_and_die("BUG in varexp"); 2617 return list; 2618 } 2619 2620 static char **expand_strvec_to_strvec(char **argv) 2621 { 2622 return expand_variables(argv, 0); 2623 } 2624 2625 static char *expand_string_to_string(const char *str) 2626 { 2627 char *argv[2], **list; 2628 2629 argv[0] = (char*)str; 2630 argv[1] = NULL; 2631 list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */ 2632 if (ENABLE_HUSH_DEBUG) 2633 if (!list[0] || list[1]) 2634 bb_error_msg_and_die("BUG in varexp2"); 2635 /* actually, just move string 2*sizeof(char*) bytes back */ 2636 strcpy((char*)list, list[0]); 2637 debug_printf_expand("string_to_string='%s'\n", (char*)list); 2638 return (char*)list; 2639 } 2640 2641 static char* expand_strvec_to_string(char **argv) 2642 { 2643 char **list; 2644 2645 list = expand_variables(argv, 0x80); 2646 /* Convert all NULs to spaces */ 2647 if (list[0]) { 2648 int n = 1; 2649 while (list[n]) { 2650 if (ENABLE_HUSH_DEBUG) 2651 if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) 2652 bb_error_msg_and_die("BUG in varexp3"); 2653 list[n][-1] = ' '; /* TODO: or to ifs[0]? */ 2654 n++; 2655 } 2656 } 2657 strcpy((char*)list, list[0]); 2658 debug_printf_expand("strvec_to_string='%s'\n", (char*)list); 2659 return (char*)list; 2660 } 2661 2662 /* This is used to get/check local shell variables */ 2663 static struct variable *get_local_var(const char *name) 2664 { 2665 struct variable *cur; 2666 int len; 2667 2668 if (!name) 2669 return NULL; 2670 len = strlen(name); 2671 for (cur = top_var; cur; cur = cur->next) { 2672 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') 2673 return cur; 2674 } 2675 return NULL; 2676 } 2677 2678 /* str holds "NAME=VAL" and is expected to be malloced. 2679 * We take ownership of it. */ 2680 static int set_local_var(char *str, int flg_export) 2681 { 2682 struct variable *cur; 2683 char *value; 2684 int name_len; 2685 2686 value = strchr(str, '='); 2687 if (!value) { /* not expected to ever happen? */ 2688 free(str); 2689 return -1; 2690 } 2691 2692 name_len = value - str + 1; /* including '=' */ 2693 cur = top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */ 2694 while (1) { 2695 if (strncmp(cur->varstr, str, name_len) != 0) { 2696 if (!cur->next) { 2697 /* Bail out. Note that now cur points 2698 * to last var in linked list */ 2699 break; 2700 } 2701 cur = cur->next; 2702 continue; 2703 } 2704 /* We found an existing var with this name */ 2705 *value = '\0'; 2706 if (cur->flg_read_only) { 2707 bb_error_msg("%s: readonly variable", str); 2708 free(str); 2709 return -1; 2710 } 2711 unsetenv(str); /* just in case */ 2712 *value = '='; 2713 if (strcmp(cur->varstr, str) == 0) { 2714 free_and_exp: 2715 free(str); 2716 goto exp; 2717 } 2718 if (cur->max_len >= strlen(str)) { 2719 /* This one is from startup env, reuse space */ 2720 strcpy(cur->varstr, str); 2721 goto free_and_exp; 2722 } 2723 /* max_len == 0 signifies "malloced" var, which we can 2724 * (and has to) free */ 2725 if (!cur->max_len) 2726 free(cur->varstr); 2727 cur->max_len = 0; 2728 goto set_str_and_exp; 2729 } 2730 2731 /* Not found - create next variable struct */ 2732 cur->next = xzalloc(sizeof(*cur)); 2733 cur = cur->next; 2734 2735 set_str_and_exp: 2736 cur->varstr = str; 2737 exp: 2738 if (flg_export) 2739 cur->flg_export = 1; 2740 if (cur->flg_export) 2741 return putenv(cur->varstr); 2742 return 0; 2743 } 2744 2745 static void unset_local_var(const char *name) 2746 { 2747 struct variable *cur; 2748 struct variable *prev = prev; /* for gcc */ 2749 int name_len; 2750 2751 if (!name) 2752 return; 2753 name_len = strlen(name); 2754 cur = top_var; 2755 while (cur) { 2756 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { 2757 if (cur->flg_read_only) { 2758 bb_error_msg("%s: readonly variable", name); 2759 return; 2760 } 2761 /* prev is ok to use here because 1st variable, HUSH_VERSION, 2762 * is ro, and we cannot reach this code on the 1st pass */ 2763 prev->next = cur->next; 2764 unsetenv(cur->varstr); 2765 if (!cur->max_len) 2766 free(cur->varstr); 2767 free(cur); 2768 return; 2769 } 2770 prev = cur; 2771 cur = cur->next; 2772 } 2773 } 2774 2775 static int is_assignment(const char *s) 2776 { 2777 if (!s || !isalpha(*s)) 2778 return 0; 2779 s++; 2780 while (isalnum(*s) || *s == '_') 2781 s++; 2782 return *s == '='; 2783 } 2784 2785 /* the src parameter allows us to peek forward to a possible &n syntax 2786 * for file descriptor duplication, e.g., "2>&1". 2787 * Return code is 0 normally, 1 if a syntax error is detected in src. 2788 * Resource errors (in xmalloc) cause the process to exit */ 2789 static int setup_redirect(struct p_context *ctx, int fd, redir_type style, 2790 struct in_str *input) 2791 { 2792 struct child_prog *child = ctx->child; 2793 struct redir_struct *redir = child->redirects; 2794 struct redir_struct *last_redir = NULL; 2795 2796 /* Create a new redir_struct and drop it onto the end of the linked list */ 2797 while (redir) { 2798 last_redir = redir; 2799 redir = redir->next; 2800 } 2801 redir = xmalloc(sizeof(struct redir_struct)); 2802 redir->next = NULL; 2803 redir->word.gl_pathv = NULL; 2804 if (last_redir) { 2805 last_redir->next = redir; 2806 } else { 2807 child->redirects = redir; 2808 } 2809 2810 redir->type = style; 2811 redir->fd = (fd == -1) ? redir_table[style].default_fd : fd; 2812 2813 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); 2814 2815 /* Check for a '2>&1' type redirect */ 2816 redir->dup = redirect_dup_num(input); 2817 if (redir->dup == -2) return 1; /* syntax error */ 2818 if (redir->dup != -1) { 2819 /* Erik had a check here that the file descriptor in question 2820 * is legit; I postpone that to "run time" 2821 * A "-" representation of "close me" shows up as a -3 here */ 2822 debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup); 2823 } else { 2824 /* We do _not_ try to open the file that src points to, 2825 * since we need to return and let src be expanded first. 2826 * Set ctx->pending_redirect, so we know what to do at the 2827 * end of the next parsed word. */ 2828 ctx->pending_redirect = redir; 2829 } 2830 return 0; 2831 } 2832 2833 static struct pipe *new_pipe(void) 2834 { 2835 struct pipe *pi; 2836 pi = xzalloc(sizeof(struct pipe)); 2837 /*pi->num_progs = 0;*/ 2838 /*pi->progs = NULL;*/ 2839 /*pi->next = NULL;*/ 2840 /*pi->followup = 0; invalid */ 2841 if (RES_NONE) 2842 pi->res_word = RES_NONE; 2843 return pi; 2844 } 2845 2846 static void initialize_context(struct p_context *ctx) 2847 { 2848 ctx->child = NULL; 2849 ctx->pipe = ctx->list_head = new_pipe(); 2850 ctx->pending_redirect = NULL; 2851 ctx->res_w = RES_NONE; 2852 //only ctx->parse_type is not touched... is this intentional? 2853 ctx->old_flag = 0; 2854 ctx->stack = NULL; 2855 done_command(ctx); /* creates the memory for working child */ 2856 } 2857 2858 /* normal return is 0 2859 * if a reserved word is found, and processed, return 1 2860 * should handle if, then, elif, else, fi, for, while, until, do, done. 2861 * case, function, and select are obnoxious, save those for later. 2862 */ 2863 #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS 2864 static int reserved_word(o_string *dest, struct p_context *ctx) 2865 { 2866 struct reserved_combo { 2867 char literal[7]; 2868 unsigned char code; 2869 int flag; 2870 }; 2871 /* Mostly a list of accepted follow-up reserved words. 2872 * FLAG_END means we are done with the sequence, and are ready 2873 * to turn the compound list into a command. 2874 * FLAG_START means the word must start a new compound list. 2875 */ 2876 static const struct reserved_combo reserved_list[] = { 2877 #if ENABLE_HUSH_IF 2878 { "if", RES_IF, FLAG_THEN | FLAG_START }, 2879 { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, 2880 { "elif", RES_ELIF, FLAG_THEN }, 2881 { "else", RES_ELSE, FLAG_FI }, 2882 { "fi", RES_FI, FLAG_END }, 2883 #endif 2884 #if ENABLE_HUSH_LOOPS 2885 { "for", RES_FOR, FLAG_IN | FLAG_START }, 2886 { "while", RES_WHILE, FLAG_DO | FLAG_START }, 2887 { "until", RES_UNTIL, FLAG_DO | FLAG_START }, 2888 { "in", RES_IN, FLAG_DO }, 2889 { "do", RES_DO, FLAG_DONE }, 2890 { "done", RES_DONE, FLAG_END } 2891 #endif 2892 }; 2893 2894 const struct reserved_combo *r; 2895 2896 for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) { 2897 if (strcmp(dest->data, r->literal) != 0) 2898 continue; 2899 debug_printf("found reserved word %s, code %d\n", r->literal, r->code); 2900 if (r->flag & FLAG_START) { 2901 struct p_context *new; 2902 debug_printf("push stack\n"); 2903 #if ENABLE_HUSH_LOOPS 2904 if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) { 2905 syntax("malformed for"); /* example: 'for if' */ 2906 ctx->res_w = RES_SNTX; 2907 b_reset(dest); 2908 return 1; 2909 } 2910 #endif 2911 new = xmalloc(sizeof(*new)); 2912 *new = *ctx; /* physical copy */ 2913 initialize_context(ctx); 2914 ctx->stack = new; 2915 } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) { 2916 syntax(NULL); 2917 ctx->res_w = RES_SNTX; 2918 b_reset(dest); 2919 return 1; 2920 } 2921 ctx->res_w = r->code; 2922 ctx->old_flag = r->flag; 2923 if (ctx->old_flag & FLAG_END) { 2924 struct p_context *old; 2925 debug_printf("pop stack\n"); 2926 done_pipe(ctx, PIPE_SEQ); 2927 old = ctx->stack; 2928 old->child->group = ctx->list_head; 2929 old->child->subshell = 0; 2930 *ctx = *old; /* physical copy */ 2931 free(old); 2932 } 2933 b_reset(dest); 2934 return 1; 2935 } 2936 return 0; 2937 } 2938 #else 2939 #define reserved_word(dest, ctx) ((int)0) 2940 #endif 2941 2942 /* Normal return is 0. 2943 * Syntax or xglob errors return 1. */ 2944 static int done_word(o_string *dest, struct p_context *ctx) 2945 { 2946 struct child_prog *child = ctx->child; 2947 glob_t *glob_target; 2948 int gr, flags = 0; 2949 2950 debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child); 2951 if (dest->length == 0 && !dest->nonnull) { 2952 debug_printf_parse("done_word return 0: true null, ignored\n"); 2953 return 0; 2954 } 2955 if (ctx->pending_redirect) { 2956 glob_target = &ctx->pending_redirect->word; 2957 } else { 2958 if (child->group) { 2959 syntax(NULL); 2960 debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); 2961 return 1; 2962 } 2963 if (!child->argv && (ctx->parse_type & PARSEFLAG_SEMICOLON)) { 2964 debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data); 2965 if (reserved_word(dest, ctx)) { 2966 debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX)); 2967 return (ctx->res_w == RES_SNTX); 2968 } 2969 } 2970 glob_target = &child->glob_result; 2971 if (child->argv) 2972 flags |= GLOB_APPEND; 2973 } 2974 gr = xglob(dest, flags, glob_target); 2975 if (gr != 0) { 2976 debug_printf_parse("done_word return 1: xglob returned %d\n", gr); 2977 return 1; 2978 } 2979 2980 b_reset(dest); 2981 if (ctx->pending_redirect) { 2982 ctx->pending_redirect = NULL; 2983 if (glob_target->gl_pathc != 1) { 2984 bb_error_msg("ambiguous redirect"); 2985 debug_printf_parse("done_word return 1: ambiguous redirect\n"); 2986 return 1; 2987 } 2988 } else { 2989 child->argv = glob_target->gl_pathv; 2990 } 2991 #if ENABLE_HUSH_LOOPS 2992 if (ctx->res_w == RES_FOR) { 2993 done_word(dest, ctx); 2994 done_pipe(ctx, PIPE_SEQ); 2995 } 2996 #endif 2997 debug_printf_parse("done_word return 0\n"); 2998 return 0; 2999 } 3000 3001 /* The only possible error here is out of memory, in which case 3002 * xmalloc exits. */ 3003 static int done_command(struct p_context *ctx) 3004 { 3005 /* The child is really already in the pipe structure, so 3006 * advance the pipe counter and make a new, null child. */ 3007 struct pipe *pi = ctx->pipe; 3008 struct child_prog *child = ctx->child; 3009 3010 if (child) { 3011 if (child->group == NULL 3012 && child->argv == NULL 3013 && child->redirects == NULL 3014 ) { 3015 debug_printf_parse("done_command: skipping null cmd, num_progs=%d\n", pi->num_progs); 3016 return pi->num_progs; 3017 } 3018 pi->num_progs++; 3019 debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs); 3020 } else { 3021 debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs); 3022 } 3023 3024 /* Only real trickiness here is that the uncommitted 3025 * child structure is not counted in pi->num_progs. */ 3026 pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); 3027 child = &pi->progs[pi->num_progs]; 3028 3029 memset(child, 0, sizeof(*child)); 3030 /*child->redirects = NULL;*/ 3031 /*child->argv = NULL;*/ 3032 /*child->is_stopped = 0;*/ 3033 /*child->group = NULL;*/ 3034 /*child->glob_result.gl_pathv = NULL;*/ 3035 child->family = pi; 3036 //sp: /*child->sp = 0;*/ 3037 //pt: child->parse_type = ctx->parse_type; 3038 3039 ctx->child = child; 3040 /* but ctx->pipe and ctx->list_head remain unchanged */ 3041 3042 return pi->num_progs; /* used only for 0/nonzero check */ 3043 } 3044 3045 static int done_pipe(struct p_context *ctx, pipe_style type) 3046 { 3047 struct pipe *new_p; 3048 int not_null; 3049 3050 debug_printf_parse("done_pipe entered, followup %d\n", type); 3051 not_null = done_command(ctx); /* implicit closure of previous command */ 3052 ctx->pipe->followup = type; 3053 ctx->pipe->res_word = ctx->res_w; 3054 /* Without this check, even just <enter> on command line generates 3055 * tree of three NOPs (!). Which is harmless but annoying. 3056 * IOW: it is safe to do it unconditionally. */ 3057 if (not_null) { 3058 new_p = new_pipe(); 3059 ctx->pipe->next = new_p; 3060 ctx->pipe = new_p; 3061 ctx->child = NULL; 3062 done_command(ctx); /* set up new pipe to accept commands */ 3063 } 3064 debug_printf_parse("done_pipe return 0\n"); 3065 return 0; 3066 } 3067 3068 /* peek ahead in the in_str to find out if we have a "&n" construct, 3069 * as in "2>&1", that represents duplicating a file descriptor. 3070 * returns either -2 (syntax error), -1 (no &), or the number found. 3071 */ 3072 static int redirect_dup_num(struct in_str *input) 3073 { 3074 int ch, d = 0, ok = 0; 3075 ch = b_peek(input); 3076 if (ch != '&') return -1; 3077 3078 b_getch(input); /* get the & */ 3079 ch = b_peek(input); 3080 if (ch == '-') { 3081 b_getch(input); 3082 return -3; /* "-" represents "close me" */ 3083 } 3084 while (isdigit(ch)) { 3085 d = d*10 + (ch-'0'); 3086 ok = 1; 3087 b_getch(input); 3088 ch = b_peek(input); 3089 } 3090 if (ok) return d; 3091 3092 bb_error_msg("ambiguous redirect"); 3093 return -2; 3094 } 3095 3096 /* If a redirect is immediately preceded by a number, that number is 3097 * supposed to tell which file descriptor to redirect. This routine 3098 * looks for such preceding numbers. In an ideal world this routine 3099 * needs to handle all the following classes of redirects... 3100 * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo 3101 * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo 3102 * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo 3103 * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo 3104 * A -1 output from this program means no valid number was found, so the 3105 * caller should use the appropriate default for this redirection. 3106 */ 3107 static int redirect_opt_num(o_string *o) 3108 { 3109 int num; 3110 3111 if (o->length == 0) 3112 return -1; 3113 for (num = 0; num < o->length; num++) { 3114 if (!isdigit(*(o->data + num))) { 3115 return -1; 3116 } 3117 } 3118 /* reuse num (and save an int) */ 3119 num = atoi(o->data); 3120 b_reset(o); 3121 return num; 3122 } 3123 3124 #if ENABLE_HUSH_TICK 3125 static FILE *generate_stream_from_list(struct pipe *head) 3126 { 3127 FILE *pf; 3128 int pid, channel[2]; 3129 3130 xpipe(channel); 3131 #if BB_MMU 3132 pid = fork(); 3133 #else 3134 pid = vfork(); 3135 #endif 3136 if (pid < 0) { 3137 bb_perror_msg_and_die("fork"); 3138 } else if (pid == 0) { 3139 close(channel[0]); 3140 if (channel[1] != 1) { 3141 dup2(channel[1], 1); 3142 close(channel[1]); 3143 } 3144 /* Prevent it from trying to handle ctrl-z etc */ 3145 #if ENABLE_HUSH_JOB 3146 run_list_level = 1; 3147 #endif 3148 /* Process substitution is not considered to be usual 3149 * 'command execution'. 3150 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. */ 3151 /* Not needed, we are relying on it being disabled 3152 * everywhere outside actual command execution. */ 3153 /*set_jobctrl_sighandler(SIG_IGN);*/ 3154 set_misc_sighandler(SIG_DFL); 3155 _exit(run_list_real(head)); /* leaks memory */ 3156 } 3157 close(channel[1]); 3158 pf = fdopen(channel[0], "r"); 3159 return pf; 3160 } 3161 3162 /* Return code is exit status of the process that is run. */ 3163 static int process_command_subs(o_string *dest, struct p_context *ctx, 3164 struct in_str *input, const char *subst_end) 3165 { 3166 int retcode, ch, eol_cnt; 3167 o_string result = NULL_O_STRING; 3168 struct p_context inner; 3169 FILE *p; 3170 struct in_str pipe_str; 3171 3172 initialize_context(&inner); 3173 3174 /* recursion to generate command */ 3175 retcode = parse_stream(&result, &inner, input, subst_end); 3176 if (retcode != 0) 3177 return retcode; /* syntax error or EOF */ 3178 done_word(&result, &inner); 3179 done_pipe(&inner, PIPE_SEQ); 3180 b_free(&result); 3181 3182 p = generate_stream_from_list(inner.list_head); 3183 if (p == NULL) return 1; 3184 mark_open(fileno(p)); 3185 setup_file_in_str(&pipe_str, p); 3186 3187 /* now send results of command back into original context */ 3188 eol_cnt = 0; 3189 while ((ch = b_getch(&pipe_str)) != EOF) { 3190 if (ch == '\n') { 3191 eol_cnt++; 3192 continue; 3193 } 3194 while (eol_cnt) { 3195 b_addqchr(dest, '\n', dest->quote); 3196 eol_cnt--; 3197 } 3198 b_addqchr(dest, ch, dest->quote); 3199 } 3200 3201 debug_printf("done reading from pipe, pclose()ing\n"); 3202 /* This is the step that wait()s for the child. Should be pretty 3203 * safe, since we just read an EOF from its stdout. We could try 3204 * to do better, by using wait(), and keeping track of background jobs 3205 * at the same time. That would be a lot of work, and contrary 3206 * to the KISS philosophy of this program. */ 3207 mark_closed(fileno(p)); 3208 retcode = fclose(p); 3209 free_pipe_list(inner.list_head, 0); 3210 debug_printf("closed FILE from child, retcode=%d\n", retcode); 3211 return retcode; 3212 } 3213 #endif 3214 3215 static int parse_group(o_string *dest, struct p_context *ctx, 3216 struct in_str *input, int ch) 3217 { 3218 int rcode; 3219 const char *endch = NULL; 3220 struct p_context sub; 3221 struct child_prog *child = ctx->child; 3222 3223 debug_printf_parse("parse_group entered\n"); 3224 if (child->argv) { 3225 syntax(NULL); 3226 debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); 3227 return 1; 3228 } 3229 initialize_context(&sub); 3230 endch = "}"; 3231 if (ch == '(') { 3232 endch = ")"; 3233 child->subshell = 1; 3234 } 3235 rcode = parse_stream(dest, &sub, input, endch); 3236 //vda: err chk? 3237 done_word(dest, &sub); /* finish off the final word in the subcontext */ 3238 done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ 3239 child->group = sub.list_head; 3240 3241 debug_printf_parse("parse_group return %d\n", rcode); 3242 return rcode; 3243 /* child remains "open", available for possible redirects */ 3244 } 3245 3246 /* Basically useful version until someone wants to get fancier, 3247 * see the bash man page under "Parameter Expansion" */ 3248 static const char *lookup_param(const char *src) 3249 { 3250 struct variable *var = get_local_var(src); 3251 if (var) 3252 return strchr(var->varstr, '=') + 1; 3253 return NULL; 3254 } 3255 3256 /* return code: 0 for OK, 1 for syntax error */ 3257 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) 3258 { 3259 int ch = b_peek(input); /* first character after the $ */ 3260 unsigned char quote_mask = dest->quote ? 0x80 : 0; 3261 3262 debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); 3263 if (isalpha(ch)) { 3264 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3265 //sp: ctx->child->sp++; 3266 while (1) { 3267 debug_printf_parse(": '%c'\n", ch); 3268 b_getch(input); 3269 b_addchr(dest, ch | quote_mask); 3270 quote_mask = 0; 3271 ch = b_peek(input); 3272 if (!isalnum(ch) && ch != '_') 3273 break; 3274 } 3275 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3276 } else if (isdigit(ch)) { 3277 make_one_char_var: 3278 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3279 //sp: ctx->child->sp++; 3280 debug_printf_parse(": '%c'\n", ch); 3281 b_getch(input); 3282 b_addchr(dest, ch | quote_mask); 3283 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3284 } else switch (ch) { 3285 case '$': /* pid */ 3286 case '!': /* last bg pid */ 3287 case '?': /* last exit code */ 3288 case '#': /* number of args */ 3289 case '*': /* args */ 3290 case '@': /* args */ 3291 goto make_one_char_var; 3292 case '{': 3293 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3294 //sp: ctx->child->sp++; 3295 b_getch(input); 3296 /* XXX maybe someone will try to escape the '}' */ 3297 while (1) { 3298 ch = b_getch(input); 3299 if (ch == '}') 3300 break; 3301 if (!isalnum(ch) && ch != '_') { 3302 syntax("unterminated ${name}"); 3303 debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); 3304 return 1; 3305 } 3306 debug_printf_parse(": '%c'\n", ch); 3307 b_addchr(dest, ch | quote_mask); 3308 quote_mask = 0; 3309 } 3310 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3311 break; 3312 #if ENABLE_HUSH_TICK 3313 case '(': 3314 b_getch(input); 3315 process_command_subs(dest, ctx, input, ")"); 3316 break; 3317 #endif 3318 case '-': 3319 case '_': 3320 /* still unhandled, but should be eventually */ 3321 bb_error_msg("unhandled syntax: $%c", ch); 3322 return 1; 3323 break; 3324 default: 3325 b_addqchr(dest, '$', dest->quote); 3326 } 3327 debug_printf_parse("handle_dollar return 0\n"); 3328 return 0; 3329 } 3330 3331 /* return code is 0 for normal exit, 1 for syntax error */ 3332 static int parse_stream(o_string *dest, struct p_context *ctx, 3333 struct in_str *input, const char *end_trigger) 3334 { 3335 int ch, m; 3336 int redir_fd; 3337 redir_type redir_style; 3338 int next; 3339 3340 /* Only double-quote state is handled in the state variable dest->quote. 3341 * A single-quote triggers a bypass of the main loop until its mate is 3342 * found. When recursing, quote state is passed in via dest->quote. */ 3343 3344 debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger); 3345 3346 while (1) { 3347 m = CHAR_IFS; 3348 next = '\0'; 3349 ch = b_getch(input); 3350 if (ch != EOF) { 3351 m = charmap[ch]; 3352 if (ch != '\n') 3353 next = b_peek(input); 3354 } 3355 debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", 3356 ch, ch, m, dest->quote); 3357 if (m == CHAR_ORDINARY 3358 || (m != CHAR_SPECIAL && dest->quote) 3359 ) { 3360 if (ch == EOF) { 3361 syntax("unterminated \""); 3362 debug_printf_parse("parse_stream return 1: unterminated \"\n"); 3363 return 1; 3364 } 3365 b_addqchr(dest, ch, dest->quote); 3366 continue; 3367 } 3368 if (m == CHAR_IFS) { 3369 if (done_word(dest, ctx)) { 3370 debug_printf_parse("parse_stream return 1: done_word!=0\n"); 3371 return 1; 3372 } 3373 if (ch == EOF) 3374 break; 3375 /* If we aren't performing a substitution, treat 3376 * a newline as a command separator. 3377 * [why we don't handle it exactly like ';'? --vda] */ 3378 if (end_trigger && ch == '\n') { 3379 done_pipe(ctx, PIPE_SEQ); 3380 } 3381 } 3382 if ((end_trigger && strchr(end_trigger, ch)) 3383 && !dest->quote && ctx->res_w == RES_NONE 3384 ) { 3385 debug_printf_parse("parse_stream return 0: end_trigger char found\n"); 3386 return 0; 3387 } 3388 if (m == CHAR_IFS) 3389 continue; 3390 switch (ch) { 3391 case '#': 3392 if (dest->length == 0 && !dest->quote) { 3393 while (1) { 3394 ch = b_peek(input); 3395 if (ch == EOF || ch == '\n') 3396 break; 3397 b_getch(input); 3398 } 3399 } else { 3400 b_addqchr(dest, ch, dest->quote); 3401 } 3402 break; 3403 case '\\': 3404 if (next == EOF) { 3405 syntax("\\<eof>"); 3406 debug_printf_parse("parse_stream return 1: \\<eof>\n"); 3407 return 1; 3408 } 3409 b_addqchr(dest, '\\', dest->quote); 3410 b_addqchr(dest, b_getch(input), dest->quote); 3411 break; 3412 case '$': 3413 if (handle_dollar(dest, ctx, input) != 0) { 3414 debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n"); 3415 return 1; 3416 } 3417 break; 3418 case '\'': 3419 dest->nonnull = 1; 3420 while (1) { 3421 ch = b_getch(input); 3422 if (ch == EOF || ch == '\'') 3423 break; 3424 b_addchr(dest, ch); 3425 } 3426 if (ch == EOF) { 3427 syntax("unterminated '"); 3428 debug_printf_parse("parse_stream return 1: unterminated '\n"); 3429 return 1; 3430 } 3431 break; 3432 case '"': 3433 dest->nonnull = 1; 3434 dest->quote = !dest->quote; 3435 break; 3436 #if ENABLE_HUSH_TICK 3437 case '`': 3438 process_command_subs(dest, ctx, input, "`"); 3439 break; 3440 #endif 3441 case '>': 3442 redir_fd = redirect_opt_num(dest); 3443 done_word(dest, ctx); 3444 redir_style = REDIRECT_OVERWRITE; 3445 if (next == '>') { 3446 redir_style = REDIRECT_APPEND; 3447 b_getch(input); 3448 } 3449 #if 0 3450 else if (next == '(') { 3451 syntax(">(process) not supported"); 3452 debug_printf_parse("parse_stream return 1: >(process) not supported\n"); 3453 return 1; 3454 } 3455 #endif 3456 setup_redirect(ctx, redir_fd, redir_style, input); 3457 break; 3458 case '<': 3459 redir_fd = redirect_opt_num(dest); 3460 done_word(dest, ctx); 3461 redir_style = REDIRECT_INPUT; 3462 if (next == '<') { 3463 redir_style = REDIRECT_HEREIS; 3464 b_getch(input); 3465 } else if (next == '>') { 3466 redir_style = REDIRECT_IO; 3467 b_getch(input); 3468 } 3469 #if 0 3470 else if (next == '(') { 3471 syntax("<(process) not supported"); 3472 debug_printf_parse("parse_stream return 1: <(process) not supported\n"); 3473 return 1; 3474 } 3475 #endif 3476 setup_redirect(ctx, redir_fd, redir_style, input); 3477 break; 3478 case ';': 3479 done_word(dest, ctx); 3480 done_pipe(ctx, PIPE_SEQ); 3481 break; 3482 case '&': 3483 done_word(dest, ctx); 3484 if (next == '&') { 3485 b_getch(input); 3486 done_pipe(ctx, PIPE_AND); 3487 } else { 3488 done_pipe(ctx, PIPE_BG); 3489 } 3490 break; 3491 case '|': 3492 done_word(dest, ctx); 3493 if (next == '|') { 3494 b_getch(input); 3495 done_pipe(ctx, PIPE_OR); 3496 } else { 3497 /* we could pick up a file descriptor choice here 3498 * with redirect_opt_num(), but bash doesn't do it. 3499 * "echo foo 2| cat" yields "foo 2". */ 3500 done_command(ctx); 3501 } 3502 break; 3503 case '(': 3504 case '{': 3505 if (parse_group(dest, ctx, input, ch) != 0) { 3506 debug_printf_parse("parse_stream return 1: parse_group returned non-0\n"); 3507 return 1; 3508 } 3509 break; 3510 case ')': 3511 case '}': 3512 syntax("unexpected }"); /* Proper use of this character is caught by end_trigger */ 3513 debug_printf_parse("parse_stream return 1: unexpected '}'\n"); 3514 return 1; 3515 default: 3516 if (ENABLE_HUSH_DEBUG) 3517 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 3518 } 3519 } 3520 /* Complain if quote? No, maybe we just finished a command substitution 3521 * that was quoted. Example: 3522 * $ echo "`cat foo` plus more" 3523 * and we just got the EOF generated by the subshell that ran "cat foo" 3524 * The only real complaint is if we got an EOF when end_trigger != NULL, 3525 * that is, we were really supposed to get end_trigger, and never got 3526 * one before the EOF. Can't use the standard "syntax error" return code, 3527 * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ 3528 debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); 3529 if (end_trigger) 3530 return -1; 3531 return 0; 3532 } 3533 3534 static void set_in_charmap(const char *set, int code) 3535 { 3536 while (*set) 3537 charmap[(unsigned char)*set++] = code; 3538 } 3539 3540 static void update_charmap(void) 3541 { 3542 /* char *ifs and char charmap[256] are both globals. */ 3543 ifs = getenv("IFS"); 3544 if (ifs == NULL) 3545 ifs = " \t\n"; 3546 /* Precompute a list of 'flow through' behavior so it can be treated 3547 * quickly up front. Computation is necessary because of IFS. 3548 * Special case handling of IFS == " \t\n" is not implemented. 3549 * The charmap[] array only really needs two bits each, 3550 * and on most machines that would be faster (reduced L1 cache use). 3551 */ 3552 memset(charmap, CHAR_ORDINARY, sizeof(charmap)); 3553 #if ENABLE_HUSH_TICK 3554 set_in_charmap("\\$\"`", CHAR_SPECIAL); 3555 #else 3556 set_in_charmap("\\$\"", CHAR_SPECIAL); 3557 #endif 3558 set_in_charmap("<>;&|(){}#'", CHAR_ORDINARY_IF_QUOTED); 3559 set_in_charmap(ifs, CHAR_IFS); /* are ordinary if quoted */ 3560 } 3561 3562 /* most recursion does not come through here, the exception is 3563 * from builtin_source() and builtin_eval() */ 3564 static int parse_and_run_stream(struct in_str *inp, int parse_flag) 3565 { 3566 struct p_context ctx; 3567 o_string temp = NULL_O_STRING; 3568 int rcode; 3569 do { 3570 ctx.parse_type = parse_flag; 3571 initialize_context(&ctx); 3572 update_charmap(); 3573 if (!(parse_flag & PARSEFLAG_SEMICOLON) || (parse_flag & PARSEFLAG_REPARSING)) 3574 set_in_charmap(";$&|", CHAR_ORDINARY); 3575 #if ENABLE_HUSH_INTERACTIVE 3576 inp->promptmode = 0; /* PS1 */ 3577 #endif 3578 /* We will stop & execute after each ';' or '\n'. 3579 * Example: "sleep 9999; echo TEST" + ctrl-C: 3580 * TEST should be printed */ 3581 rcode = parse_stream(&temp, &ctx, inp, ";\n"); 3582 if (rcode != 1 && ctx.old_flag != 0) { 3583 syntax(NULL); 3584 } 3585 if (rcode != 1 && ctx.old_flag == 0) { 3586 done_word(&temp, &ctx); 3587 done_pipe(&ctx, PIPE_SEQ); 3588 debug_print_tree(ctx.list_head, 0); 3589 debug_printf_exec("parse_stream_outer: run_list\n"); 3590 run_list(ctx.list_head); 3591 } else { 3592 if (ctx.old_flag != 0) { 3593 free(ctx.stack); 3594 b_reset(&temp); 3595 } 3596 temp.nonnull = 0; 3597 temp.quote = 0; 3598 inp->p = NULL; 3599 free_pipe_list(ctx.list_head, 0); 3600 } 3601 b_free(&temp); 3602 } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ 3603 return 0; 3604 } 3605 3606 static int parse_and_run_string(const char *s, int parse_flag) 3607 { 3608 struct in_str input; 3609 setup_string_in_str(&input, s); 3610 return parse_and_run_stream(&input, parse_flag); 3611 } 3612 3613 static int parse_and_run_file(FILE *f) 3614 { 3615 int rcode; 3616 struct in_str input; 3617 setup_file_in_str(&input, f); 3618 rcode = parse_and_run_stream(&input, PARSEFLAG_SEMICOLON); 3619 return rcode; 3620 } 3621 3622 #if ENABLE_HUSH_JOB 3623 /* Make sure we have a controlling tty. If we get started under a job 3624 * aware app (like bash for example), make sure we are now in charge so 3625 * we don't fight over who gets the foreground */ 3626 static void setup_job_control(void) 3627 { 3628 pid_t shell_pgrp; 3629 3630 saved_task_pgrp = shell_pgrp = getpgrp(); 3631 debug_printf_jobs("saved_task_pgrp=%d\n", saved_task_pgrp); 3632 fcntl(interactive_fd, F_SETFD, FD_CLOEXEC); 3633 3634 /* If we were ran as 'hush &', 3635 * sleep until we are in the foreground. */ 3636 while (tcgetpgrp(interactive_fd) != shell_pgrp) { 3637 /* Send TTIN to ourself (should stop us) */ 3638 kill(- shell_pgrp, SIGTTIN); 3639 shell_pgrp = getpgrp(); 3640 } 3641 3642 /* Ignore job-control and misc signals. */ 3643 set_jobctrl_sighandler(SIG_IGN); 3644 set_misc_sighandler(SIG_IGN); 3645 //huh? signal(SIGCHLD, SIG_IGN); 3646 3647 /* We _must_ restore tty pgrp on fatal signals */ 3648 set_fatal_sighandler(sigexit); 3649 3650 /* Put ourselves in our own process group. */ 3651 setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 3652 /* Grab control of the terminal. */ 3653 tcsetpgrp(interactive_fd, getpid()); 3654 } 3655 #endif 3656 3657 int hush_main(int argc, char **argv); 7470 } 7471 default: 7472 return EXIT_FAILURE; 7473 } 7474 return EXIT_SUCCESS; 7475 } 7476 7477 int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 3658 7478 int hush_main(int argc, char **argv) 3659 7479 { 3660 static const char version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;3661 static const struct variable const_shell_ver = {3662 .next = NULL,3663 .varstr = (char*)version_str,3664 .max_len = 1, /* 0 can provoke free(name) */3665 .flg_export = 1,3666 .flg_read_only = 1,3667 };3668 3669 7480 int opt; 3670 FILE *input;7481 unsigned builtin_argc; 3671 7482 char **e; 3672 7483 struct variable *cur_var; 3673 3674 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 3675 7484 struct variable *shell_ver; 7485 7486 INIT_G(); 7487 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ 7488 G.last_exitcode = EXIT_SUCCESS; 7489 #if !BB_MMU 7490 G.argv0_for_re_execing = argv[0]; 7491 #endif 3676 7492 /* Deal with HUSH_VERSION */ 3677 shell_ver = const_shell_ver; /* copying struct here */ 3678 top_var = &shell_ver; 7493 shell_ver = xzalloc(sizeof(*shell_ver)); 7494 shell_ver->flg_export = 1; 7495 shell_ver->flg_read_only = 1; 7496 /* Code which handles ${var<op>...} needs writable values for all variables, 7497 * therefore we xstrdup: */ 7498 shell_ver->varstr = xstrdup(hush_version_str); 7499 /* Create shell local variables from the values 7500 * currently living in the environment */ 7501 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); 3679 7502 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ 3680 /* Initialize our shell local variables with the values 3681 * currently living in the environment */ 3682 cur_var = top_var; 7503 G.top_var = shell_ver; 7504 cur_var = G.top_var; 3683 7505 e = environ; 3684 7506 if (e) while (*e) { … … 3693 7515 e++; 3694 7516 } 3695 putenv((char *)version_str); /* reinstate HUSH_VERSION */ 7517 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ 7518 debug_printf_env("putenv '%s'\n", shell_ver->varstr); 7519 putenv(shell_ver->varstr); 7520 7521 /* Export PWD */ 7522 set_pwd_var(/*exp:*/ 1); 7523 /* bash also exports SHLVL and _, 7524 * and sets (but doesn't export) the following variables: 7525 * BASH=/bin/bash 7526 * BASH_VERSINFO=([0]="3" [1]="2" [2]="0" [3]="1" [4]="release" [5]="i386-pc-linux-gnu") 7527 * BASH_VERSION='3.2.0(1)-release' 7528 * HOSTTYPE=i386 7529 * MACHTYPE=i386-pc-linux-gnu 7530 * OSTYPE=linux-gnu 7531 * HOSTNAME=<xxxxxxxxxx> 7532 * PPID=<NNNNN> - we also do it elsewhere 7533 * EUID=<NNNNN> 7534 * UID=<NNNNN> 7535 * GROUPS=() 7536 * LINES=<NNN> 7537 * COLUMNS=<NNN> 7538 * BASH_ARGC=() 7539 * BASH_ARGV=() 7540 * BASH_LINENO=() 7541 * BASH_SOURCE=() 7542 * DIRSTACK=() 7543 * PIPESTATUS=([0]="0") 7544 * HISTFILE=/<xxx>/.bash_history 7545 * HISTFILESIZE=500 7546 * HISTSIZE=500 7547 * MAILCHECK=60 7548 * PATH=/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:. 7549 * SHELL=/bin/bash 7550 * SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor 7551 * TERM=dumb 7552 * OPTERR=1 7553 * OPTIND=1 7554 * IFS=$' \t\n' 7555 * PS1='\s-\v\$ ' 7556 * PS2='> ' 7557 * PS4='+ ' 7558 */ 3696 7559 3697 7560 #if ENABLE_FEATURE_EDITING 3698 line_input_state = new_line_input_t(FOR_SHELL); 3699 #endif 3700 /* XXX what should these be while sourcing /etc/profile? */ 3701 global_argc = argc; 3702 global_argv = argv; 7561 G.line_input_state = new_line_input_t(FOR_SHELL); 7562 # if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY 7563 { 7564 const char *hp = get_local_var_value("HISTFILE"); 7565 if (!hp) { 7566 hp = get_local_var_value("HOME"); 7567 if (hp) { 7568 G.line_input_state->hist_file = concat_path_file(hp, ".hush_history"); 7569 //set_local_var(xasprintf("HISTFILE=%s", ...)); 7570 } 7571 } 7572 } 7573 # endif 7574 #endif 7575 7576 G.global_argc = argc; 7577 G.global_argv = argv; 3703 7578 /* Initialize some more globals to non-zero values */ 3704 set_cwd(); 3705 #if ENABLE_HUSH_INTERACTIVE 3706 #if ENABLE_FEATURE_EDITING 3707 cmdedit_set_initial_prompt(); 3708 #endif 3709 PS2 = "> "; 3710 #endif 3711 3712 if (EXIT_SUCCESS) /* otherwise is already done */ 3713 last_return_code = EXIT_SUCCESS; 3714 3715 if (argv[0] && argv[0][0] == '-') { 3716 debug_printf("sourcing /etc/profile\n"); 3717 input = fopen("/etc/profile", "r"); 3718 if (input != NULL) { 3719 mark_open(fileno(input)); 3720 parse_and_run_file(input); 3721 mark_closed(fileno(input)); 3722 fclose(input); 3723 } 3724 } 3725 input = stdin; 3726 3727 while ((opt = getopt(argc, argv, "c:xif")) > 0) { 7579 cmdedit_update_prompt(); 7580 7581 if (setjmp(die_jmp)) { 7582 /* xfunc has failed! die die die */ 7583 /* no EXIT traps, this is an escape hatch! */ 7584 G.exiting = 1; 7585 hush_exit(xfunc_error_retval); 7586 } 7587 7588 /* Shell is non-interactive at first. We need to call 7589 * init_sigmasks() if we are going to execute "sh <script>", 7590 * "sh -c <cmds>" or login shell's /etc/profile and friends. 7591 * If we later decide that we are interactive, we run init_sigmasks() 7592 * in order to intercept (more) signals. 7593 */ 7594 7595 /* Parse options */ 7596 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ 7597 builtin_argc = 0; 7598 while (1) { 7599 opt = getopt(argc, argv, "+c:xins" 7600 #if !BB_MMU 7601 "<:$:R:V:" 7602 # if ENABLE_HUSH_FUNCTIONS 7603 "F:" 7604 # endif 7605 #endif 7606 ); 7607 if (opt <= 0) 7608 break; 3728 7609 switch (opt) { 3729 7610 case 'c': 3730 global_argv = argv + optind; 3731 global_argc = argc - optind; 3732 opt = parse_and_run_string(optarg, PARSEFLAG_SEMICOLON); 7611 /* Possibilities: 7612 * sh ... -c 'script' 7613 * sh ... -c 'script' ARG0 [ARG1...] 7614 * On NOMMU, if builtin_argc != 0, 7615 * sh ... -c 'builtin' BARGV... "" ARG0 [ARG1...] 7616 * "" needs to be replaced with NULL 7617 * and BARGV vector fed to builtin function. 7618 * Note: the form without ARG0 never happens: 7619 * sh ... -c 'builtin' BARGV... "" 7620 */ 7621 if (!G.root_pid) { 7622 G.root_pid = getpid(); 7623 G.root_ppid = getppid(); 7624 } 7625 G.global_argv = argv + optind; 7626 G.global_argc = argc - optind; 7627 if (builtin_argc) { 7628 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ 7629 const struct built_in_command *x; 7630 7631 init_sigmasks(); 7632 x = find_builtin(optarg); 7633 if (x) { /* paranoia */ 7634 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ 7635 G.global_argv += builtin_argc; 7636 G.global_argv[-1] = NULL; /* replace "" */ 7637 G.last_exitcode = x->b_function(argv + optind - 1); 7638 } 7639 goto final_return; 7640 } 7641 if (!G.global_argv[0]) { 7642 /* -c 'script' (no params): prevent empty $0 */ 7643 G.global_argv--; /* points to argv[i] of 'script' */ 7644 G.global_argv[0] = argv[0]; 7645 G.global_argc++; 7646 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ 7647 init_sigmasks(); 7648 parse_and_run_string(optarg); 3733 7649 goto final_return; 3734 7650 case 'i': 3735 7651 /* Well, we cannot just declare interactiveness, 3736 7652 * we have to have some stuff (ctty, etc) */ 3737 /* interactive_fd++; */7653 /* G_interactive_fd++; */ 3738 7654 break; 3739 case 'f': 3740 fake_mode = 1; 7655 case 's': 7656 /* "-s" means "read from stdin", but this is how we always 7657 * operate, so simply do nothing here. */ 3741 7658 break; 7659 #if !BB_MMU 7660 case '<': /* "big heredoc" support */ 7661 full_write1_str(optarg); 7662 _exit(0); 7663 case '$': { 7664 unsigned long long empty_trap_mask; 7665 7666 G.root_pid = bb_strtou(optarg, &optarg, 16); 7667 optarg++; 7668 G.root_ppid = bb_strtou(optarg, &optarg, 16); 7669 optarg++; 7670 G.last_bg_pid = bb_strtou(optarg, &optarg, 16); 7671 optarg++; 7672 G.last_exitcode = bb_strtou(optarg, &optarg, 16); 7673 optarg++; 7674 builtin_argc = bb_strtou(optarg, &optarg, 16); 7675 optarg++; 7676 empty_trap_mask = bb_strtoull(optarg, &optarg, 16); 7677 if (empty_trap_mask != 0) { 7678 int sig; 7679 init_sigmasks(); 7680 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7681 for (sig = 1; sig < NSIG; sig++) { 7682 if (empty_trap_mask & (1LL << sig)) { 7683 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7684 sigaddset(&G.blocked_set, sig); 7685 } 7686 } 7687 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 7688 } 7689 # if ENABLE_HUSH_LOOPS 7690 optarg++; 7691 G.depth_of_loop = bb_strtou(optarg, &optarg, 16); 7692 # endif 7693 break; 7694 } 7695 case 'R': 7696 case 'V': 7697 set_local_var(xstrdup(optarg), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ opt == 'R'); 7698 break; 7699 # if ENABLE_HUSH_FUNCTIONS 7700 case 'F': { 7701 struct function *funcp = new_function(optarg); 7702 /* funcp->name is already set to optarg */ 7703 /* funcp->body is set to NULL. It's a special case. */ 7704 funcp->body_as_string = argv[optind]; 7705 optind++; 7706 break; 7707 } 7708 # endif 7709 #endif 7710 case 'n': 7711 case 'x': 7712 if (set_mode(1, opt, NULL) == 0) /* no error */ 7713 break; 3742 7714 default: 3743 7715 #ifndef BB_VER … … 3749 7721 #endif 3750 7722 } 3751 } 3752 #if ENABLE_HUSH_JOB 3753 /* A shell is interactive if the '-i' flag was given, or if all of 3754 * the following conditions are met: 7723 } /* option parsing loop */ 7724 7725 if (!G.root_pid) { 7726 G.root_pid = getpid(); 7727 G.root_ppid = getppid(); 7728 } 7729 7730 /* If we are login shell... */ 7731 if (argv[0] && argv[0][0] == '-') { 7732 FILE *input; 7733 debug_printf("sourcing /etc/profile\n"); 7734 input = fopen_for_read("/etc/profile"); 7735 if (input != NULL) { 7736 close_on_exec_on(fileno(input)); 7737 init_sigmasks(); 7738 parse_and_run_file(input); 7739 fclose(input); 7740 } 7741 /* bash: after sourcing /etc/profile, 7742 * tries to source (in the given order): 7743 * ~/.bash_profile, ~/.bash_login, ~/.profile, 7744 * stopping on first found. --noprofile turns this off. 7745 * bash also sources ~/.bash_logout on exit. 7746 * If called as sh, skips .bash_XXX files. 7747 */ 7748 } 7749 7750 if (argv[optind]) { 7751 FILE *input; 7752 /* 7753 * "bash <script>" (which is never interactive (unless -i?)) 7754 * sources $BASH_ENV here (without scanning $PATH). 7755 * If called as sh, does the same but with $ENV. 7756 */ 7757 debug_printf("running script '%s'\n", argv[optind]); 7758 G.global_argv = argv + optind; 7759 G.global_argc = argc - optind; 7760 input = xfopen_for_read(argv[optind]); 7761 close_on_exec_on(fileno(input)); 7762 init_sigmasks(); 7763 parse_and_run_file(input); 7764 #if ENABLE_FEATURE_CLEAN_UP 7765 fclose(input); 7766 #endif 7767 goto final_return; 7768 } 7769 7770 /* Up to here, shell was non-interactive. Now it may become one. 7771 * NB: don't forget to (re)run init_sigmasks() as needed. 7772 */ 7773 7774 /* A shell is interactive if the '-i' flag was given, 7775 * or if all of the following conditions are met: 3755 7776 * no -c command 3756 7777 * no arguments remaining or the -s flag given 3757 7778 * standard input is a terminal 3758 7779 * standard output is a terminal 3759 * Refer to Posix.2, the description of the 'sh' utility. */ 3760 if (argv[optind] == NULL && input == stdin 3761 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 3762 ) { 3763 saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); 3764 debug_printf("saved_tty_pgrp=%d\n", saved_tty_pgrp); 3765 if (saved_tty_pgrp >= 0) { 3766 /* try to dup to high fd#, >= 255 */ 3767 interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 3768 if (interactive_fd < 0) { 3769 /* try to dup to any fd */ 3770 interactive_fd = dup(STDIN_FILENO); 3771 if (interactive_fd < 0) 3772 /* give up */ 3773 interactive_fd = 0; 3774 } 3775 // TODO: track & disallow any attempts of user 3776 // to (inadvertently) close/redirect it 3777 } 3778 } 3779 debug_printf("interactive_fd=%d\n", interactive_fd); 3780 if (interactive_fd) { 3781 /* Looks like they want an interactive shell */ 3782 setup_job_control(); 3783 /* Make xfuncs do cleanup on exit */ 3784 die_sleep = -1; /* flag */ 3785 // FIXME: should we reset die_sleep = 0 whereever we fork? 3786 if (setjmp(die_jmp)) { 3787 /* xfunc has failed! die die die */ 3788 hush_exit(xfunc_error_retval); 3789 } 3790 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 3791 printf("\n\n%s hush - the humble shell v"HUSH_VER_STR"\n", bb_banner); 3792 printf("Enter 'help' for a list of built-in commands.\n\n"); 3793 #endif 7780 * Refer to Posix.2, the description of the 'sh' utility. 7781 */ 7782 #if ENABLE_HUSH_JOB 7783 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 7784 G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); 7785 debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); 7786 if (G_saved_tty_pgrp < 0) 7787 G_saved_tty_pgrp = 0; 7788 7789 /* try to dup stdin to high fd#, >= 255 */ 7790 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 7791 if (G_interactive_fd < 0) { 7792 /* try to dup to any fd */ 7793 G_interactive_fd = dup(STDIN_FILENO); 7794 if (G_interactive_fd < 0) { 7795 /* give up */ 7796 G_interactive_fd = 0; 7797 G_saved_tty_pgrp = 0; 7798 } 7799 } 7800 // TODO: track & disallow any attempts of user 7801 // to (inadvertently) close/redirect G_interactive_fd 7802 } 7803 debug_printf("interactive_fd:%d\n", G_interactive_fd); 7804 if (G_interactive_fd) { 7805 close_on_exec_on(G_interactive_fd); 7806 7807 if (G_saved_tty_pgrp) { 7808 /* If we were run as 'hush &', sleep until we are 7809 * in the foreground (tty pgrp == our pgrp). 7810 * If we get started under a job aware app (like bash), 7811 * make sure we are now in charge so we don't fight over 7812 * who gets the foreground */ 7813 while (1) { 7814 pid_t shell_pgrp = getpgrp(); 7815 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); 7816 if (G_saved_tty_pgrp == shell_pgrp) 7817 break; 7818 /* send TTIN to ourself (should stop us) */ 7819 kill(- shell_pgrp, SIGTTIN); 7820 } 7821 } 7822 7823 /* Block some signals */ 7824 init_sigmasks(); 7825 7826 if (G_saved_tty_pgrp) { 7827 /* Set other signals to restore saved_tty_pgrp */ 7828 set_fatal_handlers(); 7829 /* Put ourselves in our own process group 7830 * (bash, too, does this only if ctty is available) */ 7831 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 7832 /* Grab control of the terminal */ 7833 tcsetpgrp(G_interactive_fd, getpid()); 7834 } 7835 /* -1 is special - makes xfuncs longjmp, not exit 7836 * (we reset die_sleep = 0 whereever we [v]fork) */ 7837 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 7838 } else { 7839 init_sigmasks(); 3794 7840 } 3795 7841 #elif ENABLE_HUSH_INTERACTIVE 3796 /* no job control compiled, only prompt/line editing */ 3797 if (argv[optind] == NULL && input == stdin 3798 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 3799 ) { 3800 interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 3801 if (interactive_fd < 0) { 7842 /* No job control compiled in, only prompt/line editing */ 7843 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 7844 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 7845 if (G_interactive_fd < 0) { 3802 7846 /* try to dup to any fd */ 3803 interactive_fd = dup(STDIN_FILENO);3804 if ( interactive_fd < 0)7847 G_interactive_fd = dup(STDIN_FILENO); 7848 if (G_interactive_fd < 0) 3805 7849 /* give up */ 3806 interactive_fd = 0; 3807 } 3808 } 3809 3810 #endif 3811 3812 if (argv[optind] == NULL) { 3813 opt = parse_and_run_file(stdin); 3814 goto final_return; 3815 } 3816 3817 debug_printf("\nrunning script '%s'\n", argv[optind]); 3818 global_argv = argv + optind; 3819 global_argc = argc - optind; 3820 input = xfopen(argv[optind], "r"); 3821 opt = parse_and_run_file(input); 7850 G_interactive_fd = 0; 7851 } 7852 } 7853 if (G_interactive_fd) { 7854 close_on_exec_on(G_interactive_fd); 7855 } 7856 init_sigmasks(); 7857 #else 7858 /* We have interactiveness code disabled */ 7859 init_sigmasks(); 7860 #endif 7861 /* bash: 7862 * if interactive but not a login shell, sources ~/.bashrc 7863 * (--norc turns this off, --rcfile <file> overrides) 7864 */ 7865 7866 if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) { 7867 /* note: ash and hush share this string */ 7868 printf("\n\n%s %s\n" 7869 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") 7870 "\n", 7871 bb_banner, 7872 "hush - the humble shell" 7873 ); 7874 } 7875 7876 parse_and_run_file(stdin); 3822 7877 3823 7878 final_return: 3824 3825 #if ENABLE_FEATURE_CLEAN_UP 7879 hush_exit(G.last_exitcode); 7880 } 7881 7882 7883 #if ENABLE_MSH 7884 int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 7885 int msh_main(int argc, char **argv) 7886 { 7887 //bb_error_msg("msh is deprecated, please use hush instead"); 7888 return hush_main(argc, argv); 7889 } 7890 #endif 7891 7892 7893 /* 7894 * Built-ins 7895 */ 7896 static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM) 7897 { 7898 return 0; 7899 } 7900 7901 static int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) 7902 { 7903 int argc = 0; 7904 while (*argv) { 7905 argc++; 7906 argv++; 7907 } 7908 return applet_main_func(argc, argv - argc); 7909 } 7910 7911 static int FAST_FUNC builtin_test(char **argv) 7912 { 7913 return run_applet_main(argv, test_main); 7914 } 7915 7916 static int FAST_FUNC builtin_echo(char **argv) 7917 { 7918 return run_applet_main(argv, echo_main); 7919 } 7920 7921 #if ENABLE_PRINTF 7922 static int FAST_FUNC builtin_printf(char **argv) 7923 { 7924 return run_applet_main(argv, printf_main); 7925 } 7926 #endif 7927 7928 static char **skip_dash_dash(char **argv) 7929 { 7930 argv++; 7931 if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == '\0') 7932 argv++; 7933 return argv; 7934 } 7935 7936 static int FAST_FUNC builtin_eval(char **argv) 7937 { 7938 int rcode = EXIT_SUCCESS; 7939 7940 argv = skip_dash_dash(argv); 7941 if (*argv) { 7942 char *str = expand_strvec_to_string(argv); 7943 /* bash: 7944 * eval "echo Hi; done" ("done" is syntax error): 7945 * "echo Hi" will not execute too. 7946 */ 7947 parse_and_run_string(str); 7948 free(str); 7949 rcode = G.last_exitcode; 7950 } 7951 return rcode; 7952 } 7953 7954 static int FAST_FUNC builtin_cd(char **argv) 7955 { 7956 const char *newdir; 7957 7958 argv = skip_dash_dash(argv); 7959 newdir = argv[0]; 7960 if (newdir == NULL) { 7961 /* bash does nothing (exitcode 0) if HOME is ""; if it's unset, 7962 * bash says "bash: cd: HOME not set" and does nothing 7963 * (exitcode 1) 7964 */ 7965 const char *home = get_local_var_value("HOME"); 7966 newdir = home ? home : "/"; 7967 } 7968 if (chdir(newdir)) { 7969 /* Mimic bash message exactly */ 7970 bb_perror_msg("cd: %s", newdir); 7971 return EXIT_FAILURE; 7972 } 7973 /* Read current dir (get_cwd(1) is inside) and set PWD. 7974 * Note: do not enforce exporting. If PWD was unset or unexported, 7975 * set it again, but do not export. bash does the same. 7976 */ 7977 set_pwd_var(/*exp:*/ 0); 7978 return EXIT_SUCCESS; 7979 } 7980 7981 static int FAST_FUNC builtin_exec(char **argv) 7982 { 7983 argv = skip_dash_dash(argv); 7984 if (argv[0] == NULL) 7985 return EXIT_SUCCESS; /* bash does this */ 7986 7987 /* Careful: we can end up here after [v]fork. Do not restore 7988 * tty pgrp then, only top-level shell process does that */ 7989 if (G_saved_tty_pgrp && getpid() == G.root_pid) 7990 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 7991 7992 /* TODO: if exec fails, bash does NOT exit! We do. 7993 * We'll need to undo sigprocmask (it's inside execvp_or_die) 7994 * and tcsetpgrp, and this is inherently racy. 7995 */ 7996 execvp_or_die(argv); 7997 } 7998 7999 static int FAST_FUNC builtin_exit(char **argv) 8000 { 8001 debug_printf_exec("%s()\n", __func__); 8002 8003 /* interactive bash: 8004 * # trap "echo EEE" EXIT 8005 * # exit 8006 * exit 8007 * There are stopped jobs. 8008 * (if there are _stopped_ jobs, running ones don't count) 8009 * # exit 8010 * exit 8011 # EEE (then bash exits) 8012 * 8013 * TODO: we can use G.exiting = -1 as indicator "last cmd was exit" 8014 */ 8015 8016 /* note: EXIT trap is run by hush_exit */ 8017 argv = skip_dash_dash(argv); 8018 if (argv[0] == NULL) 8019 hush_exit(G.last_exitcode); 8020 /* mimic bash: exit 123abc == exit 255 + error msg */ 8021 xfunc_error_retval = 255; 8022 /* bash: exit -2 == exit 254, no error msg */ 8023 hush_exit(xatoi(argv[0]) & 0xff); 8024 } 8025 8026 static void print_escaped(const char *s) 8027 { 8028 if (*s == '\'') 8029 goto squote; 8030 do { 8031 const char *p = strchrnul(s, '\''); 8032 /* print 'xxxx', possibly just '' */ 8033 printf("'%.*s'", (int)(p - s), s); 8034 if (*p == '\0') 8035 break; 8036 s = p; 8037 squote: 8038 /* s points to '; print "'''...'''" */ 8039 putchar('"'); 8040 do putchar('\''); while (*++s == '\''); 8041 putchar('"'); 8042 } while (*s); 8043 } 8044 8045 #if !ENABLE_HUSH_LOCAL 8046 #define helper_export_local(argv, exp, lvl) \ 8047 helper_export_local(argv, exp) 8048 #endif 8049 static void helper_export_local(char **argv, int exp, int lvl) 8050 { 8051 do { 8052 char *name = *argv; 8053 char *name_end = strchrnul(name, '='); 8054 8055 /* So far we do not check that name is valid (TODO?) */ 8056 8057 if (*name_end == '\0') { 8058 struct variable *var, **vpp; 8059 8060 vpp = get_ptr_to_local_var(name, name_end - name); 8061 var = vpp ? *vpp : NULL; 8062 8063 if (exp == -1) { /* unexporting? */ 8064 /* export -n NAME (without =VALUE) */ 8065 if (var) { 8066 var->flg_export = 0; 8067 debug_printf_env("%s: unsetenv '%s'\n", __func__, name); 8068 unsetenv(name); 8069 } /* else: export -n NOT_EXISTING_VAR: no-op */ 8070 continue; 8071 } 8072 if (exp == 1) { /* exporting? */ 8073 /* export NAME (without =VALUE) */ 8074 if (var) { 8075 var->flg_export = 1; 8076 debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr); 8077 putenv(var->varstr); 8078 continue; 8079 } 8080 } 8081 /* Exporting non-existing variable. 8082 * bash does not put it in environment, 8083 * but remembers that it is exported, 8084 * and does put it in env when it is set later. 8085 * We just set it to "" and export. */ 8086 /* Or, it's "local NAME" (without =VALUE). 8087 * bash sets the value to "". */ 8088 name = xasprintf("%s=", name); 8089 } else { 8090 /* (Un)exporting/making local NAME=VALUE */ 8091 name = xstrdup(name); 8092 } 8093 set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ 0); 8094 } while (*++argv); 8095 } 8096 8097 static int FAST_FUNC builtin_export(char **argv) 8098 { 8099 unsigned opt_unexport; 8100 8101 #if ENABLE_HUSH_EXPORT_N 8102 /* "!": do not abort on errors */ 8103 opt_unexport = getopt32(argv, "!n"); 8104 if (opt_unexport == (uint32_t)-1) 8105 return EXIT_FAILURE; 8106 argv += optind; 8107 #else 8108 opt_unexport = 0; 8109 argv++; 8110 #endif 8111 8112 if (argv[0] == NULL) { 8113 char **e = environ; 8114 if (e) { 8115 while (*e) { 8116 #if 0 8117 puts(*e++); 8118 #else 8119 /* ash emits: export VAR='VAL' 8120 * bash: declare -x VAR="VAL" 8121 * we follow ash example */ 8122 const char *s = *e++; 8123 const char *p = strchr(s, '='); 8124 8125 if (!p) /* wtf? take next variable */ 8126 continue; 8127 /* export var= */ 8128 printf("export %.*s", (int)(p - s) + 1, s); 8129 print_escaped(p + 1); 8130 putchar('\n'); 8131 #endif 8132 } 8133 /*fflush_all(); - done after each builtin anyway */ 8134 } 8135 return EXIT_SUCCESS; 8136 } 8137 8138 helper_export_local(argv, (opt_unexport ? -1 : 1), 0); 8139 8140 return EXIT_SUCCESS; 8141 } 8142 8143 #if ENABLE_HUSH_LOCAL 8144 static int FAST_FUNC builtin_local(char **argv) 8145 { 8146 if (G.func_nest_level == 0) { 8147 bb_error_msg("%s: not in a function", argv[0]); 8148 return EXIT_FAILURE; /* bash compat */ 8149 } 8150 helper_export_local(argv, 0, G.func_nest_level); 8151 return EXIT_SUCCESS; 8152 } 8153 #endif 8154 8155 static int FAST_FUNC builtin_trap(char **argv) 8156 { 8157 int sig; 8158 char *new_cmd; 8159 8160 if (!G.traps) 8161 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 8162 8163 argv++; 8164 if (!*argv) { 8165 int i; 8166 /* No args: print all trapped */ 8167 for (i = 0; i < NSIG; ++i) { 8168 if (G.traps[i]) { 8169 printf("trap -- "); 8170 print_escaped(G.traps[i]); 8171 /* note: bash adds "SIG", but only if invoked 8172 * as "bash". If called as "sh", or if set -o posix, 8173 * then it prints short signal names. 8174 * We are printing short names: */ 8175 printf(" %s\n", get_signame(i)); 8176 } 8177 } 8178 /*fflush_all(); - done after each builtin anyway */ 8179 return EXIT_SUCCESS; 8180 } 8181 8182 new_cmd = NULL; 8183 /* If first arg is a number: reset all specified signals */ 8184 sig = bb_strtou(*argv, NULL, 10); 8185 if (errno == 0) { 8186 int ret; 8187 process_sig_list: 8188 ret = EXIT_SUCCESS; 8189 while (*argv) { 8190 sig = get_signum(*argv++); 8191 if (sig < 0 || sig >= NSIG) { 8192 ret = EXIT_FAILURE; 8193 /* Mimic bash message exactly */ 8194 bb_perror_msg("trap: %s: invalid signal specification", argv[-1]); 8195 continue; 8196 } 8197 8198 free(G.traps[sig]); 8199 G.traps[sig] = xstrdup(new_cmd); 8200 8201 debug_printf("trap: setting SIG%s (%i) to '%s'\n", 8202 get_signame(sig), sig, G.traps[sig]); 8203 8204 /* There is no signal for 0 (EXIT) */ 8205 if (sig == 0) 8206 continue; 8207 8208 if (new_cmd) { 8209 sigaddset(&G.blocked_set, sig); 8210 } else { 8211 /* There was a trap handler, we are removing it 8212 * (if sig has non-DFL handling, 8213 * we don't need to do anything) */ 8214 if (sig < 32 && (G.non_DFL_mask & (1 << sig))) 8215 continue; 8216 sigdelset(&G.blocked_set, sig); 8217 } 8218 } 8219 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 8220 return ret; 8221 } 8222 8223 if (!argv[1]) { /* no second arg */ 8224 bb_error_msg("trap: invalid arguments"); 8225 return EXIT_FAILURE; 8226 } 8227 8228 /* First arg is "-": reset all specified to default */ 8229 /* First arg is "--": skip it, the rest is "handler SIGs..." */ 8230 /* Everything else: set arg as signal handler 8231 * (includes "" case, which ignores signal) */ 8232 if (argv[0][0] == '-') { 8233 if (argv[0][1] == '\0') { /* "-" */ 8234 /* new_cmd remains NULL: "reset these sigs" */ 8235 goto reset_traps; 8236 } 8237 if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */ 8238 argv++; 8239 } 8240 /* else: "-something", no special meaning */ 8241 } 8242 new_cmd = *argv; 8243 reset_traps: 8244 argv++; 8245 goto process_sig_list; 8246 } 8247 8248 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */ 8249 static int FAST_FUNC builtin_type(char **argv) 8250 { 8251 int ret = EXIT_SUCCESS; 8252 8253 while (*++argv) { 8254 const char *type; 8255 char *path = NULL; 8256 8257 if (0) {} /* make conditional compile easier below */ 8258 /*else if (find_alias(*argv)) 8259 type = "an alias";*/ 8260 #if ENABLE_HUSH_FUNCTIONS 8261 else if (find_function(*argv)) 8262 type = "a function"; 8263 #endif 8264 else if (find_builtin(*argv)) 8265 type = "a shell builtin"; 8266 else if ((path = find_in_path(*argv)) != NULL) 8267 type = path; 8268 else { 8269 bb_error_msg("type: %s: not found", *argv); 8270 ret = EXIT_FAILURE; 8271 continue; 8272 } 8273 8274 printf("%s is %s\n", *argv, type); 8275 free(path); 8276 } 8277 8278 return ret; 8279 } 8280 8281 #if ENABLE_HUSH_JOB 8282 /* built-in 'fg' and 'bg' handler */ 8283 static int FAST_FUNC builtin_fg_bg(char **argv) 8284 { 8285 int i, jobnum; 8286 struct pipe *pi; 8287 8288 if (!G_interactive_fd) 8289 return EXIT_FAILURE; 8290 8291 /* If they gave us no args, assume they want the last backgrounded task */ 8292 if (!argv[1]) { 8293 for (pi = G.job_list; pi; pi = pi->next) { 8294 if (pi->jobid == G.last_jobid) { 8295 goto found; 8296 } 8297 } 8298 bb_error_msg("%s: no current job", argv[0]); 8299 return EXIT_FAILURE; 8300 } 8301 if (sscanf(argv[1], "%%%d", &jobnum) != 1) { 8302 bb_error_msg("%s: bad argument '%s'", argv[0], argv[1]); 8303 return EXIT_FAILURE; 8304 } 8305 for (pi = G.job_list; pi; pi = pi->next) { 8306 if (pi->jobid == jobnum) { 8307 goto found; 8308 } 8309 } 8310 bb_error_msg("%s: %d: no such job", argv[0], jobnum); 8311 return EXIT_FAILURE; 8312 found: 8313 /* TODO: bash prints a string representation 8314 * of job being foregrounded (like "sleep 1 | cat") */ 8315 if (argv[0][0] == 'f' && G_saved_tty_pgrp) { 8316 /* Put the job into the foreground. */ 8317 tcsetpgrp(G_interactive_fd, pi->pgrp); 8318 } 8319 8320 /* Restart the processes in the job */ 8321 debug_printf_jobs("reviving %d procs, pgrp %d\n", pi->num_cmds, pi->pgrp); 8322 for (i = 0; i < pi->num_cmds; i++) { 8323 debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid); 8324 pi->cmds[i].is_stopped = 0; 8325 } 8326 pi->stopped_cmds = 0; 8327 8328 i = kill(- pi->pgrp, SIGCONT); 8329 if (i < 0) { 8330 if (errno == ESRCH) { 8331 delete_finished_bg_job(pi); 8332 return EXIT_SUCCESS; 8333 } 8334 bb_perror_msg("kill (SIGCONT)"); 8335 } 8336 8337 if (argv[0][0] == 'f') { 8338 remove_bg_job(pi); 8339 return checkjobs_and_fg_shell(pi); 8340 } 8341 return EXIT_SUCCESS; 8342 } 8343 #endif 8344 8345 #if ENABLE_HUSH_HELP 8346 static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM) 8347 { 8348 const struct built_in_command *x; 8349 8350 printf( 8351 "Built-in commands:\n" 8352 "------------------\n"); 8353 for (x = bltins1; x != &bltins1[ARRAY_SIZE(bltins1)]; x++) { 8354 if (x->b_descr) 8355 printf("%-10s%s\n", x->b_cmd, x->b_descr); 8356 } 8357 bb_putchar('\n'); 8358 return EXIT_SUCCESS; 8359 } 8360 #endif 8361 8362 #if ENABLE_HUSH_JOB 8363 static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM) 8364 { 8365 struct pipe *job; 8366 const char *status_string; 8367 8368 for (job = G.job_list; job; job = job->next) { 8369 if (job->alive_cmds == job->stopped_cmds) 8370 status_string = "Stopped"; 8371 else 8372 status_string = "Running"; 8373 8374 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); 8375 } 8376 return EXIT_SUCCESS; 8377 } 8378 #endif 8379 8380 #if HUSH_DEBUG 8381 static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) 8382 { 8383 void *p; 8384 unsigned long l; 8385 8386 # ifdef M_TRIM_THRESHOLD 8387 /* Optional. Reduces probability of false positives */ 8388 malloc_trim(0); 8389 # endif 8390 /* Crude attempt to find where "free memory" starts, 8391 * sans fragmentation. */ 8392 p = malloc(240); 8393 l = (unsigned long)p; 8394 free(p); 8395 p = malloc(3400); 8396 if (l < (unsigned long)p) l = (unsigned long)p; 8397 free(p); 8398 8399 if (!G.memleak_value) 8400 G.memleak_value = l; 8401 8402 l -= G.memleak_value; 8403 if ((long)l < 0) 8404 l = 0; 8405 l /= 1024; 8406 if (l > 127) 8407 l = 127; 8408 8409 /* Exitcode is "how many kilobytes we leaked since 1st call" */ 8410 return l; 8411 } 8412 #endif 8413 8414 static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) 8415 { 8416 puts(get_cwd(0)); 8417 return EXIT_SUCCESS; 8418 } 8419 8420 static int FAST_FUNC builtin_read(char **argv) 8421 { 8422 const char *r; 8423 char *opt_n = NULL; 8424 char *opt_p = NULL; 8425 char *opt_t = NULL; 8426 char *opt_u = NULL; 8427 int read_flags; 8428 8429 /* "!": do not abort on errors. 8430 * Option string must start with "sr" to match BUILTIN_READ_xxx 8431 */ 8432 read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); 8433 if (read_flags == (uint32_t)-1) 8434 return EXIT_FAILURE; 8435 argv += optind; 8436 8437 r = shell_builtin_read(set_local_var_from_halves, 8438 argv, 8439 get_local_var_value("IFS"), /* can be NULL */ 8440 read_flags, 8441 opt_n, 8442 opt_p, 8443 opt_t, 8444 opt_u 8445 ); 8446 8447 if ((uintptr_t)r > 1) { 8448 bb_error_msg("%s", r); 8449 r = (char*)(uintptr_t)1; 8450 } 8451 8452 return (uintptr_t)r; 8453 } 8454 8455 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set 8456 * built-in 'set' handler 8457 * SUSv3 says: 8458 * set [-abCefhmnuvx] [-o option] [argument...] 8459 * set [+abCefhmnuvx] [+o option] [argument...] 8460 * set -- [argument...] 8461 * set -o 8462 * set +o 8463 * Implementations shall support the options in both their hyphen and 8464 * plus-sign forms. These options can also be specified as options to sh. 8465 * Examples: 8466 * Write out all variables and their values: set 8467 * Set $1, $2, and $3 and set "$#" to 3: set c a b 8468 * Turn on the -x and -v options: set -xv 8469 * Unset all positional parameters: set -- 8470 * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x" 8471 * Set the positional parameters to the expansion of x, even if x expands 8472 * with a leading '-' or '+': set -- $x 8473 * 8474 * So far, we only support "set -- [argument...]" and some of the short names. 8475 */ 8476 static int FAST_FUNC builtin_set(char **argv) 8477 { 8478 int n; 8479 char **pp, **g_argv; 8480 char *arg = *++argv; 8481 8482 if (arg == NULL) { 8483 struct variable *e; 8484 for (e = G.top_var; e; e = e->next) 8485 puts(e->varstr); 8486 return EXIT_SUCCESS; 8487 } 8488 8489 do { 8490 if (strcmp(arg, "--") == 0) { 8491 ++argv; 8492 goto set_argv; 8493 } 8494 if (arg[0] != '+' && arg[0] != '-') 8495 break; 8496 for (n = 1; arg[n]; ++n) { 8497 if (set_mode((arg[0] == '-'), arg[n], argv[1])) 8498 goto error; 8499 if (arg[n] == 'o' && argv[1]) 8500 argv++; 8501 } 8502 } while ((arg = *++argv) != NULL); 8503 /* Now argv[0] is 1st argument */ 8504 8505 if (arg == NULL) 8506 return EXIT_SUCCESS; 8507 set_argv: 8508 8509 /* NB: G.global_argv[0] ($0) is never freed/changed */ 8510 g_argv = G.global_argv; 8511 if (G.global_args_malloced) { 8512 pp = g_argv; 8513 while (*++pp) 8514 free(*pp); 8515 g_argv[1] = NULL; 8516 } else { 8517 G.global_args_malloced = 1; 8518 pp = xzalloc(sizeof(pp[0]) * 2); 8519 pp[0] = g_argv[0]; /* retain $0 */ 8520 g_argv = pp; 8521 } 8522 /* This realloc's G.global_argv */ 8523 G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1); 8524 8525 n = 1; 8526 while (*++pp) 8527 n++; 8528 G.global_argc = n; 8529 8530 return EXIT_SUCCESS; 8531 8532 /* Nothing known, so abort */ 8533 error: 8534 bb_error_msg("set: %s: invalid option", arg); 8535 return EXIT_FAILURE; 8536 } 8537 8538 static int FAST_FUNC builtin_shift(char **argv) 8539 { 8540 int n = 1; 8541 argv = skip_dash_dash(argv); 8542 if (argv[0]) { 8543 n = atoi(argv[0]); 8544 } 8545 if (n >= 0 && n < G.global_argc) { 8546 if (G.global_args_malloced) { 8547 int m = 1; 8548 while (m <= n) 8549 free(G.global_argv[m++]); 8550 } 8551 G.global_argc -= n; 8552 memmove(&G.global_argv[1], &G.global_argv[n+1], 8553 G.global_argc * sizeof(G.global_argv[0])); 8554 return EXIT_SUCCESS; 8555 } 8556 return EXIT_FAILURE; 8557 } 8558 8559 static int FAST_FUNC builtin_source(char **argv) 8560 { 8561 char *arg_path, *filename; 8562 FILE *input; 8563 save_arg_t sv; 8564 #if ENABLE_HUSH_FUNCTIONS 8565 smallint sv_flg; 8566 #endif 8567 8568 argv = skip_dash_dash(argv); 8569 filename = argv[0]; 8570 if (!filename) { 8571 /* bash says: "bash: .: filename argument required" */ 8572 return 2; /* bash compat */ 8573 } 8574 arg_path = NULL; 8575 if (!strchr(filename, '/')) { 8576 arg_path = find_in_path(filename); 8577 if (arg_path) 8578 filename = arg_path; 8579 } 8580 input = fopen_or_warn(filename, "r"); 8581 free(arg_path); 8582 if (!input) { 8583 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 8584 return EXIT_FAILURE; 8585 } 8586 close_on_exec_on(fileno(input)); 8587 8588 #if ENABLE_HUSH_FUNCTIONS 8589 sv_flg = G.flag_return_in_progress; 8590 /* "we are inside sourced file, ok to use return" */ 8591 G.flag_return_in_progress = -1; 8592 #endif 8593 save_and_replace_G_args(&sv, argv); 8594 8595 parse_and_run_file(input); 3826 8596 fclose(input); 3827 if (cwd != bb_msg_unknown) 3828 free((char*)cwd); 3829 cur_var = top_var->next; 3830 while (cur_var) { 3831 struct variable *tmp = cur_var; 3832 if (!cur_var->max_len) 3833 free(cur_var->varstr); 3834 cur_var = cur_var->next; 3835 free(tmp); 3836 } 3837 #endif 3838 hush_exit(opt ? opt : last_return_code); 3839 } 8597 8598 restore_G_args(&sv, argv); 8599 #if ENABLE_HUSH_FUNCTIONS 8600 G.flag_return_in_progress = sv_flg; 8601 #endif 8602 8603 return G.last_exitcode; 8604 } 8605 8606 static int FAST_FUNC builtin_umask(char **argv) 8607 { 8608 int rc; 8609 mode_t mask; 8610 8611 mask = umask(0); 8612 argv = skip_dash_dash(argv); 8613 if (argv[0]) { 8614 mode_t old_mask = mask; 8615 8616 mask ^= 0777; 8617 rc = bb_parse_mode(argv[0], &mask); 8618 mask ^= 0777; 8619 if (rc == 0) { 8620 mask = old_mask; 8621 /* bash messages: 8622 * bash: umask: 'q': invalid symbolic mode operator 8623 * bash: umask: 999: octal number out of range 8624 */ 8625 bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); 8626 } 8627 } else { 8628 rc = 1; 8629 /* Mimic bash */ 8630 printf("%04o\n", (unsigned) mask); 8631 /* fall through and restore mask which we set to 0 */ 8632 } 8633 umask(mask); 8634 8635 return !rc; /* rc != 0 - success */ 8636 } 8637 8638 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ 8639 static int FAST_FUNC builtin_unset(char **argv) 8640 { 8641 int ret; 8642 unsigned opts; 8643 8644 /* "!": do not abort on errors */ 8645 /* "+": stop at 1st non-option */ 8646 opts = getopt32(argv, "!+vf"); 8647 if (opts == (unsigned)-1) 8648 return EXIT_FAILURE; 8649 if (opts == 3) { 8650 bb_error_msg("unset: -v and -f are exclusive"); 8651 return EXIT_FAILURE; 8652 } 8653 argv += optind; 8654 8655 ret = EXIT_SUCCESS; 8656 while (*argv) { 8657 if (!(opts & 2)) { /* not -f */ 8658 if (unset_local_var(*argv)) { 8659 /* unset <nonexistent_var> doesn't fail. 8660 * Error is when one tries to unset RO var. 8661 * Message was printed by unset_local_var. */ 8662 ret = EXIT_FAILURE; 8663 } 8664 } 8665 #if ENABLE_HUSH_FUNCTIONS 8666 else { 8667 unset_func(*argv); 8668 } 8669 #endif 8670 argv++; 8671 } 8672 return ret; 8673 } 8674 8675 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ 8676 static int FAST_FUNC builtin_wait(char **argv) 8677 { 8678 int ret = EXIT_SUCCESS; 8679 int status, sig; 8680 8681 argv = skip_dash_dash(argv); 8682 if (argv[0] == NULL) { 8683 /* Don't care about wait results */ 8684 /* Note 1: must wait until there are no more children */ 8685 /* Note 2: must be interruptible */ 8686 /* Examples: 8687 * $ sleep 3 & sleep 6 & wait 8688 * [1] 30934 sleep 3 8689 * [2] 30935 sleep 6 8690 * [1] Done sleep 3 8691 * [2] Done sleep 6 8692 * $ sleep 3 & sleep 6 & wait 8693 * [1] 30936 sleep 3 8694 * [2] 30937 sleep 6 8695 * [1] Done sleep 3 8696 * ^C <-- after ~4 sec from keyboard 8697 * $ 8698 */ 8699 sigaddset(&G.blocked_set, SIGCHLD); 8700 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 8701 while (1) { 8702 checkjobs(NULL); 8703 if (errno == ECHILD) 8704 break; 8705 /* Wait for SIGCHLD or any other signal of interest */ 8706 /* sigtimedwait with infinite timeout: */ 8707 sig = sigwaitinfo(&G.blocked_set, NULL); 8708 if (sig > 0) { 8709 sig = check_and_run_traps(sig); 8710 if (sig && sig != SIGCHLD) { /* see note 2 */ 8711 ret = 128 + sig; 8712 break; 8713 } 8714 } 8715 } 8716 sigdelset(&G.blocked_set, SIGCHLD); 8717 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 8718 return ret; 8719 } 8720 8721 /* This is probably buggy wrt interruptible-ness */ 8722 while (*argv) { 8723 pid_t pid = bb_strtou(*argv, NULL, 10); 8724 if (errno) { 8725 /* mimic bash message */ 8726 bb_error_msg("wait: '%s': not a pid or valid job spec", *argv); 8727 return EXIT_FAILURE; 8728 } 8729 if (waitpid(pid, &status, 0) == pid) { 8730 if (WIFSIGNALED(status)) 8731 ret = 128 + WTERMSIG(status); 8732 else if (WIFEXITED(status)) 8733 ret = WEXITSTATUS(status); 8734 else /* wtf? */ 8735 ret = EXIT_FAILURE; 8736 } else { 8737 bb_perror_msg("wait %s", *argv); 8738 ret = 127; 8739 } 8740 argv++; 8741 } 8742 8743 return ret; 8744 } 8745 8746 #if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS 8747 static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min) 8748 { 8749 if (argv[1]) { 8750 def = bb_strtou(argv[1], NULL, 10); 8751 if (errno || def < def_min || argv[2]) { 8752 bb_error_msg("%s: bad arguments", argv[0]); 8753 def = UINT_MAX; 8754 } 8755 } 8756 return def; 8757 } 8758 #endif 8759 8760 #if ENABLE_HUSH_LOOPS 8761 static int FAST_FUNC builtin_break(char **argv) 8762 { 8763 unsigned depth; 8764 if (G.depth_of_loop == 0) { 8765 bb_error_msg("%s: only meaningful in a loop", argv[0]); 8766 return EXIT_SUCCESS; /* bash compat */ 8767 } 8768 G.flag_break_continue++; /* BC_BREAK = 1 */ 8769 8770 G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1); 8771 if (depth == UINT_MAX) 8772 G.flag_break_continue = BC_BREAK; 8773 if (G.depth_of_loop < depth) 8774 G.depth_break_continue = G.depth_of_loop; 8775 8776 return EXIT_SUCCESS; 8777 } 8778 8779 static int FAST_FUNC builtin_continue(char **argv) 8780 { 8781 G.flag_break_continue = 1; /* BC_CONTINUE = 2 = 1+1 */ 8782 return builtin_break(argv); 8783 } 8784 #endif 8785 8786 #if ENABLE_HUSH_FUNCTIONS 8787 static int FAST_FUNC builtin_return(char **argv) 8788 { 8789 int rc; 8790 8791 if (G.flag_return_in_progress != -1) { 8792 bb_error_msg("%s: not in a function or sourced script", argv[0]); 8793 return EXIT_FAILURE; /* bash compat */ 8794 } 8795 8796 G.flag_return_in_progress = 1; 8797 8798 /* bash: 8799 * out of range: wraps around at 256, does not error out 8800 * non-numeric param: 8801 * f() { false; return qwe; }; f; echo $? 8802 * bash: return: qwe: numeric argument required <== we do this 8803 * 255 <== we also do this 8804 */ 8805 rc = parse_numeric_argv1(argv, G.last_exitcode, 0); 8806 return rc; 8807 } 8808 #endif -
branches/2.2.9/mindi-busybox/shell/hush_test/hush-misc/syntax_err.right
r1765 r2725 1 1 shown 2 2 hush: syntax error: unterminated ' 3 test 4 not shown -
branches/2.2.9/mindi-busybox/shell/hush_test/hush-vars/var_subst_in_for.tests
r1765 r2725 1 1 if test $# = 0; then 2 exec "$THIS_SH" var_subst_in_for.testsabc "d e"2 exec "$THIS_SH" "$0" abc "d e" 3 3 fi 4 4 -
branches/2.2.9/mindi-busybox/shell/hush_test/hush-z_slow/leak_var.right
r1765 r2725 1 1 Measuring memory leak... 2 vsz does not grow 2 Ok -
branches/2.2.9/mindi-busybox/shell/hush_test/hush-z_slow/leak_var.tests
r1765 r2725 1 pid=$$2 3 # Warm up4 unset t5 t=1111111111111111111111111111111111111111111111111111111111111111111111116 export t7 unset t8 t=1111111111111111111111111111111111111111111111111111111111111111111111119 export t10 unset t11 t=11111111111111111111111111111111111111111111111111111111111111111111111112 export t13 unset t14 t=11111111111111111111111111111111111111111111111111111111111111111111111115 export t16 unset t17 t=11111111111111111111111111111111111111111111111111111111111111111111111118 export t19 i=120 if test $i = 1111111111111111111111111111111111111111111111; then i=2; fi21 beg=`ps -o pid,vsz | grep "^ *$pid "`22 23 1 echo "Measuring memory leak..." 24 beg=`ps -o pid,vsz | grep "^ *$pid "`25 2 i=1 26 3 while test $i != X; do … … 60 37 if test $i = 111111111111111111111111111111111111111111111i; then i=j; fi 61 38 if test $i = 111111111111111111111111111111111111111111111j; then i=X; fi 39 memleak 62 40 done 63 end=`ps -o pid,vsz | grep "^ *$pid "` 64 65 if test "$beg" != "$end"; then66 echo "vsz grows: $beg -> $end"41 memleak 42 kb=$? 43 if test $kb -le 4; then 44 echo Ok 67 45 else 68 echo " vsz does not grow"46 echo "Bad: $kb kb (or more) leaked" 69 47 fi -
branches/2.2.9/mindi-busybox/shell/hush_test/run-all
r1765 r2725 1 1 #!/bin/sh 2 2 3 test -x hush || { echo "No ./hush?!"; exit; } 3 unset LANG LANGUAGE 4 unset LC_COLLATE 5 unset LC_CTYPE 6 unset LC_MONETARY 7 unset LC_MESSAGES 8 unset LC_NUMERIC 9 unset LC_TIME 10 unset LC_ALL 4 11 5 PATH="$PWD:$PATH" # for hush and recho/zecho/printenv 12 if test ! -x hush; then 13 if test ! -x ../../busybox; then 14 echo "Can't run tests. Put hush binary into this directory (`pwd`)" 15 exit 1 16 fi 17 echo "No ./hush - creating a link to ../../busybox" 18 ln -s ../../busybox hush 19 fi 20 if test ! -f .config; then 21 if test ! -f ../../.config; then 22 echo "Missing .config file" 23 exit 1 24 fi 25 cp ../../.config . || exit 1 26 fi 27 28 eval $(sed -e '/^#/d' -e '/^$/d' -e 's:^:export :' .config) 29 30 PATH="`pwd`:$PATH" # for hush and recho/zecho/printenv 6 31 export PATH 7 32 8 THIS_SH=" $PWD/hush"33 THIS_SH="`pwd`/hush" 9 34 export THIS_SH 10 35 11 36 do_test() 12 37 { 13 test -d "$1" || return 0 14 ( 15 cd "$1" || { echo "cannot cd $1!"; exit 1; } 16 for x in run-*; do 17 test -f "$x" || continue 18 case "$x" in 19 "$0"|run-minimal|run-gprof) ;; 20 *.orig|*~) ;; 21 #*) echo $x ; sh $x ;; 22 *) 23 sh "$x" >"../$1-$x.fail" 2>&1 && \ 24 { echo "$1/$x: ok"; rm "../$1-$x.fail"; } || echo "$1/$x: fail"; 25 ;; 26 esac 27 done 28 # Many bash run-XXX scripts just do this, 29 # no point in duplication it all over the place 30 for x in *.tests; do 38 test -d "$1" || return 0 39 d=${d%/} 40 # echo Running tests in directory "$1" 41 ( 42 tret=0 43 cd "$1" || { echo "cannot cd $1!"; exit 1; } 44 for x in run-*; do 45 test -f "$x" || continue 46 case "$x" in 47 "$0"|run-minimal|run-gprof) ;; 48 *.orig|*~) ;; 49 #*) echo $x ; sh $x ;; 50 *) 51 sh "$x" >"../$1-$x.fail" 2>&1 && \ 52 { echo "$1/$x: ok"; rm "../$1-$x.fail"; } || echo "$1/$x: fail"; 53 ;; 54 esac 55 done 56 # Many bash run-XXX scripts just do this, 57 # no point in duplication it all over the place 58 for x in *.tests; do 31 59 test -x "$x" || continue 32 60 name="${x%%.tests}" 33 61 test -f "$name.right" || continue 34 { 35 "$THIS_SH" "./$x" >"$name.xx" 2>&1 36 diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" 37 } && echo "$1/$x: ok" || echo "$1/$x: fail" 38 done 39 ) 62 # echo Running test: "$x" 63 ( 64 "$THIS_SH" "./$x" >"$name.xx" 2>&1 65 # filter C library differences 66 sed -i \ 67 -e "/: invalid option /s:'::g" \ 68 "$name.xx" 69 test $? -eq 77 && rm -f "../$1-$x.fail" && exit 77 70 diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" 71 ) 72 case $? in 73 0) echo "$1/$x: ok";; 74 77) echo "$1/$x: skip (feature disabled)";; 75 *) echo "$1/$x: fail"; tret=1;; 76 esac 77 done 78 exit ${tret} 79 ) 40 80 } 41 81 … … 43 83 # Usage: run-all [directories] 44 84 85 ret=0 86 45 87 if [ $# -lt 1 ]; then 46 47 88 # All sub directories 89 modules=`ls -d hush-*` 48 90 49 50 do_test $module 51 91 for module in $modules; do 92 do_test $module || ret=1 93 done 52 94 else 53 95 while [ $# -ge 1 ]; do 54 96 if [ -d $1 ]; then 55 do_test $197 do_test $1 || ret=1 56 98 fi 57 99 shift 58 100 done 59 101 fi 102 103 exit ${ret}
Note:
See TracChangeset
for help on using the changeset viewer.