Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/shell
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- Location:
- branches/stable/mindi-busybox/shell
- Files:
-
- 4 deleted
- 5 edited
- 8 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/shell/Config.in
r821 r1770 8 8 choice 9 9 prompt "Choose your default shell" 10 default CONFIG_FEATURE_SH_IS_NONE10 default FEATURE_SH_IS_NONE 11 11 help 12 12 Choose a shell. The ash shell is the most bash compatible 13 13 and full featured one. 14 14 15 config CONFIG_FEATURE_SH_IS_ASH16 select CONFIG_ASH15 config FEATURE_SH_IS_ASH 16 select ASH 17 17 bool "ash" 18 18 19 config CONFIG_FEATURE_SH_IS_HUSH20 select CONFIG_HUSH19 config FEATURE_SH_IS_HUSH 20 select HUSH 21 21 bool "hush" 22 22 23 config CONFIG_FEATURE_SH_IS_LASH24 select CONFIG_LASH23 config FEATURE_SH_IS_LASH 24 select LASH 25 25 bool "lash" 26 26 27 config CONFIG_FEATURE_SH_IS_MSH28 select CONFIG_MSH27 config FEATURE_SH_IS_MSH 28 select MSH 29 29 bool "msh" 30 30 31 config CONFIG_FEATURE_SH_IS_NONE31 config FEATURE_SH_IS_NONE 32 32 bool "none" 33 33 34 34 endchoice 35 35 36 config CONFIG_ASH36 config ASH 37 37 bool "ash" 38 38 default n 39 select CONFIG_TEST39 select TEST 40 40 help 41 41 Tha 'ash' shell adds about 60k in the default configuration and is … … 46 46 47 47 comment "Ash Shell Options" 48 depends on CONFIG_ASH49 50 config CONFIG_ASH_JOB_CONTROL48 depends on ASH 49 50 config ASH_JOB_CONTROL 51 51 bool "Job control" 52 52 default y 53 depends on CONFIG_ASH53 depends on ASH 54 54 help 55 55 Enable job control in the ash shell. 56 56 57 config CONFIG_ASH_READ_NCHARS57 config ASH_READ_NCHARS 58 58 bool "'read -n N' and 'read -s' support" 59 59 default n 60 depends on CONFIG_ASH60 depends on ASH 61 61 help 62 62 'read -n N' will return a value after N characters have been read. 63 63 'read -s' will read without echoing the user's input. 64 64 65 config CONFIG_ASH_READ_TIMEOUT65 config ASH_READ_TIMEOUT 66 66 bool "'read -t S' support." 67 67 default n 68 depends on CONFIG_ASH68 depends on ASH 69 69 help 70 70 'read -t S' will return a value after S seconds have passed. … … 72 72 as a decimal fraction, e.g. 'read -t 2.5 foo'. 73 73 74 config CONFIG_ASH_ALIAS74 config ASH_ALIAS 75 75 bool "alias support" 76 76 default y 77 depends on CONFIG_ASH77 depends on ASH 78 78 help 79 79 Enable alias support in the ash shell. 80 80 81 config CONFIG_ASH_MATH_SUPPORT81 config ASH_MATH_SUPPORT 82 82 bool "Posix math support" 83 83 default y 84 depends on CONFIG_ASH84 depends on ASH 85 85 help 86 86 Enable math support in the ash shell. 87 87 88 config CONFIG_ASH_MATH_SUPPORT_6488 config ASH_MATH_SUPPORT_64 89 89 bool "Extend Posix math support to 64 bit" 90 90 default n 91 depends on CONFIG_ASH_MATH_SUPPORT91 depends on ASH_MATH_SUPPORT 92 92 help 93 93 Enable 64-bit math support in the ash shell. This will make … … 95 95 large numbers. 96 96 97 config CONFIG_ASH_GETOPTS97 config ASH_GETOPTS 98 98 bool "Builtin getopt to parse positional parameters" 99 99 default n 100 depends on CONFIG_ASH100 depends on ASH 101 101 help 102 102 Enable getopts builtin in the ash shell. 103 103 104 config CONFIG_ASH_BUILTIN_ECHO104 config ASH_BUILTIN_ECHO 105 105 bool "Builtin version of 'echo'" 106 106 default y 107 select CONFIG_ECHO108 depends on CONFIG_ASH109 help 110 Enable support for echo, built 111 112 config CONFIG_ASH_BUILTIN_TEST107 select ECHO 108 depends on ASH 109 help 110 Enable support for echo, builtin to ash. 111 112 config ASH_BUILTIN_TEST 113 113 bool "Builtin version of 'test'" 114 114 default y 115 select CONFIG_TEST116 depends on CONFIG_ASH117 help 118 Enable support for test, built 119 120 config CONFIG_ASH_CMDCMD115 select TEST 116 depends on ASH 117 help 118 Enable support for test, builtin to ash. 119 120 config ASH_CMDCMD 121 121 bool "'command' command to override shell builtins" 122 122 default n 123 depends on CONFIG_ASH123 depends on ASH 124 124 help 125 125 Enable support for the ash 'command' builtin, which allows … … 127 127 even when there is an ash builtin command with the same name. 128 128 129 config CONFIG_ASH_MAIL129 config ASH_MAIL 130 130 bool "Check for new mail on interactive shells" 131 131 default y 132 depends on CONFIG_ASH132 depends on ASH 133 133 help 134 134 Enable "check for new mail" in the ash shell. 135 135 136 config CONFIG_ASH_OPTIMIZE_FOR_SIZE136 config ASH_OPTIMIZE_FOR_SIZE 137 137 bool "Optimize for size instead of speed" 138 138 default y 139 depends on CONFIG_ASH139 depends on ASH 140 140 help 141 141 Compile ash for reduced size at the price of speed. 142 142 143 config CONFIG_ASH_RANDOM_SUPPORT143 config ASH_RANDOM_SUPPORT 144 144 bool "Pseudorandom generator and variable $RANDOM" 145 145 default n 146 depends on CONFIG_ASH146 depends on ASH 147 147 help 148 148 Enable pseudorandom generator and dynamic variable "$RANDOM". … … 152 152 variable will no longer have special treatment. 153 153 154 config CONFIG_ASH_EXPAND_PRMT154 config ASH_EXPAND_PRMT 155 155 bool "Expand prompt string" 156 156 default n 157 depends on CONFIG_ASH157 depends on ASH 158 158 help 159 159 "PS#" may be contain volatile content, such as backquote commands. … … 161 161 variable each time it is displayed. 162 162 163 config CONFIG_HUSH163 config HUSH 164 164 bool "hush" 165 165 default n 166 select CONFIG_TRUE167 select CONFIG_FALSE168 select CONFIG_TEST166 select TRUE 167 select FALSE 168 select TEST 169 169 help 170 170 hush is a very small shell (just 18k) and it has fairly complete … … 177 177 expansion, &> and >& redirection of stdout+stderr, etc. 178 178 179 180 config CONFIG_LASH 179 config HUSH_HELP 180 bool "help builtin" 181 default n 182 depends on HUSH 183 help 184 Enable help builtin in hush. Code size + ~1 kbyte. 185 186 config HUSH_INTERACTIVE 187 bool "Interactive mode" 188 default y 189 depends on HUSH 190 help 191 Enable interactive mode (prompt and command editing). 192 Without this, hush simply reads and executes commands 193 from stdin just like a shell script from the file. 194 No prompt, no PS1/PS2 magic shell variables. 195 196 config HUSH_JOB 197 bool "Job control" 198 default n 199 depends on HUSH_INTERACTIVE 200 help 201 Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current 202 command (not entire shell), fg/bg builtins work. Without this option, 203 "cmd &" still works by simply spawning a process and immediately 204 prompting for next command (or executing next command in a script), 205 but no separate process group is formed. 206 207 config HUSH_TICK 208 bool "Process substitution" 209 default n 210 depends on HUSH 211 help 212 Enable process substitution `command` and $(command) in hush. 213 214 config HUSH_IF 215 bool "Support if/then/elif/else/fi" 216 default n 217 depends on HUSH 218 help 219 Enable if/then/elif/else/fi in hush. 220 221 config HUSH_LOOPS 222 bool "Support for, while and until loops" 223 default n 224 depends on HUSH 225 help 226 Enable for, while and until loops in hush. 227 228 config LASH 181 229 bool "lash" 182 230 default n 183 select CONFIG_TRUE184 select CONFIG_FALSE185 select CONFIG_TEST231 select TRUE 232 select FALSE 233 select TEST 186 234 help 187 235 lash is the very smallest shell (adds just 10k) and it is quite … … 193 241 194 242 195 config CONFIG_MSH243 config MSH 196 244 bool "msh" 197 245 default n 198 select CONFIG_TRUE199 select CONFIG_FALSE200 select CONFIG_TEST246 select TRUE 247 select FALSE 248 select TEST 201 249 help 202 250 The minix shell (adds just 30k) is quite complete and handles things … … 208 256 209 257 comment "Bourne Shell Options" 210 depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH211 212 config CONFIG_FEATURE_SH_EXTRA_QUIET258 depends on MSH || LASH || HUSH || ASH 259 260 config FEATURE_SH_EXTRA_QUIET 213 261 bool "Hide message on interactive shell startup" 214 262 default n 215 depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH263 depends on MSH || LASH || HUSH || ASH 216 264 help 217 265 Remove the busybox introduction when starting a shell. 218 266 219 config CONFIG_FEATURE_SH_STANDALONE_SHELL267 config FEATURE_SH_STANDALONE 220 268 bool "Standalone shell" 221 269 default n 222 depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH223 help 224 This option causes the selected busybox shellto use busybox applets270 depends on (MSH || LASH || HUSH || ASH) && FEATURE_PREFER_APPLETS 271 help 272 This option causes busybox shells to use busybox applets 225 273 in preference to executables in the PATH whenever possible. For 226 274 example, entering the command 'ifconfig' into the shell would cause … … 231 279 for use as a rescue shell, in the event that you screw up your system. 232 280 233 Note that this will *also* cause applets to take precedence 234 over shell builtins of the same name. So turning this on will 235 eliminate any performance gained by turning on the builtin "echo" 236 and "test" commands in ash. 237 238 Note that when using this option, the shell will attempt to directly 239 run '/bin/busybox'. If you do not have the busybox binary sitting in 240 that exact location with that exact name, this option will not work at 241 all. 242 243 config CONFIG_FEATURE_COMMAND_EDITING 244 bool "Command line editing" 245 default n 246 depends on CONFIG_MSH || CONFIG_LASH || CONFIG_HUSH || CONFIG_ASH 247 help 248 Enable command editing in shell. 249 250 config CONFIG_FEATURE_COMMAND_EDITING_VI 251 bool "vi-style line editing commands" 252 default n 253 depends on CONFIG_FEATURE_COMMAND_EDITING 254 help 255 Enable vi-style line editing in the shell. This mode can be 256 turned on and off with "set -o vi" and "set +o vi". 257 258 config CONFIG_FEATURE_COMMAND_HISTORY 259 int "History size" 260 default 15 261 depends on CONFIG_FEATURE_COMMAND_EDITING 262 help 263 Specify command history size in shell. 264 265 config CONFIG_FEATURE_COMMAND_SAVEHISTORY 266 bool "History saving" 267 default n 268 depends on CONFIG_ASH && CONFIG_FEATURE_COMMAND_EDITING 269 help 270 Enable history saving in ash shell. 271 272 config CONFIG_FEATURE_COMMAND_TAB_COMPLETION 273 bool "Tab completion" 274 default n 275 depends on CONFIG_FEATURE_COMMAND_EDITING 276 help 277 Enable tab completion in shell. 278 279 config CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION 280 bool "Username completion" 281 default n 282 depends on CONFIG_FEATURE_COMMAND_TAB_COMPLETION 283 help 284 Enable username completion in shell. 285 286 config CONFIG_FEATURE_SH_FANCY_PROMPT 287 bool "Fancy shell prompts" 288 default n 289 depends on CONFIG_FEATURE_COMMAND_EDITING 290 help 291 Setting this option allows for prompts to use things like \w and 292 \$ and also using escape codes. 281 This is implemented by re-execing /proc/self/exe (typically) 282 with right parameters. Some selected applets ("NOFORK" applets) 283 can even be executed without creating new process. 284 Instead, busybox will call <applet>_main() internally. 285 286 However, this causes problems in chroot jails without mounted /proc 287 and with ps/top (command name can be shown as 'exe' for applets 288 started this way). 289 # untrue? 290 # Note that this will *also* cause applets to take precedence 291 # over shell builtins of the same name. So turning this on will 292 # eliminate any performance gained by turning on the builtin "echo" 293 # and "test" commands in ash. 294 # untrue? 295 # Note that when using this option, the shell will attempt to directly 296 # run '/bin/busybox'. If you do not have the busybox binary sitting in 297 # that exact location with that exact name, this option will not work at 298 # all. 299 300 config CTTYHACK 301 bool "cttyhack" 302 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 293 319 294 320 endmenu -
branches/stable/mindi-busybox/shell/ash.c
r821 r1770 32 32 */ 33 33 34 35 34 /* 36 35 * The follow should be set to reflect the type of system you have: … … 43 42 * a quit signal will generate a core dump. 44 43 */ 45 46 44 #define DEBUG 0 47 45 #define IFS_BROKEN 48 49 46 #define PROFILE 0 50 51 #include "busybox.h" 52 53 #ifdef DEBUG 47 #if ENABLE_ASH_JOB_CONTROL 48 #define JOBS 1 49 #else 50 #define JOBS 0 51 #endif 52 53 #if DEBUG 54 54 #define _GNU_SOURCE 55 55 #endif 56 57 #include <sys/types.h> 58 #include <sys/ioctl.h> 59 #include <sys/param.h> 60 #include <sys/resource.h> 61 #include <sys/stat.h> 62 #include <sys/wait.h> 63 64 #include <stdio.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <unistd.h> 68 69 #include <stdarg.h> 70 #include <stddef.h> 71 #include <assert.h> 72 #include <ctype.h> 73 #include <dirent.h> 74 #include <errno.h> 75 #include <fcntl.h> 76 #include <limits.h> 56 #include "busybox.h" /* for struct bb_applet */ 77 57 #include <paths.h> 78 58 #include <setjmp.h> 79 #include <signal.h>80 /*#include <stdint.h>*/81 #include <time.h>82 59 #include <fnmatch.h> 83 84 #include "pwd_.h" 85 86 #ifdef CONFIG_ASH_JOB_CONTROL 87 #define JOBS 1 88 #else 89 #undef JOBS 90 #endif 91 92 #if JOBS || defined(CONFIG_ASH_READ_NCHARS) 60 #if JOBS || ENABLE_ASH_READ_NCHARS 93 61 #include <termios.h> 94 62 #endif 95 96 #include "cmdedit.h" 97 98 #ifdef __GLIBC__ 99 /* glibc sucks */ 100 static int *dash_errno; 101 #undef errno 102 #define errno (*dash_errno) 103 #endif 63 extern char **environ; 104 64 105 65 #if defined(__uClinux__) … … 107 67 #endif 108 68 109 #ifdef DEBUG 110 #define _DIAGASSERT(assert_expr) assert(assert_expr) 111 #else 112 #define _DIAGASSERT(assert_expr) 113 #endif 114 115 116 #ifdef CONFIG_ASH_ALIAS 117 /* alias.h */ 118 119 #define ALIASINUSE 1 120 #define ALIASDEAD 2 121 122 struct alias { 123 struct alias *next; 124 char *name; 125 char *val; 126 int flag; 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)) 76 77 78 /* ============ Shell options */ 79 80 static const char *const optletters_optnames[] = { 81 "e" "errexit", 82 "f" "noglob", 83 "I" "ignoreeof", 84 "i" "interactive", 85 "m" "monitor", 86 "n" "noexec", 87 "s" "stdin", 88 "x" "xtrace", 89 "v" "verbose", 90 "C" "noclobber", 91 "a" "allexport", 92 "b" "notify", 93 "u" "nounset", 94 "\0" "vi" 95 #if DEBUG 96 ,"\0" "nolog" 97 ,"\0" "debug" 98 #endif 127 99 }; 128 100 129 static struct alias *lookupalias(const char *, int); 130 static int aliascmd(int, char **); 131 static int unaliascmd(int, char **); 132 static void rmaliases(void); 133 static int unalias(const char *); 134 static void printalias(const struct alias *); 135 #endif 136 137 /* cd.h */ 138 139 140 static void setpwd(const char *, int); 141 142 /* error.h */ 143 144 145 /* 146 * Types of operations (passed to the errmsg routine). 147 */ 148 149 150 static const char not_found_msg[] = "%s: not found"; 151 152 153 #define E_OPEN "No such file" /* opening a file */ 154 #define E_CREAT "Directory nonexistent" /* creating a file */ 155 #define E_EXEC not_found_msg+4 /* executing a program */ 101 #define optletters(n) optletters_optnames[(n)][0] 102 #define optnames(n) (&optletters_optnames[(n)][1]) 103 104 enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; 105 106 static char optlist[NOPTS] ALIGN1; 107 108 #define eflag optlist[0] 109 #define fflag optlist[1] 110 #define Iflag optlist[2] 111 #define iflag optlist[3] 112 #define mflag optlist[4] 113 #define nflag optlist[5] 114 #define sflag optlist[6] 115 #define xflag optlist[7] 116 #define vflag optlist[8] 117 #define Cflag optlist[9] 118 #define aflag optlist[10] 119 #define bflag optlist[11] 120 #define uflag optlist[12] 121 #define viflag optlist[13] 122 #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 */ 150 151 152 /* ============ Interrupts / exceptions */ 156 153 157 154 /* … … 164 161 * inner scope, and restore handler on exit from the scope. 165 162 */ 166 167 163 struct jmploc { 168 164 jmp_buf loc; 169 165 }; 170 171 static struct jmploc *handler; 166 static struct jmploc *exception_handler; 172 167 static int exception; 173 static volatile int suppressint;174 static volatile sig_atomic_t intpending;175 176 168 /* exceptions */ 177 169 #define EXINT 0 /* SIGINT received */ … … 181 173 #define EXEXIT 4 /* exit the shell */ 182 174 #define EXSIG 5 /* trapped signal in wait(1) */ 183 184 175 static volatile int suppressint; 176 static volatile sig_atomic_t intpending; 185 177 /* do we generate EXSIG events */ 186 178 static int exsig; 187 179 /* last pending signal */ 188 static volatile sig_atomic_t pendingsigs; 180 static volatile sig_atomic_t pendingsig; 181 182 /* 183 * Sigmode records the current value of the signal handlers for the various 184 * 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 */ 189 193 190 194 /* … … 194 198 * more fun than worrying about efficiency and portability. :-)) 195 199 */ 196 197 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); }) 198 #define INTOFF \ 199 ({ \ 200 #define INT_OFF \ 201 do { \ 200 202 suppressint++; \ 201 203 xbarrier(); \ 202 0; \ 203 }) 204 #define SAVEINT(v) ((v) = suppressint) 205 #define RESTOREINT(v) \ 206 ({ \ 204 } while (0) 205 206 /* 207 * Called to raise an exception. Since C doesn't include exceptions, we 208 * 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; 212 static void 213 raise_exception(int e) 214 { 215 #if DEBUG 216 if (exception_handler == NULL) 217 abort(); 218 #endif 219 INT_OFF; 220 exception = e; 221 longjmp(exception_handler->loc, 1); 222 } 223 224 /* 225 * Called from trap.c when a SIGINT is received. (If the user specifies 226 * that SIGINT is to be trapped or ignored using the trap builtin, then 227 * this routine is not called.) Suppressint is nonzero when interrupts 228 * are held using the INT_OFF macro. (The test for iflag is just 229 * defensive programming.) 230 */ 231 static void raise_interrupt(void) ATTRIBUTE_NORETURN; 232 static void 233 raise_interrupt(void) 234 { 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; 246 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 247 if (!(rootshell && iflag)) { 248 signal(SIGINT, SIG_DFL); 249 raise(SIGINT); 250 } 251 i = EXINT; 252 } 253 raise_exception(i); 254 /* NOTREACHED */ 255 } 256 257 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 258 static void 259 int_on(void) 260 { 261 if (--suppressint == 0 && intpending) { 262 raise_interrupt(); 263 } 264 } 265 #define INT_ON int_on() 266 static void 267 force_int_on(void) 268 { 269 suppressint = 0; 270 if (intpending) 271 raise_interrupt(); 272 } 273 #define FORCE_INT_ON force_int_on() 274 #else 275 #define INT_ON \ 276 do { \ 207 277 xbarrier(); \ 208 if ((suppressint = (v)) == 0 && intpending) onint(); \ 209 0; \ 210 }) 211 #define EXSIGON() \ 212 ({ \ 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 { \ 213 302 exsig++; \ 214 303 xbarrier(); \ 215 if (pendingsigs) \ 216 exraise(EXSIG); \ 217 0; \ 218 }) 304 if (pendingsig) \ 305 raise_exception(EXSIG); \ 306 } while (0) 219 307 /* EXSIG is turned off by evalbltin(). */ 220 308 221 222 static void exraise(int) ATTRIBUTE_NORETURN; 223 static void onint(void) ATTRIBUTE_NORETURN; 224 225 static void sh_error(const char *, ...) ATTRIBUTE_NORETURN; 226 static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN; 227 228 static void sh_warnx(const char *, ...); 229 230 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 231 static void 232 inton(void) { 233 if (--suppressint == 0 && intpending) { 234 onint(); 235 } 236 } 237 #define INTON inton() 238 static void forceinton(void) 239 { 240 suppressint = 0; 241 if (intpending) 242 onint(); 243 } 244 #define FORCEINTON forceinton() 245 #else 246 #define INTON \ 247 ({ \ 248 xbarrier(); \ 249 if (--suppressint == 0 && intpending) onint(); \ 250 0; \ 251 }) 252 #define FORCEINTON \ 253 ({ \ 254 xbarrier(); \ 255 suppressint = 0; \ 256 if (intpending) onint(); \ 257 0; \ 258 }) 259 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */ 260 261 /* expand.h */ 262 263 struct strlist { 264 struct strlist *next; 265 char *text; 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 } 338 339 340 /* ============ Stdout/stderr output */ 341 342 static void 343 outstr(const char *p, FILE *file) 344 { 345 INT_OFF; 346 fputs(p, file); 347 INT_ON; 348 } 349 350 static void 351 flush_stdout_stderr(void) 352 { 353 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); 364 INT_ON; 365 } 366 367 static void 368 outcslow(int c, FILE *dest) 369 { 370 INT_OFF; 371 putc(c, dest); 372 fflush(dest); 373 INT_ON; 374 } 375 376 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2))); 377 static int 378 out1fmt(const char *fmt, ...) 379 { 380 va_list ap; 381 int r; 382 383 INT_OFF; 384 va_start(ap, fmt); 385 r = vprintf(fmt, ap); 386 va_end(ap); 387 INT_ON; 388 return r; 389 } 390 391 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4))); 392 static int 393 fmtstr(char *outbuf, size_t length, const char *fmt, ...) 394 { 395 va_list ap; 396 int ret; 397 398 va_start(ap, fmt); 399 INT_OFF; 400 ret = vsnprintf(outbuf, length, fmt, ap); 401 va_end(ap); 402 INT_ON; 403 return ret; 404 } 405 406 static void 407 out1str(const char *p) 408 { 409 outstr(p, stdout); 410 } 411 412 static void 413 out2str(const char *p) 414 { 415 outstr(p, stderr); 416 flush_stderr(); 417 } 418 419 420 /* ============ Parser structures */ 421 422 /* 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' 427 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 428 /* CTLBACKQ | CTLQUOTE == '\205' */ 429 #define CTLARI '\206' /* arithmetic expression */ 430 #define CTLENDARI '\207' 431 #define CTLQUOTEMARK '\210' 432 433 /* variable substitution byte (follows CTLVAR) */ 434 #define VSTYPE 0x0f /* type of variable substitution */ 435 #define VSNUL 0x10 /* colon--treat the empty string as unset */ 436 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ 437 438 /* 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} */ 449 450 static const char dolatstr[] ALIGN1 = { 451 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 266 452 }; 267 268 269 struct arglist {270 struct strlist *list;271 struct strlist **lastp;272 };273 274 /*275 * expandarg() flags276 */277 #define EXP_FULL 0x1 /* perform word splitting & file globbing */278 #define EXP_TILDE 0x2 /* do normal tilde expansion */279 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */280 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */281 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */282 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */283 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */284 #define EXP_WORD 0x80 /* expand word in parameter expansion */285 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */286 287 288 union node;289 static void expandarg(union node *, struct arglist *, int);290 #define rmescapes(p) _rmescapes((p), 0)291 static char *_rmescapes(char *, int);292 static int casematch(union node *, char *);293 294 #ifdef CONFIG_ASH_MATH_SUPPORT295 static void expari(int);296 #endif297 298 /* eval.h */299 300 static char *commandname; /* currently executing command */301 static struct strlist *cmdenviron; /* environment for builtin command */302 static int exitstatus; /* exit status of last command */303 static int back_exitstatus; /* exit status of backquoted command */304 305 306 struct backcmd { /* result of evalbackcmd */307 int fd; /* file descriptor to read from */308 char *buf; /* buffer */309 int nleft; /* number of chars in buffer */310 struct job *jp; /* job structure for command */311 };312 313 /*314 * This file was generated by the mknodes program.315 */316 453 317 454 #define NCMD 0 … … 342 479 #define NNOT 25 343 480 344 481 union node; 345 482 346 483 struct ncmd { 347 348 349 350 484 int type; 485 union node *assign; 486 union node *args; 487 union node *redirect; 351 488 }; 352 489 353 354 490 struct npipe { 355 356 357 491 int type; 492 int backgnd; 493 struct nodelist *cmdlist; 358 494 }; 359 495 360 361 496 struct nredir { 362 363 364 497 int type; 498 union node *n; 499 union node *redirect; 365 500 }; 366 501 367 368 502 struct nbinary { 369 370 371 503 int type; 504 union node *ch1; 505 union node *ch2; 372 506 }; 373 507 374 375 508 struct nif { 376 377 378 379 509 int type; 510 union node *test; 511 union node *ifpart; 512 union node *elsepart; 380 513 }; 381 514 382 383 515 struct nfor { 384 385 386 387 516 int type; 517 union node *args; 518 union node *body; 519 char *var; 388 520 }; 389 521 390 391 522 struct ncase { 392 393 394 523 int type; 524 union node *expr; 525 union node *cases; 395 526 }; 396 527 397 398 528 struct nclist { 399 400 401 402 529 int type; 530 union node *next; 531 union node *pattern; 532 union node *body; 403 533 }; 404 534 405 406 535 struct narg { 407 408 409 410 536 int type; 537 union node *next; 538 char *text; 539 struct nodelist *backquote; 411 540 }; 412 541 413 414 542 struct nfile { 415 416 417 418 419 543 int type; 544 union node *next; 545 int fd; 546 union node *fname; 547 char *expfname; 420 548 }; 421 549 422 423 550 struct ndup { 424 425 426 427 428 551 int type; 552 union node *next; 553 int fd; 554 int dupfd; 555 union node *vname; 429 556 }; 430 557 431 432 558 struct nhere { 433 434 435 436 559 int type; 560 union node *next; 561 int fd; 562 union node *doc; 437 563 }; 438 564 439 440 565 struct nnot { 441 442 566 int type; 567 union node *com; 443 568 }; 444 569 445 446 570 union node { 447 448 449 450 451 452 453 454 455 456 457 458 459 460 571 int type; 572 struct ncmd ncmd; 573 struct npipe npipe; 574 struct nredir nredir; 575 struct nbinary nbinary; 576 struct nif nif; 577 struct nfor nfor; 578 struct ncase ncase; 579 struct nclist nclist; 580 struct narg narg; 581 struct nfile nfile; 582 struct ndup ndup; 583 struct nhere nhere; 584 struct nnot nnot; 461 585 }; 462 463 586 464 587 struct nodelist { … … 467 590 }; 468 591 469 470 592 struct funcnode { 471 593 int count; … … 473 595 }; 474 596 475 476 static void freefunc(struct funcnode *); 477 /* parser.h */ 478 479 /* control characters in argument strings */ 480 #define CTL_FIRST '\201' /* first 'special' character */ 481 #define CTLESC '\201' /* escape next character */ 482 #define CTLVAR '\202' /* variable defn */ 483 #define CTLENDVAR '\203' 484 #define CTLBACKQ '\204' 485 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 486 /* CTLBACKQ | CTLQUOTE == '\205' */ 487 #define CTLARI '\206' /* arithmetic expression */ 488 #define CTLENDARI '\207' 489 #define CTLQUOTEMARK '\210' 490 #define CTL_LAST '\210' /* last 'special' character */ 491 492 /* variable substitution byte (follows CTLVAR) */ 493 #define VSTYPE 0x0f /* type of variable substitution */ 494 #define VSNUL 0x10 /* colon--treat the empty string as unset */ 495 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ 496 497 /* values of VSTYPE field */ 498 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 499 #define VSMINUS 0x2 /* ${var-text} */ 500 #define VSPLUS 0x3 /* ${var+text} */ 501 #define VSQUESTION 0x4 /* ${var?message} */ 502 #define VSASSIGN 0x5 /* ${var=text} */ 503 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 504 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 505 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 506 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 507 #define VSLENGTH 0xa /* ${#var} */ 508 509 /* values of checkkwd variable */ 510 #define CHKALIAS 0x1 511 #define CHKKWD 0x2 512 #define CHKNL 0x4 513 514 #define IBUFSIZ (BUFSIZ + 1) 515 516 /* 517 * NEOF is returned by parsecmd when it encounters an end of file. It 518 * must be distinct from NULL, so we use the address of a variable that 519 * happens to be handy. 520 */ 521 static int plinno = 1; /* input line number */ 522 523 /* number of characters left in input buffer */ 524 static int parsenleft; /* copy of parsefile->nleft */ 525 static int parselleft; /* copy of parsefile->lleft */ 526 527 /* next character in input buffer */ 528 static char *parsenextc; /* copy of parsefile->nextc */ 597 /* 598 * Free a parse tree. 599 */ 600 static void 601 freefunc(struct funcnode *f) 602 { 603 if (f && --f->count < 0) 604 free(f); 605 } 606 607 608 /* ============ Debugging output */ 609 610 #if DEBUG 611 612 static FILE *tracefile; 613 614 static void 615 trace_printf(const char *fmt, ...) 616 { 617 va_list va; 618 619 if (debug != 1) 620 return; 621 va_start(va, fmt); 622 vfprintf(tracefile, fmt, va); 623 va_end(va); 624 } 625 626 static void 627 trace_vprintf(const char *fmt, va_list va) 628 { 629 if (debug != 1) 630 return; 631 vfprintf(tracefile, fmt, va); 632 } 633 634 static void 635 trace_puts(const char *s) 636 { 637 if (debug != 1) 638 return; 639 fputs(s, tracefile); 640 } 641 642 static void 643 trace_puts_quoted(char *s) 644 { 645 char *p; 646 char c; 647 648 if (debug != 1) 649 return; 650 putc('"', tracefile); 651 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: c = 'V'; goto backslash; 661 case CTLBACKQ: c = 'q'; goto backslash; 662 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 663 backslash: 664 putc('\\', tracefile); 665 putc(c, tracefile); 666 break; 667 default: 668 if (*p >= ' ' && *p <= '~') 669 putc(*p, tracefile); 670 else { 671 putc('\\', tracefile); 672 putc(*p >> 6 & 03, tracefile); 673 putc(*p >> 3 & 07, tracefile); 674 putc(*p & 07, tracefile); 675 } 676 break; 677 } 678 } 679 putc('"', tracefile); 680 } 681 682 static void 683 trace_puts_args(char **ap) 684 { 685 if (debug != 1) 686 return; 687 if (!*ap) 688 return; 689 while (1) { 690 trace_puts_quoted(*ap); 691 if (!*++ap) { 692 putc('\n', tracefile); 693 break; 694 } 695 putc(' ', tracefile); 696 } 697 } 698 699 static void 700 opentrace(void) 701 { 702 char s[100]; 703 #ifdef O_APPEND 704 int flags; 705 #endif 706 707 if (debug != 1) { 708 if (tracefile) 709 fflush(tracefile); 710 /* leave open because libedit might be using it */ 711 return; 712 } 713 strcpy(s, "./trace"); 714 if (tracefile) { 715 if (!freopen(s, "a", tracefile)) { 716 fprintf(stderr, "Can't re-open %s\n", s); 717 debug = 0; 718 return; 719 } 720 } else { 721 tracefile = fopen(s, "a"); 722 if (tracefile == NULL) { 723 fprintf(stderr, "Can't open %s\n", s); 724 debug = 0; 725 return; 726 } 727 } 728 #ifdef O_APPEND 729 flags = fcntl(fileno(tracefile), F_GETFL); 730 if (flags >= 0) 731 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 732 #endif 733 setlinebuf(tracefile); 734 fputs("\nTracing started.\n", tracefile); 735 } 736 737 static void 738 indent(int amount, char *pfx, FILE *fp) 739 { 740 int i; 741 742 for (i = 0; i < amount; i++) { 743 if (pfx && i == amount - 1) 744 fputs(pfx, fp); 745 putc('\t', fp); 746 } 747 } 748 749 /* little circular references here... */ 750 static void shtree(union node *n, int ind, char *pfx, FILE *fp); 751 752 static void 753 sharg(union node *arg, FILE *fp) 754 { 755 char *p; 756 struct nodelist *bqlist; 757 int subtype; 758 759 if (arg->type != NARG) { 760 out1fmt("<node type %d>\n", arg->type); 761 abort(); 762 } 763 bqlist = arg->narg.backquote; 764 for (p = arg->narg.text; *p; p++) { 765 switch (*p) { 766 case CTLESC: 767 putc(*++p, fp); 768 break; 769 case CTLVAR: 770 putc('$', fp); 771 putc('{', fp); 772 subtype = *++p; 773 if (subtype == VSLENGTH) 774 putc('#', fp); 775 776 while (*p != '=') 777 putc(*p++, fp); 778 779 if (subtype & VSNUL) 780 putc(':', fp); 781 782 switch (subtype & VSTYPE) { 783 case VSNORMAL: 784 putc('}', fp); 785 break; 786 case VSMINUS: 787 putc('-', fp); 788 break; 789 case VSPLUS: 790 putc('+', fp); 791 break; 792 case VSQUESTION: 793 putc('?', fp); 794 break; 795 case VSASSIGN: 796 putc('=', fp); 797 break; 798 case VSTRIMLEFT: 799 putc('#', fp); 800 break; 801 case VSTRIMLEFTMAX: 802 putc('#', fp); 803 putc('#', fp); 804 break; 805 case VSTRIMRIGHT: 806 putc('%', fp); 807 break; 808 case VSTRIMRIGHTMAX: 809 putc('%', fp); 810 putc('%', fp); 811 break; 812 case VSLENGTH: 813 break; 814 default: 815 out1fmt("<subtype %d>", subtype); 816 } 817 break; 818 case CTLENDVAR: 819 putc('}', fp); 820 break; 821 case CTLBACKQ: 822 case CTLBACKQ|CTLQUOTE: 823 putc('$', fp); 824 putc('(', fp); 825 shtree(bqlist->n, -1, NULL, fp); 826 putc(')', fp); 827 break; 828 default: 829 putc(*p, fp); 830 break; 831 } 832 } 833 } 834 835 static void 836 shcmd(union node *cmd, FILE *fp) 837 { 838 union node *np; 839 int first; 840 const char *s; 841 int dftfd; 842 843 first = 1; 844 for (np = cmd->ncmd.args; np; np = np->narg.next) { 845 if (!first) 846 putc(' ', fp); 847 sharg(np, fp); 848 first = 0; 849 } 850 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) { 851 if (!first) 852 putc(' ', fp); 853 dftfd = 0; 854 switch (np->nfile.type) { 855 case NTO: s = ">>"+1; dftfd = 1; break; 856 case NCLOBBER: s = ">|"; dftfd = 1; break; 857 case NAPPEND: s = ">>"; dftfd = 1; break; 858 case NTOFD: s = ">&"; dftfd = 1; break; 859 case NFROM: s = "<"; break; 860 case NFROMFD: s = "<&"; break; 861 case NFROMTO: s = "<>"; break; 862 default: s = "*error*"; break; 863 } 864 if (np->nfile.fd != dftfd) 865 fprintf(fp, "%d", np->nfile.fd); 866 fputs(s, fp); 867 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 868 fprintf(fp, "%d", np->ndup.dupfd); 869 } else { 870 sharg(np->nfile.fname, fp); 871 } 872 first = 0; 873 } 874 } 875 876 static void 877 shtree(union node *n, int ind, char *pfx, FILE *fp) 878 { 879 struct nodelist *lp; 880 const char *s; 881 882 if (n == NULL) 883 return; 884 885 indent(ind, pfx, fp); 886 switch (n->type) { 887 case NSEMI: 888 s = "; "; 889 goto binop; 890 case NAND: 891 s = " && "; 892 goto binop; 893 case NOR: 894 s = " || "; 895 binop: 896 shtree(n->nbinary.ch1, ind, NULL, fp); 897 /* if (ind < 0) */ 898 fputs(s, fp); 899 shtree(n->nbinary.ch2, ind, NULL, fp); 900 break; 901 case NCMD: 902 shcmd(n, fp); 903 if (ind >= 0) 904 putc('\n', fp); 905 break; 906 case NPIPE: 907 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 908 shcmd(lp->n, fp); 909 if (lp->next) 910 fputs(" | ", fp); 911 } 912 if (n->npipe.backgnd) 913 fputs(" &", fp); 914 if (ind >= 0) 915 putc('\n', fp); 916 break; 917 default: 918 fprintf(fp, "<node type %d>", n->type); 919 if (ind >= 0) 920 putc('\n', fp); 921 break; 922 } 923 } 924 925 static void 926 showtree(union node *n) 927 { 928 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) 939 940 #endif /* DEBUG */ 941 942 943 /* ============ Parser data */ 944 945 /* 946 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up. 947 */ 948 struct strlist { 949 struct strlist *next; 950 char *text; 951 }; 952 953 #if ENABLE_ASH_ALIAS 954 struct alias; 955 #endif 529 956 530 957 struct strpush { … … 532 959 char *prevstring; 533 960 int prevnleft; 534 #if def CONFIG_ASH_ALIAS961 #if ENABLE_ASH_ALIAS 535 962 struct alias *ap; /* if push was associated with an alias */ 536 963 #endif … … 551 978 552 979 static struct parsefile basepf; /* top level input file */ 553 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */554 980 static struct parsefile *parsefile = &basepf; /* current input file */ 555 556 557 static int tokpushback; /* last token pushed back */ 558 #define NEOF ((union node *)&tokpushback) 559 static int parsebackquote; /* nonzero if we are inside backquotes */ 981 static int startlinno; /* line # where last token started */ 982 static char *commandname; /* currently executing command */ 983 static struct strlist *cmdenviron; /* environment for builtin command */ 984 static int exitstatus; /* exit status of last command */ 985 986 987 /* ============ Message printing */ 988 989 static void 990 ash_vmsg(const char *msg, va_list ap) 991 { 992 fprintf(stderr, "%s: ", arg0); 993 if (commandname) { 994 if (strcmp(arg0, commandname)) 995 fprintf(stderr, "%s: ", commandname); 996 if (!iflag || parsefile->fd) 997 fprintf(stderr, "line %d: ", startlinno); 998 } 999 vfprintf(stderr, msg, ap); 1000 outcslow('\n', stderr); 1001 } 1002 1003 /* 1004 * Exverror is called to raise the error exception. If the second argument 1005 * is not NULL then error prints an error message using printf style 1006 * formatting. It then raises the error exception. 1007 */ 1008 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN; 1009 static void 1010 ash_vmsg_and_raise(int cond, const char *msg, va_list ap) 1011 { 1012 #if DEBUG 1013 if (msg) { 1014 TRACE(("ash_vmsg_and_raise(%d, \"", cond)); 1015 TRACEV((msg, ap)); 1016 TRACE(("\") pid=%d\n", getpid())); 1017 } else 1018 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid())); 1019 if (msg) 1020 #endif 1021 ash_vmsg(msg, ap); 1022 1023 flush_stdout_stderr(); 1024 raise_exception(cond); 1025 /* NOTREACHED */ 1026 } 1027 1028 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN; 1029 static void 1030 ash_msg_and_raise_error(const char *msg, ...) 1031 { 1032 va_list ap; 1033 1034 va_start(ap, msg); 1035 ash_vmsg_and_raise(EXERROR, msg, ap); 1036 /* NOTREACHED */ 1037 va_end(ap); 1038 } 1039 1040 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN; 1041 static void 1042 ash_msg_and_raise(int cond, const char *msg, ...) 1043 { 1044 va_list ap; 1045 1046 va_start(ap, msg); 1047 ash_vmsg_and_raise(cond, msg, ap); 1048 /* NOTREACHED */ 1049 va_end(ap); 1050 } 1051 1052 /* 1053 * error/warning routines for external builtins 1054 */ 1055 static void 1056 ash_msg(const char *fmt, ...) 1057 { 1058 va_list ap; 1059 1060 va_start(ap, fmt); 1061 ash_vmsg(fmt, ap); 1062 va_end(ap); 1063 } 1064 1065 /* 1066 * Return a string describing an error. The returned string may be a 1067 * pointer to a static buffer that will be overwritten on the next call. 1068 * Action describes the operation that got the error. 1069 */ 1070 static const char * 1071 errmsg(int e, const char *em) 1072 { 1073 if (e == ENOENT || e == ENOTDIR) { 1074 return em; 1075 } 1076 return strerror(e); 1077 } 1078 1079 1080 /* ============ Memory allocation */ 1081 1082 /* 1083 * It appears that grabstackstr() will barf with such alignments 1084 * because stalloc() will return a string allocated in a new stackblock. 1085 */ 1086 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) 1087 enum { 1088 /* Most machines require the value returned from malloc to be aligned 1089 * in some way. The following macro will get this right 1090 * on many machines. */ 1091 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, 1092 /* Minimum size of a block */ 1093 MINSIZE = SHELL_ALIGN(504), 1094 }; 1095 1096 struct stack_block { 1097 struct stack_block *prev; 1098 char space[MINSIZE]; 1099 }; 1100 1101 struct stackmark { 1102 struct stack_block *stackp; 1103 char *stacknxt; 1104 size_t stacknleft; 1105 struct stackmark *marknext; 1106 }; 1107 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 } 1145 1146 /* 1147 * Parse trees for commands are allocated in lifo order, so we use a stack 1148 * to make this more efficient, and also to avoid all sorts of exception 1149 * handling code to handle interrupts in the middle of a parse. 1150 * 1151 * The size 504 was chosen because the Ultrix malloc handles that size 1152 * well. 1153 */ 1154 static void * 1155 stalloc(size_t nbytes) 1156 { 1157 char *p; 1158 size_t aligned; 1159 1160 aligned = SHELL_ALIGN(nbytes); 1161 if (aligned > stacknleft) { 1162 size_t len; 1163 size_t blocksize; 1164 struct stack_block *sp; 1165 1166 blocksize = aligned; 1167 if (blocksize < MINSIZE) 1168 blocksize = MINSIZE; 1169 len = sizeof(struct stack_block) - MINSIZE + blocksize; 1170 if (len < blocksize) 1171 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1172 INT_OFF; 1173 sp = ckmalloc(len); 1174 sp->prev = stackp; 1175 stacknxt = sp->space; 1176 stacknleft = blocksize; 1177 sstrend = stacknxt + blocksize; 1178 stackp = sp; 1179 INT_ON; 1180 } 1181 p = stacknxt; 1182 stacknxt += aligned; 1183 stacknleft -= aligned; 1184 return p; 1185 } 1186 1187 static void 1188 stunalloc(void *p) 1189 { 1190 #if DEBUG 1191 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { 1192 write(2, "stunalloc\n", 10); 1193 abort(); 1194 } 1195 #endif 1196 stacknleft += stacknxt - (char *)p; 1197 stacknxt = p; 1198 } 1199 1200 /* 1201 * Like strdup but works with the ash stack. 1202 */ 1203 static char * 1204 ststrdup(const char *p) 1205 { 1206 size_t len = strlen(p) + 1; 1207 return memcpy(stalloc(len), p, len); 1208 } 1209 1210 static void 1211 setstackmark(struct stackmark *mark) 1212 { 1213 mark->stackp = stackp; 1214 mark->stacknxt = stacknxt; 1215 mark->stacknleft = stacknleft; 1216 mark->marknext = markp; 1217 markp = mark; 1218 } 1219 1220 static void 1221 popstackmark(struct stackmark *mark) 1222 { 1223 struct stack_block *sp; 1224 1225 if (!mark->stackp) 1226 return; 1227 1228 INT_OFF; 1229 markp = mark->marknext; 1230 while (stackp != mark->stackp) { 1231 sp = stackp; 1232 stackp = sp->prev; 1233 free(sp); 1234 } 1235 stacknxt = mark->stacknxt; 1236 stacknleft = mark->stacknleft; 1237 sstrend = mark->stacknxt + mark->stacknleft; 1238 INT_ON; 1239 } 1240 1241 /* 1242 * When the parser reads in a string, it wants to stick the string on the 1243 * stack and only adjust the stack pointer when it knows how big the 1244 * string is. Stackblock (defined in stack.h) returns a pointer to a block 1245 * of space on top of the stack and stackblocklen returns the length of 1246 * this block. Growstackblock will grow this space by at least one byte, 1247 * possibly moving it (like realloc). Grabstackblock actually allocates the 1248 * part of the block that has been used. 1249 */ 1250 static void 1251 growstackblock(void) 1252 { 1253 size_t newlen; 1254 1255 newlen = stacknleft * 2; 1256 if (newlen < stacknleft) 1257 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1258 if (newlen < 128) 1259 newlen += 128; 1260 1261 if (stacknxt == stackp->space && stackp != &stackbase) { 1262 struct stack_block *oldstackp; 1263 struct stackmark *xmark; 1264 struct stack_block *sp; 1265 struct stack_block *prevstackp; 1266 size_t grosslen; 1267 1268 INT_OFF; 1269 oldstackp = stackp; 1270 sp = stackp; 1271 prevstackp = sp->prev; 1272 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 1273 sp = ckrealloc(sp, grosslen); 1274 sp->prev = prevstackp; 1275 stackp = sp; 1276 stacknxt = sp->space; 1277 stacknleft = newlen; 1278 sstrend = sp->space + newlen; 1279 1280 /* 1281 * Stack marks pointing to the start of the old block 1282 * must be relocated to point to the new block 1283 */ 1284 xmark = markp; 1285 while (xmark != NULL && xmark->stackp == oldstackp) { 1286 xmark->stackp = stackp; 1287 xmark->stacknxt = stacknxt; 1288 xmark->stacknleft = stacknleft; 1289 xmark = xmark->marknext; 1290 } 1291 INT_ON; 1292 } else { 1293 char *oldspace = stacknxt; 1294 int oldlen = stacknleft; 1295 char *p = stalloc(newlen); 1296 1297 /* free the space we just allocated */ 1298 stacknxt = memcpy(p, oldspace, oldlen); 1299 stacknleft += newlen; 1300 } 1301 } 1302 1303 static void 1304 grabstackblock(size_t len) 1305 { 1306 len = SHELL_ALIGN(len); 1307 stacknxt += len; 1308 stacknleft -= len; 1309 } 1310 1311 /* 1312 * The following routines are somewhat easier to use than the above. 1313 * The user declares a variable of type STACKSTR, which may be declared 1314 * to be a register. The macro STARTSTACKSTR initializes things. Then 1315 * the user uses the macro STPUTC to add characters to the string. In 1316 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 1317 * grown as necessary. When the user is done, she can just leave the 1318 * string there and refer to it using stackblock(). Or she can allocate 1319 * the space for it using grabstackstr(). If it is necessary to allow 1320 * someone else to use the stack temporarily and then continue to grow 1321 * the string, the user should use grabstack to allocate the space, and 1322 * then call ungrabstr(p) to return to the previous mode of operation. 1323 * 1324 * USTPUTC is like STPUTC except that it doesn't check for overflow. 1325 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 1326 * is space for at least one character. 1327 */ 1328 static void * 1329 growstackstr(void) 1330 { 1331 size_t len = stackblocksize(); 1332 if (herefd >= 0 && len >= 1024) { 1333 full_write(herefd, stackblock(), len); 1334 return stackblock(); 1335 } 1336 growstackblock(); 1337 return stackblock() + len; 1338 } 1339 1340 /* 1341 * Called from CHECKSTRSPACE. 1342 */ 1343 static char * 1344 makestrspace(size_t newlen, char *p) 1345 { 1346 size_t len = p - stacknxt; 1347 size_t size = stackblocksize(); 1348 1349 for (;;) { 1350 size_t nleft; 1351 1352 size = stackblocksize(); 1353 nleft = size - len; 1354 if (nleft >= newlen) 1355 break; 1356 growstackblock(); 1357 } 1358 return stackblock() + len; 1359 } 1360 1361 static char * 1362 stack_nputstr(const char *s, size_t n, char *p) 1363 { 1364 p = makestrspace(n, p); 1365 p = memcpy(p, s, n) + n; 1366 return p; 1367 } 1368 1369 static char * 1370 stack_putstr(const char *s, char *p) 1371 { 1372 return stack_nputstr(s, strlen(s), p); 1373 } 1374 1375 static char * 1376 _STPUTC(int c, char *p) 1377 { 1378 if (p == sstrend) 1379 p = growstackstr(); 1380 *p++ = c; 1381 return p; 1382 } 1383 1384 #define STARTSTACKSTR(p) ((p) = stackblock()) 1385 #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)) 1404 1405 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1406 #define ungrabstackstr(s, p) stunalloc((s)) 1407 #define stackstrend() ((void *)sstrend) 1408 1409 1410 /* ============ String helpers */ 1411 1412 /* 1413 * prefix -- see if pfx is a prefix of string. 1414 */ 1415 static char * 1416 prefix(const char *string, const char *pfx) 1417 { 1418 while (*pfx) { 1419 if (*pfx++ != *string++) 1420 return 0; 1421 } 1422 return (char *) string; 1423 } 1424 1425 /* 1426 * Check for a valid number. This should be elsewhere. 1427 */ 1428 static int 1429 is_number(const char *p) 1430 { 1431 do { 1432 if (!isdigit(*p)) 1433 return 0; 1434 } while (*++p != '\0'); 1435 return 1; 1436 } 1437 1438 /* 1439 * Convert a string of digits to an integer, printing an error message on 1440 * failure. 1441 */ 1442 static int 1443 number(const char *s) 1444 { 1445 if (!is_number(s)) 1446 ash_msg_and_raise_error(illnum, s); 1447 return atoi(s); 1448 } 1449 1450 /* 1451 * Produce a possibly single quoted string suitable as input to the shell. 1452 * The return string is allocated on the stack. 1453 */ 1454 static char * 1455 single_quote(const char *s) 1456 { 1457 char *p; 1458 1459 STARTSTACKSTR(p); 1460 1461 do { 1462 char *q; 1463 size_t len; 1464 1465 len = strchrnul(s, '\'') - s; 1466 1467 q = p = makestrspace(len + 3, p); 1468 1469 *q++ = '\''; 1470 q = memcpy(q, s, len) + len; 1471 *q++ = '\''; 1472 s += len; 1473 1474 STADJUST(q - p, p); 1475 1476 len = strspn(s, "'"); 1477 if (!len) 1478 break; 1479 1480 q = p = makestrspace(len + 3, p); 1481 1482 *q++ = '"'; 1483 q = memcpy(q, s, len) + len; 1484 *q++ = '"'; 1485 s += len; 1486 1487 STADJUST(q - p, p); 1488 } while (*s); 1489 1490 USTPUTC(0, p); 1491 1492 return stackblock(); 1493 } 1494 1495 1496 /* ============ nextopt */ 1497 1498 static char **argptr; /* argument list for builtin commands */ 1499 static char *optionarg; /* set by nextopt (like getopt) */ 1500 static char *optptr; /* used by nextopt */ 1501 1502 /* 1503 * XXX - should get rid of. have all builtins use getopt(3). the 1504 * library getopt must have the BSD extension static variable "optreset" 1505 * otherwise it can't be used within the shell safely. 1506 * 1507 * Standard option processing (a la getopt) for builtin routines. The 1508 * only argument that is passed to nextopt is the option string; the 1509 * other arguments are unnecessary. It return the character, or '\0' on 1510 * end of input. 1511 */ 1512 static int 1513 nextopt(const char *optstring) 1514 { 1515 char *p; 1516 const char *q; 1517 char c; 1518 1519 p = optptr; 1520 if (p == NULL || *p == '\0') { 1521 p = *argptr; 1522 if (p == NULL || *p != '-' || *++p == '\0') 1523 return '\0'; 1524 argptr++; 1525 if (LONE_DASH(p)) /* check for "--" */ 1526 return '\0'; 1527 } 1528 c = *p++; 1529 for (q = optstring; *q != c; ) { 1530 if (*q == '\0') 1531 ash_msg_and_raise_error("illegal option -%c", c); 1532 if (*++q == ':') 1533 q++; 1534 } 1535 if (*++q == ':') { 1536 if (*p == '\0' && (p = *argptr++) == NULL) 1537 ash_msg_and_raise_error("no arg for -%c option", c); 1538 optionarg = p; 1539 p = NULL; 1540 } 1541 optptr = p; 1542 return c; 1543 } 1544 1545 1546 /* ============ Math support definitions */ 1547 1548 #if ENABLE_ASH_MATH_SUPPORT_64 1549 typedef int64_t arith_t; 1550 #define arith_t_type long long 1551 #else 1552 typedef long arith_t; 1553 #define arith_t_type long 1554 #endif 1555 1556 #if ENABLE_ASH_MATH_SUPPORT 1557 static arith_t dash_arith(const char *); 1558 static arith_t arith(const char *expr, int *perrcode); 1559 #endif 1560 1561 #if ENABLE_ASH_RANDOM_SUPPORT 1562 static unsigned long rseed; 1563 #ifndef DYNAMIC_VAR 1564 #define DYNAMIC_VAR 1565 #endif 1566 #endif 1567 1568 1569 /* ============ Shell variables */ 1570 1571 /* flags */ 1572 #define VEXPORT 0x01 /* variable is exported */ 1573 #define VREADONLY 0x02 /* variable cannot be modified */ 1574 #define VSTRFIXED 0x04 /* variable struct is statically allocated */ 1575 #define VTEXTFIXED 0x08 /* text is statically allocated */ 1576 #define VSTACK 0x10 /* text is allocated on the stack */ 1577 #define VUNSET 0x20 /* the variable is not set */ 1578 #define VNOFUNC 0x40 /* don't call the callback function */ 1579 #define VNOSET 0x80 /* do not set variable - just readonly test */ 1580 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1581 #ifdef DYNAMIC_VAR 1582 # define VDYNAMIC 0x200 /* dynamic variable */ 1583 #else 1584 # define VDYNAMIC 0 1585 #endif 1586 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[] */ 1646 #if ENABLE_LOCALE_SUPPORT 1647 static void 1648 change_lc_all(const char *value) 1649 { 1650 if (value && *value != '\0') 1651 setlocale(LC_ALL, value); 1652 } 1653 static void 1654 change_lc_ctype(const char *value) 1655 { 1656 if (value && *value != '\0') 1657 setlocale(LC_CTYPE, value); 1658 } 1659 #endif 1660 #if ENABLE_ASH_MAIL 1661 static void chkmail(void); 1662 static void changemail(const char *); 1663 #endif 1664 static void changepath(const char *); 1665 #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 }, 1672 #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 }, 1683 #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] 1702 #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] 1714 #endif 1715 1716 /* 1717 * The following macros access the values of the above variables. 1718 * They have to skip over the name. They return the null string 1719 * for unset variables. 1720 */ 1721 #define ifsval() (vifs.text + 4) 1722 #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 1751 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1752 #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 * 1759 endofname(const char *name) 1760 { 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)) 1768 break; 1769 } 1770 return p; 1771 } 1772 1773 /* 1774 * Compares two strings up to the first = or '\0'. The first 1775 * string must be terminated by '='; the second may be terminated by 1776 * either '=' or '\0'. 1777 */ 1778 static int 1779 varcmp(const char *p, const char *q) 1780 { 1781 int c, d; 1782 1783 while ((c = *p) == (d = *q)) { 1784 if (!c || c == '=') 1785 goto out; 1786 p++; 1787 q++; 1788 } 1789 if (c == '=') 1790 c = '\0'; 1791 if (d == '=') 1792 d = '\0'; 1793 out: 1794 return c - d; 1795 } 1796 1797 static int 1798 varequal(const char *a, const char *b) 1799 { 1800 return !varcmp(a, b); 1801 } 1802 1803 /* 1804 * Find the appropriate entry in the hash table from the name. 1805 */ 1806 static struct var ** 1807 hashvar(const char *p) 1808 { 1809 unsigned hashval; 1810 1811 hashval = ((unsigned char) *p) << 4; 1812 while (*p && *p != '=') 1813 hashval += (unsigned char) *p++; 1814 return &vartab[hashval % VTABSIZE]; 1815 } 1816 1817 static int 1818 vpcmp(const void *a, const void *b) 1819 { 1820 return varcmp(*(const char **)a, *(const char **)b); 1821 } 1822 1823 /* 1824 * This routine initializes the builtin variables. 1825 */ 1826 static void 1827 initvar(void) 1828 { 1829 struct var *vp; 1830 struct var *end; 1831 struct var **vpp; 1832 1833 /* 1834 * PS1 depends on uid 1835 */ 1836 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT 1837 vps1.text = "PS1=\\w \\$ "; 1838 #else 1839 if (!geteuid()) 1840 vps1.text = "PS1=# "; 1841 #endif 1842 vp = varinit; 1843 end = vp + ARRAY_SIZE(varinit); 1844 do { 1845 vpp = hashvar(vp->text); 1846 vp->next = *vpp; 1847 *vpp = vp; 1848 } while (++vp < end); 1849 } 1850 1851 static struct var ** 1852 findvar(struct var **vpp, const char *name) 1853 { 1854 for (; *vpp; vpp = &(*vpp)->next) { 1855 if (varequal((*vpp)->text, name)) { 1856 break; 1857 } 1858 } 1859 return vpp; 1860 } 1861 1862 /* 1863 * Find the value of a variable. Returns NULL if not set. 1864 */ 1865 static char * 1866 lookupvar(const char *name) 1867 { 1868 struct var *v; 1869 1870 v = *findvar(hashvar(name), name); 1871 if (v) { 1872 #ifdef DYNAMIC_VAR 1873 /* 1874 * Dynamic variables are implemented roughly the same way they are 1875 * in bash. Namely, they're "special" so long as they aren't unset. 1876 * As soon as they're unset, they're no longer dynamic, and dynamic 1877 * lookup will no longer happen at that point. -- PFM. 1878 */ 1879 if ((v->flags & VDYNAMIC)) 1880 (*v->func)(NULL); 1881 #endif 1882 if (!(v->flags & VUNSET)) 1883 return strchrnul(v->text, '=') + 1; 1884 } 1885 return NULL; 1886 } 1887 1888 /* 1889 * Search the environment of a builtin command. 1890 */ 1891 static char * 1892 bltinlookup(const char *name) 1893 { 1894 struct strlist *sp; 1895 1896 for (sp = cmdenviron; sp; sp = sp->next) { 1897 if (varequal(sp->text, name)) 1898 return strchrnul(sp->text, '=') + 1; 1899 } 1900 return lookupvar(name); 1901 } 1902 1903 /* 1904 * Same as setvar except that the variable and value are passed in 1905 * the first argument as name=value. Since the first argument will 1906 * be actually stored in the table, it should not be a string that 1907 * will go away. 1908 * Called with interrupts off. 1909 */ 1910 static void 1911 setvareq(char *s, int flags) 1912 { 1913 struct var *vp, **vpp; 1914 1915 vpp = hashvar(s); 1916 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 1917 vp = *findvar(vpp, s); 1918 if (vp) { 1919 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { 1920 const char *n; 1921 1922 if (flags & VNOSAVE) 1923 free(s); 1924 n = vp->text; 1925 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); 1926 } 1927 1928 if (flags & VNOSET) 1929 return; 1930 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); 1936 1937 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 1938 } else { 1939 if (flags & VNOSET) 1940 return; 1941 /* not found */ 1942 vp = ckmalloc(sizeof(*vp)); 1943 vp->next = *vpp; 1944 vp->func = NULL; 1945 *vpp = vp; 1946 } 1947 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 1948 s = ckstrdup(s); 1949 vp->text = s; 1950 vp->flags = flags; 1951 } 1952 1953 /* 1954 * Set the value of a variable. The flags argument is ored with the 1955 * flags of the variable. If val is NULL, the variable is unset. 1956 */ 1957 static void 1958 setvar(const char *name, const char *val, int flags) 1959 { 1960 char *p, *q; 1961 size_t namelen; 1962 char *nameeq; 1963 size_t vallen; 1964 1965 q = endofname(name); 1966 p = strchrnul(q, '='); 1967 namelen = p - name; 1968 if (!namelen || p != q) 1969 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name); 1970 vallen = 0; 1971 if (val == NULL) { 1972 flags |= VUNSET; 1973 } else { 1974 vallen = strlen(val); 1975 } 1976 INT_OFF; 1977 nameeq = ckmalloc(namelen + vallen + 2); 1978 p = memcpy(nameeq, name, namelen) + namelen; 1979 if (val) { 1980 *p++ = '='; 1981 p = memcpy(p, val, vallen) + vallen; 1982 } 1983 *p = '\0'; 1984 setvareq(nameeq, flags | VNOSAVE); 1985 INT_ON; 1986 } 1987 1988 #if ENABLE_ASH_GETOPTS 1989 /* 1990 * Safe version of setvar, returns 1 on success 0 on failure. 1991 */ 1992 static int 1993 setvarsafe(const char *name, const char *val, int flags) 1994 { 1995 int err; 1996 volatile int saveint; 1997 struct jmploc *volatile savehandler = exception_handler; 1998 struct jmploc jmploc; 1999 2000 SAVE_INT(saveint); 2001 if (setjmp(jmploc.loc)) 2002 err = 1; 2003 else { 2004 exception_handler = &jmploc; 2005 setvar(name, val, flags); 2006 err = 0; 2007 } 2008 exception_handler = savehandler; 2009 RESTORE_INT(saveint); 2010 return err; 2011 } 2012 #endif 2013 2014 /* 2015 * Unset the specified variable. 2016 */ 2017 static int 2018 unsetvar(const char *s) 2019 { 2020 struct var **vpp; 2021 struct var *vp; 2022 int retval; 2023 2024 vpp = findvar(hashvar(s), s); 2025 vp = *vpp; 2026 retval = 2; 2027 if (vp) { 2028 int flags = vp->flags; 2029 2030 retval = 1; 2031 if (flags & VREADONLY) 2032 goto out; 2033 #ifdef DYNAMIC_VAR 2034 vp->flags &= ~VDYNAMIC; 2035 #endif 2036 if (flags & VUNSET) 2037 goto ok; 2038 if ((flags & VSTRFIXED) == 0) { 2039 INT_OFF; 2040 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 2041 free((char*)vp->text); 2042 *vpp = vp->next; 2043 free(vp); 2044 INT_ON; 2045 } else { 2046 setvar(s, 0, 0); 2047 vp->flags &= ~VEXPORT; 2048 } 2049 ok: 2050 retval = 0; 2051 } 2052 out: 2053 return retval; 2054 } 2055 2056 /* 2057 * Process a linked list of variable assignments. 2058 */ 2059 static void 2060 listsetvar(struct strlist *list_set_var, int flags) 2061 { 2062 struct strlist *lp = list_set_var; 2063 2064 if (!lp) 2065 return; 2066 INT_OFF; 2067 do { 2068 setvareq(lp->text, flags); 2069 lp = lp->next; 2070 } while (lp); 2071 INT_ON; 2072 } 2073 2074 /* 2075 * Generate a list of variables satisfying the given conditions. 2076 */ 2077 static char ** 2078 listvars(int on, int off, char ***end) 2079 { 2080 struct var **vpp; 2081 struct var *vp; 2082 char **ep; 2083 int mask; 2084 2085 STARTSTACKSTR(ep); 2086 vpp = vartab; 2087 mask = on | off; 2088 do { 2089 for (vp = *vpp; vp; vp = vp->next) { 2090 if ((vp->flags & mask) == on) { 2091 if (ep == stackstrend()) 2092 ep = growstackstr(); 2093 *ep++ = (char *) vp->text; 2094 } 2095 } 2096 } while (++vpp < vartab + VTABSIZE); 2097 if (ep == stackstrend()) 2098 ep = growstackstr(); 2099 if (end) 2100 *end = ep; 2101 *ep++ = NULL; 2102 return grabstackstr(ep); 2103 } 2104 2105 2106 /* ============ Path search helper 2107 * 2108 * The variable path (passed by reference) should be set to the start 2109 * of the path before the first call; padvance will update 2110 * this value as it proceeds. Successive calls to padvance will return 2111 * the possible path expansions in sequence. If an option (indicated by 2112 * a percent sign) appears in the path entry then the global variable 2113 * pathopt will be set to point to it; otherwise pathopt will be set to 2114 * NULL. 2115 */ 2116 static const char *pathopt; /* set by padvance */ 2117 2118 static char * 2119 padvance(const char **path, const char *name) 2120 { 2121 const char *p; 2122 char *q; 2123 const char *start; 2124 size_t len; 2125 2126 if (*path == NULL) 2127 return NULL; 2128 start = *path; 2129 for (p = start; *p && *p != ':' && *p != '%'; p++); 2130 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2131 while (stackblocksize() < len) 2132 growstackblock(); 2133 q = stackblock(); 2134 if (p != start) { 2135 memcpy(q, start, p - start); 2136 q += p - start; 2137 *q++ = '/'; 2138 } 2139 strcpy(q, name); 2140 pathopt = NULL; 2141 if (*p == '%') { 2142 pathopt = ++p; 2143 while (*p && *p != ':') p++; 2144 } 2145 if (*p == ':') 2146 *path = p + 1; 2147 else 2148 *path = NULL; 2149 return stalloc(len); 2150 } 2151 2152 2153 /* ============ Prompt */ 2154 560 2155 static int doprompt; /* if set, prompt the user */ 561 2156 static int needprompt; /* true if interactive and at start of line */ 562 static int lasttoken; /* last token read */ 563 static char *wordtext; /* text of last word returned by readtoken */ 564 static int checkkwd; 565 static struct nodelist *backquotelist; 566 static union node *redirnode; 567 static struct heredoc *heredoc; 568 static int quoteflag; /* set if (part of) last token was quoted */ 569 static int startlinno; /* line # where last token started */ 570 571 static union node *parsecmd(int); 572 static void fixredir(union node *, const char *, int); 573 static const char *const *findkwd(const char *); 574 static char *endofname(const char *); 575 576 /* shell.h */ 577 578 typedef void *pointer; 579 580 static char nullstr[1]; /* zero length string */ 581 static const char spcstr[] = " "; 582 static const char snlfmt[] = "%s\n"; 583 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; 584 static const char illnum[] = "Illegal number: %s"; 585 static const char homestr[] = "HOME"; 586 587 #ifdef DEBUG 588 #define TRACE(param) trace param 589 #define TRACEV(param) tracev param 2157 2158 #if ENABLE_FEATURE_EDITING 2159 static line_input_t *line_input_state; 2160 static const char *cmdedit_prompt; 2161 static void 2162 putprompt(const char *s) 2163 { 2164 if (ENABLE_ASH_EXPAND_PRMT) { 2165 free((char*)cmdedit_prompt); 2166 cmdedit_prompt = ckstrdup(s); 2167 return; 2168 } 2169 cmdedit_prompt = s; 2170 } 590 2171 #else 591 #define TRACE(param) 592 #define TRACEV(param) 593 #endif 594 595 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 596 #define __builtin_expect(x, expected_value) (x) 597 #endif 598 599 #define xlikely(x) __builtin_expect((x),1) 600 601 602 #define TEOF 0 603 #define TNL 1 604 #define TREDIR 2 605 #define TWORD 3 606 #define TSEMI 4 607 #define TBACKGND 5 608 #define TAND 6 609 #define TOR 7 610 #define TPIPE 8 611 #define TLP 9 612 #define TRP 10 613 #define TENDCASE 11 614 #define TENDBQUOTE 12 615 #define TNOT 13 616 #define TCASE 14 617 #define TDO 15 618 #define TDONE 16 619 #define TELIF 17 620 #define TELSE 18 621 #define TESAC 19 622 #define TFI 20 623 #define TFOR 21 624 #define TIF 22 625 #define TIN 23 626 #define TTHEN 24 627 #define TUNTIL 25 628 #define TWHILE 26 629 #define TBEGIN 27 630 #define TEND 28 631 632 /* first char is indicating which tokens mark the end of a list */ 633 static const char *const tokname_array[] = { 634 "\1end of file", 635 "\0newline", 636 "\0redirection", 637 "\0word", 638 "\0;", 639 "\0&", 640 "\0&&", 641 "\0||", 642 "\0|", 643 "\0(", 644 "\1)", 645 "\1;;", 646 "\1`", 647 #define KWDOFFSET 13 648 /* the following are keywords */ 649 "\0!", 650 "\0case", 651 "\1do", 652 "\1done", 653 "\1elif", 654 "\1else", 655 "\1esac", 656 "\1fi", 657 "\0for", 658 "\0if", 659 "\0in", 660 "\1then", 661 "\0until", 662 "\0while", 663 "\0{", 664 "\1}", 665 }; 666 667 static const char *tokname(int tok) 668 { 669 static char buf[16]; 670 671 if (tok >= TSEMI) 672 buf[0] = '"'; 673 sprintf(buf + (tok >= TSEMI), "%s%c", 674 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0)); 675 return buf; 676 } 677 678 /* machdep.h */ 679 680 /* 681 * Most machines require the value returned from malloc to be aligned 682 * in some way. The following macro will get this right on many machines. 683 */ 684 685 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1) 686 /* 687 * It appears that grabstackstr() will barf with such alignments 688 * because stalloc() will return a string allocated in a new stackblock. 689 */ 690 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) 691 692 /* 693 * This file was generated by the mksyntax program. 694 */ 695 2172 static void 2173 putprompt(const char *s) 2174 { 2175 out2str(s); 2176 } 2177 #endif 2178 2179 #if ENABLE_ASH_EXPAND_PRMT 2180 /* expandstr() needs parsing machinery, so it is far away ahead... */ 2181 static const char *expandstr(const char *ps); 2182 #else 2183 #define expandstr(s) s 2184 #endif 2185 2186 static void 2187 setprompt(int whichprompt) 2188 { 2189 const char *prompt; 2190 #if ENABLE_ASH_EXPAND_PRMT 2191 struct stackmark smark; 2192 #endif 2193 2194 needprompt = 0; 2195 2196 switch (whichprompt) { 2197 case 1: 2198 prompt = ps1val(); 2199 break; 2200 case 2: 2201 prompt = ps2val(); 2202 break; 2203 default: /* 0 */ 2204 prompt = nullstr; 2205 } 2206 #if ENABLE_ASH_EXPAND_PRMT 2207 setstackmark(&smark); 2208 stalloc(stackblocksize()); 2209 #endif 2210 putprompt(expandstr(prompt)); 2211 #if ENABLE_ASH_EXPAND_PRMT 2212 popstackmark(&smark); 2213 #endif 2214 } 2215 2216 2217 /* ============ The cd and pwd commands */ 2218 2219 #define CD_PHYSICAL 1 2220 #define CD_PRINT 2 2221 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 static int 2228 cdopt(void) 2229 { 2230 int flags = 0; 2231 int i, j; 2232 2233 j = 'L'; 2234 while ((i = nextopt("LP"))) { 2235 if (i != j) { 2236 flags ^= CD_PHYSICAL; 2237 j = i; 2238 } 2239 } 2240 2241 return flags; 2242 } 2243 2244 /* 2245 * Update curdir (the name of the current directory) in response to a 2246 * cd command. 2247 */ 2248 static const char * 2249 updatepwd(const char *dir) 2250 { 2251 char *new; 2252 char *p; 2253 char *cdcomppath; 2254 const char *lim; 2255 2256 cdcomppath = ststrdup(dir); 2257 STARTSTACKSTR(new); 2258 if (*dir != '/') { 2259 if (curdir == nullstr) 2260 return 0; 2261 new = stack_putstr(curdir, new); 2262 } 2263 new = makestrspace(strlen(dir) + 2, new); 2264 lim = stackblock() + 1; 2265 if (*dir != '/') { 2266 if (new[-1] != '/') 2267 USTPUTC('/', new); 2268 if (new > lim && *lim == '/') 2269 lim++; 2270 } else { 2271 USTPUTC('/', new); 2272 cdcomppath++; 2273 if (dir[1] == '/' && dir[2] != '/') { 2274 USTPUTC('/', new); 2275 cdcomppath++; 2276 lim++; 2277 } 2278 } 2279 p = strtok(cdcomppath, "/"); 2280 while (p) { 2281 switch (*p) { 2282 case '.': 2283 if (p[1] == '.' && p[2] == '\0') { 2284 while (new > lim) { 2285 STUNPUTC(new); 2286 if (new[-1] == '/') 2287 break; 2288 } 2289 break; 2290 } 2291 if (p[1] == '\0') 2292 break; 2293 /* fall through */ 2294 default: 2295 new = stack_putstr(p, new); 2296 USTPUTC('/', new); 2297 } 2298 p = strtok(0, "/"); 2299 } 2300 if (new > lim) 2301 STUNPUTC(new); 2302 *new = 0; 2303 return stackblock(); 2304 } 2305 2306 /* 2307 * Find out what the current directory is. If we already know the current 2308 * directory, this routine returns immediately. 2309 */ 2310 static char * 2311 getpwd(void) 2312 { 2313 char *dir = getcwd(0, 0); 2314 return dir ? dir : nullstr; 2315 } 2316 2317 static void 2318 setpwd(const char *val, int setold) 2319 { 2320 char *oldcur, *dir; 2321 2322 oldcur = dir = curdir; 2323 2324 if (setold) { 2325 setvar("OLDPWD", oldcur, VEXPORT); 2326 } 2327 INT_OFF; 2328 if (physdir != nullstr) { 2329 if (physdir != oldcur) 2330 free(physdir); 2331 physdir = nullstr; 2332 } 2333 if (oldcur == val || !val) { 2334 char *s = getpwd(); 2335 physdir = s; 2336 if (!val) 2337 dir = s; 2338 } else 2339 dir = ckstrdup(val); 2340 if (oldcur != dir && oldcur != nullstr) { 2341 free(oldcur); 2342 } 2343 curdir = dir; 2344 INT_ON; 2345 setvar("PWD", dir, VEXPORT); 2346 } 2347 2348 static void hashcd(void); 2349 2350 /* 2351 * Actually do the chdir. We also call hashcd to let the routines in exec.c 2352 * know that the current directory has changed. 2353 */ 2354 static int 2355 docd(const char *dest, int flags) 2356 { 2357 const char *dir = 0; 2358 int err; 2359 2360 TRACE(("docd(\"%s\", %d) called\n", dest, flags)); 2361 2362 INT_OFF; 2363 if (!(flags & CD_PHYSICAL)) { 2364 dir = updatepwd(dest); 2365 if (dir) 2366 dest = dir; 2367 } 2368 err = chdir(dest); 2369 if (err) 2370 goto out; 2371 setpwd(dir, 1); 2372 hashcd(); 2373 out: 2374 INT_ON; 2375 return err; 2376 } 2377 2378 static int 2379 cdcmd(int argc, char **argv) 2380 { 2381 const char *dest; 2382 const char *path; 2383 const char *p; 2384 char c; 2385 struct stat statb; 2386 int flags; 2387 2388 flags = cdopt(); 2389 dest = *argptr; 2390 if (!dest) 2391 dest = bltinlookup(homestr); 2392 else if (LONE_DASH(dest)) { 2393 dest = bltinlookup("OLDPWD"); 2394 flags |= CD_PRINT; 2395 } 2396 if (!dest) 2397 dest = nullstr; 2398 if (*dest == '/') 2399 goto step7; 2400 if (*dest == '.') { 2401 c = dest[1]; 2402 dotdot: 2403 switch (c) { 2404 case '\0': 2405 case '/': 2406 goto step6; 2407 case '.': 2408 c = dest[2]; 2409 if (c != '.') 2410 goto dotdot; 2411 } 2412 } 2413 if (!*dest) 2414 dest = "."; 2415 path = bltinlookup("CDPATH"); 2416 if (!path) { 2417 step6: 2418 step7: 2419 p = dest; 2420 goto docd; 2421 } 2422 do { 2423 c = *path; 2424 p = padvance(&path, dest); 2425 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2426 if (c && c != ':') 2427 flags |= CD_PRINT; 2428 docd: 2429 if (!docd(p, flags)) 2430 goto out; 2431 break; 2432 } 2433 } while (path); 2434 ash_msg_and_raise_error("can't cd to %s", dest); 2435 /* NOTREACHED */ 2436 out: 2437 if (flags & CD_PRINT) 2438 out1fmt(snlfmt, curdir); 2439 return 0; 2440 } 2441 2442 static int 2443 pwdcmd(int argc, char **argv) 2444 { 2445 int flags; 2446 const char *dir = curdir; 2447 2448 flags = cdopt(); 2449 if (flags) { 2450 if (physdir == nullstr) 2451 setpwd(dir, 0); 2452 dir = physdir; 2453 } 2454 out1fmt(snlfmt, dir); 2455 return 0; 2456 } 2457 2458 2459 /* ============ ... */ 2460 2461 #define IBUFSIZ (BUFSIZ + 1) 2462 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */ 696 2463 697 2464 /* Syntax classes */ … … 712 2479 #define CIGN 14 /* character should be ignored */ 713 2480 714 #if def CONFIG_ASH_ALIAS2481 #if ENABLE_ASH_ALIAS 715 2482 #define SYNBASE 130 716 2483 #define PEOF -130 … … 723 2490 #endif 724 2491 725 #define is_digit(c) ((unsigned)((c) - '0') <= 9) 726 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 727 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 728 729 /* C99 say: "char" declaration may be signed or unsigned default */ 730 #define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int) 731 732 /* 733 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise 734 * (assuming ascii char codes, as the original implementation did) 735 */ 736 #define is_special(c) \ 737 ( (((unsigned int)c) - 33 < 32) \ 738 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) 739 740 #define digit_val(c) ((c) - '0') 741 742 /* 743 * This file was generated by the mksyntax program. 744 */ 745 746 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 2492 /* number syntax index */ 2493 #define BASESYNTAX 0 /* not in quotes */ 2494 #define DQSYNTAX 1 /* in double quotes */ 2495 #define SQSYNTAX 2 /* in single quotes */ 2496 #define ARISYNTAX 3 /* in arithmetic */ 2497 2498 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 747 2499 #define USE_SIT_FUNCTION 748 2500 #endif 749 2501 750 /* number syntax index */ 751 #define BASESYNTAX 0 /* not in quotes */ 752 #define DQSYNTAX 1 /* in double quotes */ 753 #define SQSYNTAX 2 /* in single quotes */ 754 #define ARISYNTAX 3 /* in arithmetic */ 755 756 #ifdef CONFIG_ASH_MATH_SUPPORT 2502 #if ENABLE_ASH_MATH_SUPPORT 757 2503 static const char S_I_T[][4] = { 758 #if def CONFIG_ASH_ALIAS759 { CSPCL, CIGN, CIGN, CIGN},/* 0, PEOA */760 #endif 761 { CSPCL, CWORD, CWORD, CWORD},/* 1, ' ' */762 { CNL, CNL, CNL, CNL},/* 2, \n */763 { CWORD, CCTL, CCTL, CWORD},/* 3, !*-/:=?[]~ */764 { CDQUOTE, CENDQUOTE, CWORD, CWORD},/* 4, '"' */765 { CVAR, CVAR, CWORD, CVAR},/* 5, $ */766 { CSQUOTE, CWORD, CENDQUOTE, CWORD},/* 6, "'" */767 { CSPCL, CWORD, CWORD, CLP},/* 7, ( */768 { CSPCL, CWORD, CWORD, CRP},/* 8, ) */769 { CBACK, CBACK, CCTL, CBACK},/* 9, \ */770 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE},/* 10, ` */771 { CENDVAR, CENDVAR, CWORD, CENDVAR},/* 11, } */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, } */ 772 2518 #ifndef USE_SIT_FUNCTION 773 { CENDFILE, CENDFILE, CENDFILE, CENDFILE},/* 12, PEOF */774 { CWORD, CWORD, CWORD, CWORD},/* 13, 0-9A-Za-z */775 { CCTL, CCTL, CCTL, CCTL}/* 14, CTLESC ... */2519 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2520 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2521 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 776 2522 #endif 777 2523 }; 778 2524 #else 779 2525 static const char S_I_T[][3] = { 780 #if def CONFIG_ASH_ALIAS781 { CSPCL, CIGN, CIGN},/* 0, PEOA */782 #endif 783 { CSPCL, CWORD, CWORD},/* 1, ' ' */784 { CNL, CNL, CNL},/* 2, \n */785 { CWORD, CCTL, CCTL},/* 3, !*-/:=?[]~ */786 { CDQUOTE, CENDQUOTE, CWORD},/* 4, '"' */787 { CVAR, CVAR, CWORD},/* 5, $ */788 { CSQUOTE, CWORD, CENDQUOTE},/* 6, "'" */789 { CSPCL, CWORD, CWORD},/* 7, ( */790 { CSPCL, CWORD, CWORD},/* 8, ) */791 { CBACK, CBACK, CCTL},/* 9, \ */792 { CBQUOTE, CBQUOTE, CWORD},/* 10, ` */793 { CENDVAR, CENDVAR, CWORD},/* 11, } */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, } */ 794 2540 #ifndef USE_SIT_FUNCTION 795 { CENDFILE, CENDFILE, CENDFILE},/* 12, PEOF */796 { CWORD, CWORD, CWORD},/* 13, 0-9A-Za-z */797 { CCTL, CCTL, CCTL}/* 14, CTLESC ... */2541 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2542 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2543 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 798 2544 #endif 799 2545 }; 800 #endif /* CONFIG_ASH_MATH_SUPPORT */2546 #endif /* ASH_MATH_SUPPORT */ 801 2547 802 2548 #ifdef USE_SIT_FUNCTION 803 2549 804 #define U_C(c) ((unsigned char)(c)) 805 806 static int SIT(int c, int syntax) 807 { 808 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 809 #ifdef CONFIG_ASH_ALIAS 810 static const char syntax_index_table[] = { 2550 static int 2551 SIT(int c, int syntax) 2552 { 2553 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 2554 #if ENABLE_ASH_ALIAS 2555 static const char syntax_index_table[] ALIGN1 = { 811 2556 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 812 2557 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ … … 815 2560 }; 816 2561 #else 817 static const char syntax_index_table[] = {2562 static const char syntax_index_table[] ALIGN1 = { 818 2563 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 819 2564 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ … … 827 2572 if (c == PEOF) /* 2^8+2 */ 828 2573 return CENDFILE; 829 #if def CONFIG_ASH_ALIAS2574 #if ENABLE_ASH_ALIAS 830 2575 if (c == PEOA) /* 2^8+1 */ 831 2576 indx = 0; 832 2577 else 833 2578 #endif 834 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK)) 835 return CCTL; 836 else { 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 { 837 2586 s = strchr(spec_symbls, c); 838 if (s == 0 || *s == 0)2587 if (s == NULL || *s == '\0') 839 2588 return CWORD; 840 2589 indx = syntax_index_table[(s - spec_symbls)]; … … 843 2592 } 844 2593 845 #else /* USE_SIT_FUNCTION */ 846 847 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax] 848 849 #ifdef CONFIG_ASH_ALIAS 850 #define CSPCL_CIGN_CIGN_CIGN 0 851 #define CSPCL_CWORD_CWORD_CWORD 1 852 #define CNL_CNL_CNL_CNL 2 853 #define CWORD_CCTL_CCTL_CWORD 3 854 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 855 #define CVAR_CVAR_CWORD_CVAR 5 856 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 857 #define CSPCL_CWORD_CWORD_CLP 7 858 #define CSPCL_CWORD_CWORD_CRP 8 859 #define CBACK_CBACK_CCTL_CBACK 9 860 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 861 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11 862 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 863 #define CWORD_CWORD_CWORD_CWORD 13 864 #define CCTL_CCTL_CCTL_CCTL 14 2594 #else /* !USE_SIT_FUNCTION */ 2595 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 865 2612 #else 866 #define CSPCL_CWORD_CWORD_CWORD 867 #define CNL_CNL_CNL_CNL 868 #define CWORD_CCTL_CCTL_CWORD 869 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 870 #define CVAR_CVAR_CWORD_CVAR 871 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 872 #define CSPCL_CWORD_CWORD_CLP 873 #define CSPCL_CWORD_CWORD_CRP 874 #define CBACK_CBACK_CCTL_CBACK 875 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 876 #define CENDVAR_CENDVAR_CWORD_CENDVAR 877 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 878 #define CWORD_CWORD_CWORD_CWORD 879 #define CCTL_CCTL_CCTL_CCTL 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 880 2627 #endif 881 2628 … … 883 2630 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 884 2631 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 885 #if def CONFIG_ASH_ALIAS2632 #if ENABLE_ASH_ALIAS 886 2633 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN, 887 2634 #endif … … 1144 2891 }; 1145 2892 2893 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]) 2894 1146 2895 #endif /* USE_SIT_FUNCTION */ 1147 2896 1148 /* alias.c */ 1149 2897 2898 /* ============ Alias handling */ 2899 2900 #if ENABLE_ASH_ALIAS 2901 2902 #define ALIASINUSE 1 2903 #define ALIASDEAD 2 1150 2904 1151 2905 #define ATABSIZE 39 1152 2906 1153 static int funcblocksize; /* size of structures in function */ 1154 static int funcstringsize; /* size of strings in node */ 1155 static pointer funcblock; /* block to allocate function from */ 1156 static char *funcstring; /* block to allocate strings from */ 1157 1158 static const short nodesize[26] = { 1159 SHELL_ALIGN(sizeof (struct ncmd)), 1160 SHELL_ALIGN(sizeof (struct npipe)), 1161 SHELL_ALIGN(sizeof (struct nredir)), 1162 SHELL_ALIGN(sizeof (struct nredir)), 1163 SHELL_ALIGN(sizeof (struct nredir)), 1164 SHELL_ALIGN(sizeof (struct nbinary)), 1165 SHELL_ALIGN(sizeof (struct nbinary)), 1166 SHELL_ALIGN(sizeof (struct nbinary)), 1167 SHELL_ALIGN(sizeof (struct nif)), 1168 SHELL_ALIGN(sizeof (struct nbinary)), 1169 SHELL_ALIGN(sizeof (struct nbinary)), 1170 SHELL_ALIGN(sizeof (struct nfor)), 1171 SHELL_ALIGN(sizeof (struct ncase)), 1172 SHELL_ALIGN(sizeof (struct nclist)), 1173 SHELL_ALIGN(sizeof (struct narg)), 1174 SHELL_ALIGN(sizeof (struct narg)), 1175 SHELL_ALIGN(sizeof (struct nfile)), 1176 SHELL_ALIGN(sizeof (struct nfile)), 1177 SHELL_ALIGN(sizeof (struct nfile)), 1178 SHELL_ALIGN(sizeof (struct nfile)), 1179 SHELL_ALIGN(sizeof (struct nfile)), 1180 SHELL_ALIGN(sizeof (struct ndup)), 1181 SHELL_ALIGN(sizeof (struct ndup)), 1182 SHELL_ALIGN(sizeof (struct nhere)), 1183 SHELL_ALIGN(sizeof (struct nhere)), 1184 SHELL_ALIGN(sizeof (struct nnot)), 2907 struct alias { 2908 struct alias *next; 2909 char *name; 2910 char *val; 2911 int flag; 1185 2912 }; 1186 2913 1187 1188 static void calcsize(union node *); 1189 static void sizenodelist(struct nodelist *); 1190 static union node *copynode(union node *); 1191 static struct nodelist *copynodelist(struct nodelist *); 1192 static char *nodesavestr(char *); 1193 1194 1195 static int evalstring(char *, int mask); 1196 union node; /* BLETCH for ansi C */ 1197 static void evaltree(union node *, int); 1198 static void evalbackcmd(union node *, struct backcmd *); 1199 1200 static int evalskip; /* set if we are skipping commands */ 1201 static int skipcount; /* number of levels to skip */ 1202 static int funcnest; /* depth of function calls */ 1203 1204 /* reasons for skipping commands (see comment on breakcmd routine) */ 1205 #define SKIPBREAK (1 << 0) 1206 #define SKIPCONT (1 << 1) 1207 #define SKIPFUNC (1 << 2) 1208 #define SKIPFILE (1 << 3) 1209 #define SKIPEVAL (1 << 4) 1210 1211 /* 1212 * This file was generated by the mkbuiltins program. 1213 */ 1214 1215 #if JOBS 1216 static int bgcmd(int, char **); 1217 #endif 1218 static int breakcmd(int, char **); 1219 static int cdcmd(int, char **); 1220 #ifdef CONFIG_ASH_CMDCMD 1221 static int commandcmd(int, char **); 1222 #endif 1223 static int dotcmd(int, char **); 1224 static int evalcmd(int, char **); 1225 #ifdef CONFIG_ASH_BUILTIN_ECHO 1226 static int echocmd(int, char **); 1227 #endif 1228 #ifdef CONFIG_ASH_BUILTIN_TEST 1229 static int testcmd(int, char **); 1230 #endif 1231 static int execcmd(int, char **); 1232 static int exitcmd(int, char **); 1233 static int exportcmd(int, char **); 1234 static int falsecmd(int, char **); 1235 #if JOBS 1236 static int fgcmd(int, char **); 1237 #endif 1238 #ifdef CONFIG_ASH_GETOPTS 1239 static int getoptscmd(int, char **); 1240 #endif 1241 static int hashcmd(int, char **); 1242 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 1243 static int helpcmd(int argc, char **argv); 1244 #endif 1245 #if JOBS 1246 static int jobscmd(int, char **); 1247 #endif 1248 #ifdef CONFIG_ASH_MATH_SUPPORT 1249 static int letcmd(int, char **); 1250 #endif 1251 static int localcmd(int, char **); 1252 static int pwdcmd(int, char **); 1253 static int readcmd(int, char **); 1254 static int returncmd(int, char **); 1255 static int setcmd(int, char **); 1256 static int shiftcmd(int, char **); 1257 static int timescmd(int, char **); 1258 static int trapcmd(int, char **); 1259 static int truecmd(int, char **); 1260 static int typecmd(int, char **); 1261 static int umaskcmd(int, char **); 1262 static int unsetcmd(int, char **); 1263 static int waitcmd(int, char **); 1264 static int ulimitcmd(int, char **); 1265 #if JOBS 1266 static int killcmd(int, char **); 1267 #endif 1268 1269 /* mail.h */ 1270 1271 #ifdef CONFIG_ASH_MAIL 1272 static void chkmail(void); 1273 static void changemail(const char *); 1274 #endif 1275 1276 /* exec.h */ 1277 1278 /* values of cmdtype */ 1279 #define CMDUNKNOWN -1 /* no entry in table for command */ 1280 #define CMDNORMAL 0 /* command is an executable program */ 1281 #define CMDFUNCTION 1 /* command is a shell function */ 1282 #define CMDBUILTIN 2 /* command is a shell builtin */ 1283 1284 struct builtincmd { 1285 const char *name; 1286 int (*builtin)(int, char **); 1287 /* unsigned flags; */ 1288 }; 1289 1290 1291 #define COMMANDCMD (builtincmd + 5 + \ 1292 2 * ENABLE_ASH_BUILTIN_TEST + \ 1293 ENABLE_ASH_ALIAS + \ 1294 ENABLE_ASH_JOB_CONTROL) 1295 #define EXECCMD (builtincmd + 7 + \ 1296 2 * ENABLE_ASH_BUILTIN_TEST + \ 1297 ENABLE_ASH_ALIAS + \ 1298 ENABLE_ASH_JOB_CONTROL + \ 1299 ENABLE_ASH_CMDCMD + \ 1300 ENABLE_ASH_BUILTIN_ECHO) 1301 1302 #define BUILTIN_NOSPEC "0" 1303 #define BUILTIN_SPECIAL "1" 1304 #define BUILTIN_REGULAR "2" 1305 #define BUILTIN_SPEC_REG "3" 1306 #define BUILTIN_ASSIGN "4" 1307 #define BUILTIN_SPEC_ASSG "5" 1308 #define BUILTIN_REG_ASSG "6" 1309 #define BUILTIN_SPEC_REG_ASSG "7" 1310 1311 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) 1312 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) 1313 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4) 1314 1315 /* make sure to keep these in proper order since it is searched via bsearch() */ 1316 static const struct builtincmd builtincmd[] = { 1317 { BUILTIN_SPEC_REG ".", dotcmd }, 1318 { BUILTIN_SPEC_REG ":", truecmd }, 1319 #ifdef CONFIG_ASH_BUILTIN_TEST 1320 { BUILTIN_REGULAR "[", testcmd }, 1321 { BUILTIN_REGULAR "[[", testcmd }, 1322 #endif 1323 #ifdef CONFIG_ASH_ALIAS 1324 { BUILTIN_REG_ASSG "alias", aliascmd }, 1325 #endif 1326 #if JOBS 1327 { BUILTIN_REGULAR "bg", bgcmd }, 1328 #endif 1329 { BUILTIN_SPEC_REG "break", breakcmd }, 1330 { BUILTIN_REGULAR "cd", cdcmd }, 1331 { BUILTIN_NOSPEC "chdir", cdcmd }, 1332 #ifdef CONFIG_ASH_CMDCMD 1333 { BUILTIN_REGULAR "command", commandcmd }, 1334 #endif 1335 { BUILTIN_SPEC_REG "continue", breakcmd }, 1336 #ifdef CONFIG_ASH_BUILTIN_ECHO 1337 { BUILTIN_REGULAR "echo", echocmd }, 1338 #endif 1339 { BUILTIN_SPEC_REG "eval", evalcmd }, 1340 { BUILTIN_SPEC_REG "exec", execcmd }, 1341 { BUILTIN_SPEC_REG "exit", exitcmd }, 1342 { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, 1343 { BUILTIN_REGULAR "false", falsecmd }, 1344 #if JOBS 1345 { BUILTIN_REGULAR "fg", fgcmd }, 1346 #endif 1347 #ifdef CONFIG_ASH_GETOPTS 1348 { BUILTIN_REGULAR "getopts", getoptscmd }, 1349 #endif 1350 { BUILTIN_NOSPEC "hash", hashcmd }, 1351 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 1352 { BUILTIN_NOSPEC "help", helpcmd }, 1353 #endif 1354 #if JOBS 1355 { BUILTIN_REGULAR "jobs", jobscmd }, 1356 { BUILTIN_REGULAR "kill", killcmd }, 1357 #endif 1358 #ifdef CONFIG_ASH_MATH_SUPPORT 1359 { BUILTIN_NOSPEC "let", letcmd }, 1360 #endif 1361 { BUILTIN_ASSIGN "local", localcmd }, 1362 { BUILTIN_NOSPEC "pwd", pwdcmd }, 1363 { BUILTIN_REGULAR "read", readcmd }, 1364 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 1365 { BUILTIN_SPEC_REG "return", returncmd }, 1366 { BUILTIN_SPEC_REG "set", setcmd }, 1367 { BUILTIN_SPEC_REG "shift", shiftcmd }, 1368 { BUILTIN_SPEC_REG "source", dotcmd }, 1369 #ifdef CONFIG_ASH_BUILTIN_TEST 1370 { BUILTIN_REGULAR "test", testcmd }, 1371 #endif 1372 { BUILTIN_SPEC_REG "times", timescmd }, 1373 { BUILTIN_SPEC_REG "trap", trapcmd }, 1374 { BUILTIN_REGULAR "true", truecmd }, 1375 { BUILTIN_NOSPEC "type", typecmd }, 1376 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 1377 { BUILTIN_REGULAR "umask", umaskcmd }, 1378 #ifdef CONFIG_ASH_ALIAS 1379 { BUILTIN_REGULAR "unalias", unaliascmd }, 1380 #endif 1381 { BUILTIN_SPEC_REG "unset", unsetcmd }, 1382 { BUILTIN_REGULAR "wait", waitcmd }, 1383 }; 1384 1385 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) ) 1386 1387 1388 1389 struct cmdentry { 1390 int cmdtype; 1391 union param { 1392 int index; 1393 const struct builtincmd *cmd; 1394 struct funcnode *func; 1395 } u; 1396 }; 1397 1398 1399 /* action to find_command() */ 1400 #define DO_ERR 0x01 /* prints errors */ 1401 #define DO_ABS 0x02 /* checks absolute paths */ 1402 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 1403 #define DO_ALTPATH 0x08 /* using alternate path */ 1404 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 1405 1406 static const char *pathopt; /* set by padvance */ 1407 1408 static void shellexec(char **, const char *, int) 1409 ATTRIBUTE_NORETURN; 1410 static char *padvance(const char **, const char *); 1411 static void find_command(char *, struct cmdentry *, int, const char *); 1412 static struct builtincmd *find_builtin(const char *); 1413 static void hashcd(void); 1414 static void changepath(const char *); 1415 static void defun(char *, union node *); 1416 static void unsetfunc(const char *); 1417 1418 #ifdef CONFIG_ASH_MATH_SUPPORT_64 1419 typedef int64_t arith_t; 1420 #define arith_t_type (long long) 1421 #else 1422 typedef long arith_t; 1423 #define arith_t_type (long) 1424 #endif 1425 1426 #ifdef CONFIG_ASH_MATH_SUPPORT 1427 static arith_t dash_arith(const char *); 1428 static arith_t arith(const char *expr, int *perrcode); 1429 #endif 1430 1431 #ifdef CONFIG_ASH_RANDOM_SUPPORT 1432 static unsigned long rseed; 1433 static void change_random(const char *); 1434 # ifndef DYNAMIC_VAR 1435 # define DYNAMIC_VAR 1436 # endif 1437 #endif 1438 1439 /* init.h */ 1440 1441 static void reset(void); 1442 1443 /* var.h */ 1444 1445 /* 1446 * Shell variables. 1447 */ 1448 1449 /* flags */ 1450 #define VEXPORT 0x01 /* variable is exported */ 1451 #define VREADONLY 0x02 /* variable cannot be modified */ 1452 #define VSTRFIXED 0x04 /* variable struct is statically allocated */ 1453 #define VTEXTFIXED 0x08 /* text is statically allocated */ 1454 #define VSTACK 0x10 /* text is allocated on the stack */ 1455 #define VUNSET 0x20 /* the variable is not set */ 1456 #define VNOFUNC 0x40 /* don't call the callback function */ 1457 #define VNOSET 0x80 /* do not set variable - just readonly test */ 1458 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1459 #ifdef DYNAMIC_VAR 1460 # define VDYNAMIC 0x200 /* dynamic variable */ 1461 # else 1462 # define VDYNAMIC 0 1463 #endif 1464 1465 struct var { 1466 struct var *next; /* next entry in hash list */ 1467 int flags; /* flags are defined above */ 1468 const char *text; /* name=value */ 1469 void (*func)(const char *); /* function to be called when */ 1470 /* the variable gets set/unset */ 1471 }; 1472 1473 struct localvar { 1474 struct localvar *next; /* next local variable in list */ 1475 struct var *vp; /* the variable that was made local */ 1476 int flags; /* saved flags */ 1477 const char *text; /* saved text */ 1478 }; 1479 1480 1481 static struct localvar *localvars; 1482 1483 /* 1484 * Shell variables. 1485 */ 1486 1487 #ifdef CONFIG_ASH_GETOPTS 1488 static void getoptsreset(const char *); 1489 #endif 1490 1491 #ifdef CONFIG_LOCALE_SUPPORT 1492 #include <locale.h> 1493 static void change_lc_all(const char *value); 1494 static void change_lc_ctype(const char *value); 1495 #endif 1496 1497 1498 #define VTABSIZE 39 1499 1500 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; 1501 #ifdef IFS_BROKEN 1502 static const char defifsvar[] = "IFS= \t\n"; 1503 #define defifs (defifsvar + 4) 1504 #else 1505 static const char defifs[] = " \t\n"; 1506 #endif 1507 1508 1509 static struct var varinit[] = { 1510 #ifdef IFS_BROKEN 1511 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, 1512 #else 1513 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, 1514 #endif 1515 1516 #ifdef CONFIG_ASH_MAIL 1517 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1519 #endif 1520 1521 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, 1522 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, 1523 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, 1524 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, 1525 #ifdef CONFIG_ASH_GETOPTS 1526 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1527 #endif 1528 #ifdef CONFIG_ASH_RANDOM_SUPPORT 1529 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1530 #endif 1531 #ifdef CONFIG_LOCALE_SUPPORT 1532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1533 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1534 #endif 1535 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 1536 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1537 #endif 1538 }; 1539 1540 #define vifs varinit[0] 1541 #ifdef CONFIG_ASH_MAIL 1542 #define vmail (&vifs)[1] 1543 #define vmpath (&vmail)[1] 1544 #else 1545 #define vmpath vifs 1546 #endif 1547 #define vpath (&vmpath)[1] 1548 #define vps1 (&vpath)[1] 1549 #define vps2 (&vps1)[1] 1550 #define vps4 (&vps2)[1] 1551 #define voptind (&vps4)[1] 1552 #ifdef CONFIG_ASH_GETOPTS 1553 #define vrandom (&voptind)[1] 1554 #else 1555 #define vrandom (&vps4)[1] 1556 #endif 1557 #define defpath (defpathvar + 5) 1558 1559 /* 1560 * The following macros access the values of the above variables. 1561 * They have to skip over the name. They return the null string 1562 * for unset variables. 1563 */ 1564 1565 #define ifsval() (vifs.text + 4) 1566 #define ifsset() ((vifs.flags & VUNSET) == 0) 1567 #define mailval() (vmail.text + 5) 1568 #define mpathval() (vmpath.text + 9) 1569 #define pathval() (vpath.text + 5) 1570 #define ps1val() (vps1.text + 4) 1571 #define ps2val() (vps2.text + 4) 1572 #define ps4val() (vps4.text + 4) 1573 #define optindval() (voptind.text + 7) 1574 1575 #define mpathset() ((vmpath.flags & VUNSET) == 0) 1576 1577 static void setvar(const char *, const char *, int); 1578 static void setvareq(char *, int); 1579 static void listsetvar(struct strlist *, int); 1580 static char *lookupvar(const char *); 1581 static char *bltinlookup(const char *); 1582 static char **listvars(int, int, char ***); 1583 #define environment() listvars(VEXPORT, VUNSET, 0) 1584 static int showvars(const char *, int, int); 1585 static void poplocalvars(void); 1586 static int unsetvar(const char *); 1587 #ifdef CONFIG_ASH_GETOPTS 1588 static int setvarsafe(const char *, const char *, int); 1589 #endif 1590 static int varcmp(const char *, const char *); 1591 static struct var **hashvar(const char *); 1592 1593 1594 static inline int varequal(const char *a, const char *b) { 1595 return !varcmp(a, b); 1596 } 1597 1598 1599 static int loopnest; /* current loop nesting level */ 1600 1601 /* 1602 * The parsefile structure pointed to by the global variable parsefile 1603 * contains information about the current file being read. 1604 */ 1605 1606 1607 struct redirtab { 1608 struct redirtab *next; 1609 int renamed[10]; 1610 int nullredirs; 1611 }; 1612 1613 static struct redirtab *redirlist; 1614 static int nullredirs; 1615 1616 extern char **environ; 1617 1618 /* output.h */ 1619 1620 1621 static void outstr(const char *, FILE *); 1622 static void outcslow(int, FILE *); 1623 static void flushall(void); 1624 static void flusherr(void); 1625 static int out1fmt(const char *, ...) 1626 __attribute__((__format__(__printf__,1,2))); 1627 static int fmtstr(char *, size_t, const char *, ...) 1628 __attribute__((__format__(__printf__,3,4))); 1629 1630 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1631 1632 1633 static void out1str(const char *p) 1634 { 1635 outstr(p, stdout); 1636 } 1637 1638 static void out2str(const char *p) 1639 { 1640 outstr(p, stderr); 1641 flusherr(); 1642 } 1643 1644 /* 1645 * Initialization code. 1646 */ 1647 1648 /* 1649 * This routine initializes the builtin variables. 1650 */ 1651 1652 static inline void 1653 initvar(void) 1654 { 1655 struct var *vp; 1656 struct var *end; 1657 struct var **vpp; 1658 1659 /* 1660 * PS1 depends on uid 1661 */ 1662 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT) 1663 vps1.text = "PS1=\\w \\$ "; 1664 #else 1665 if (!geteuid()) 1666 vps1.text = "PS1=# "; 1667 #endif 1668 vp = varinit; 1669 end = vp + sizeof(varinit) / sizeof(varinit[0]); 1670 do { 1671 vpp = hashvar(vp->text); 1672 vp->next = *vpp; 1673 *vpp = vp; 1674 } while (++vp < end); 1675 } 1676 1677 static inline void 1678 init(void) 1679 { 1680 1681 /* from input.c: */ 1682 { 1683 basepf.nextc = basepf.buf = basebuf; 1684 } 1685 1686 /* from trap.c: */ 1687 { 1688 signal(SIGCHLD, SIG_DFL); 1689 } 1690 1691 /* from var.c: */ 1692 { 1693 char **envp; 1694 char ppid[32]; 1695 const char *p; 1696 struct stat st1, st2; 1697 1698 initvar(); 1699 for (envp = environ ; envp && *envp ; envp++) { 1700 if (strchr(*envp, '=')) { 1701 setvareq(*envp, VEXPORT|VTEXTFIXED); 1702 } 1703 } 1704 1705 snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); 1706 setvar("PPID", ppid, 0); 1707 1708 p = lookupvar("PWD"); 1709 if (p) 1710 if (*p != '/' || stat(p, &st1) || stat(".", &st2) || 1711 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 1712 p = 0; 1713 setpwd(p, 0); 1714 } 1715 } 1716 1717 /* PEOF (the end of file marker) */ 1718 1719 enum { 1720 INPUT_PUSH_FILE = 1, 1721 INPUT_NOFILE_OK = 2, 1722 }; 1723 1724 /* 1725 * The input line number. Input.c just defines this variable, and saves 1726 * and restores it when files are pushed and popped. The user of this 1727 * package must set its value. 1728 */ 1729 1730 static int pgetc(void); 1731 static int pgetc2(void); 1732 static int preadbuffer(void); 1733 static void pungetc(void); 1734 static void pushstring(char *, void *); 1735 static void popstring(void); 1736 static void setinputfd(int, int); 1737 static void setinputstring(char *); 1738 static void popfile(void); 1739 static void popallfiles(void); 1740 static void closescript(void); 1741 1742 1743 /* jobs.h */ 1744 2914 static struct alias *atab[ATABSIZE]; 2915 2916 static struct alias ** 2917 __lookupalias(const char *name) { 2918 unsigned int hashval; 2919 struct alias **app; 2920 const char *p; 2921 unsigned int ch; 2922 2923 p = name; 2924 2925 ch = (unsigned char)*p; 2926 hashval = ch << 4; 2927 while (ch) { 2928 hashval += ch; 2929 ch = (unsigned char)*++p; 2930 } 2931 app = &atab[hashval % ATABSIZE]; 2932 2933 for (; *app; app = &(*app)->next) { 2934 if (strcmp(name, (*app)->name) == 0) { 2935 break; 2936 } 2937 } 2938 2939 return app; 2940 } 2941 2942 static struct alias * 2943 lookupalias(const char *name, int check) 2944 { 2945 struct alias *ap = *__lookupalias(name); 2946 2947 if (check && ap && (ap->flag & ALIASINUSE)) 2948 return NULL; 2949 return ap; 2950 } 2951 2952 static struct alias * 2953 freealias(struct alias *ap) 2954 { 2955 struct alias *next; 2956 2957 if (ap->flag & ALIASINUSE) { 2958 ap->flag |= ALIASDEAD; 2959 return ap; 2960 } 2961 2962 next = ap->next; 2963 free(ap->name); 2964 free(ap->val); 2965 free(ap); 2966 return next; 2967 } 2968 2969 static void 2970 setalias(const char *name, const char *val) 2971 { 2972 struct alias *ap, **app; 2973 2974 app = __lookupalias(name); 2975 ap = *app; 2976 INT_OFF; 2977 if (ap) { 2978 if (!(ap->flag & ALIASINUSE)) { 2979 free(ap->val); 2980 } 2981 ap->val = ckstrdup(val); 2982 ap->flag &= ~ALIASDEAD; 2983 } else { 2984 /* not found */ 2985 ap = ckmalloc(sizeof(struct alias)); 2986 ap->name = ckstrdup(name); 2987 ap->val = ckstrdup(val); 2988 ap->flag = 0; 2989 ap->next = 0; 2990 *app = ap; 2991 } 2992 INT_ON; 2993 } 2994 2995 static int 2996 unalias(const char *name) 2997 { 2998 struct alias **app; 2999 3000 app = __lookupalias(name); 3001 3002 if (*app) { 3003 INT_OFF; 3004 *app = freealias(*app); 3005 INT_ON; 3006 return 0; 3007 } 3008 3009 return 1; 3010 } 3011 3012 static void 3013 rmaliases(void) 3014 { 3015 struct alias *ap, **app; 3016 int i; 3017 3018 INT_OFF; 3019 for (i = 0; i < ATABSIZE; i++) { 3020 app = &atab[i]; 3021 for (ap = *app; ap; ap = *app) { 3022 *app = freealias(*app); 3023 if (ap == *app) { 3024 app = &ap->next; 3025 } 3026 } 3027 } 3028 INT_ON; 3029 } 3030 3031 static void 3032 printalias(const struct alias *ap) 3033 { 3034 out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); 3035 } 3036 3037 /* 3038 * TODO - sort output 3039 */ 3040 static int 3041 aliascmd(int argc, char **argv) 3042 { 3043 char *n, *v; 3044 int ret = 0; 3045 struct alias *ap; 3046 3047 if (argc == 1) { 3048 int i; 3049 3050 for (i = 0; i < ATABSIZE; i++) 3051 for (ap = atab[i]; ap; ap = ap->next) { 3052 printalias(ap); 3053 } 3054 return 0; 3055 } 3056 while ((n = *++argv) != NULL) { 3057 v = strchr(n+1, '='); 3058 if (v == NULL) { /* n+1: funny ksh stuff */ 3059 ap = *__lookupalias(n); 3060 if (ap == NULL) { 3061 fprintf(stderr, "%s: %s not found\n", "alias", n); 3062 ret = 1; 3063 } else 3064 printalias(ap); 3065 } else { 3066 *v++ = '\0'; 3067 setalias(n, v); 3068 } 3069 } 3070 3071 return ret; 3072 } 3073 3074 static int 3075 unaliascmd(int argc, char **argv) 3076 { 3077 int i; 3078 3079 while ((i = nextopt("a")) != '\0') { 3080 if (i == 'a') { 3081 rmaliases(); 3082 return 0; 3083 } 3084 } 3085 for (i = 0; *argptr; argptr++) { 3086 if (unalias(*argptr)) { 3087 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr); 3088 i = 1; 3089 } 3090 } 3091 3092 return i; 3093 } 3094 3095 #endif /* ASH_ALIAS */ 3096 3097 3098 /* ============ jobs.c */ 1745 3099 1746 3100 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ … … 1753 3107 #define SHOW_PID 0x04 /* include process pid */ 1754 3108 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ 1755 1756 3109 1757 3110 /* … … 1791 3144 1792 3145 static pid_t backgndpid; /* pid of last background process */ 1793 static int job_warning; /* user was warned about stopped jobs */ 1794 #if JOBS 1795 static int jobctl; /* true if doing job control */ 1796 #endif 3146 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 1797 3147 1798 3148 static struct job *makejob(union node *, int); 1799 3149 static int forkshell(struct job *, union node *, int); 1800 3150 static int waitforjob(struct job *); 1801 static int stoppedjobs(void); 1802 1803 #if ! JOBS 1804 #define setjobctl(on) /* do nothing */3151 3152 #if !JOBS 3153 enum { jobctl = 0 }; 3154 #define setjobctl(on) do {} while (0) 1805 3155 #else 3156 static smallint jobctl; /* true if doing job control */ 1806 3157 static void setjobctl(int); 1807 static void showjobs(FILE *, int); 1808 #endif 1809 1810 /* main.h */ 1811 1812 1813 /* pid of main shell */ 1814 static int rootpid; 1815 /* shell level: 0 for the main shell, 1 for its children, and so on */ 1816 static int shlvl; 1817 #define rootshell (!shlvl) 1818 1819 static void readcmdfile(char *); 1820 static int cmdloop(int); 1821 1822 /* memalloc.h */ 1823 1824 1825 struct stackmark { 1826 struct stack_block *stackp; 1827 char *stacknxt; 1828 size_t stacknleft; 1829 struct stackmark *marknext; 1830 }; 1831 1832 /* minimum size of a block */ 1833 #define MINSIZE SHELL_ALIGN(504) 1834 1835 struct stack_block { 1836 struct stack_block *prev; 1837 char space[MINSIZE]; 1838 }; 1839 1840 static struct stack_block stackbase; 1841 static struct stack_block *stackp = &stackbase; 1842 static struct stackmark *markp; 1843 static char *stacknxt = stackbase.space; 1844 static size_t stacknleft = MINSIZE; 1845 static char *sstrend = stackbase.space + MINSIZE; 1846 static int herefd = -1; 1847 1848 1849 static pointer ckmalloc(size_t); 1850 static pointer ckrealloc(pointer, size_t); 1851 static char *savestr(const char *); 1852 static pointer stalloc(size_t); 1853 static void stunalloc(pointer); 1854 static void setstackmark(struct stackmark *); 1855 static void popstackmark(struct stackmark *); 1856 static void growstackblock(void); 1857 static void *growstackstr(void); 1858 static char *makestrspace(size_t, char *); 1859 static char *stnputs(const char *, size_t, char *); 1860 static char *stputs(const char *, char *); 1861 1862 1863 static inline char *_STPUTC(int c, char *p) { 1864 if (p == sstrend) 1865 p = growstackstr(); 1866 *p++ = c; 1867 return p; 1868 } 1869 1870 #define stackblock() ((void *)stacknxt) 1871 #define stackblocksize() stacknleft 1872 #define STARTSTACKSTR(p) ((p) = stackblock()) 1873 #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) 1874 #define CHECKSTRSPACE(n, p) \ 1875 ({ \ 1876 char *q = (p); \ 1877 size_t l = (n); \ 1878 size_t m = sstrend - q; \ 1879 if (l > m) \ 1880 (p) = makestrspace(l, q); \ 1881 0; \ 1882 }) 1883 #define USTPUTC(c, p) (*p++ = (c)) 1884 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0')) 1885 #define STUNPUTC(p) (--p) 1886 #define STTOPC(p) p[-1] 1887 #define STADJUST(amount, p) (p += (amount)) 1888 1889 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1890 #define ungrabstackstr(s, p) stunalloc((s)) 1891 #define stackstrend() ((void *)sstrend) 1892 1893 #define ckfree(p) free((pointer)(p)) 1894 1895 /* mystring.h */ 1896 1897 1898 #define DOLATSTRLEN 4 1899 1900 static char *prefix(const char *, const char *); 1901 static int number(const char *); 1902 static int is_number(const char *); 1903 static char *single_quote(const char *); 1904 static char *sstrdup(const char *); 1905 1906 #define equal(s1, s2) (strcmp(s1, s2) == 0) 1907 #define scopy(s1, s2) ((void)strcpy(s2, s1)) 1908 1909 /* options.h */ 1910 1911 struct shparam { 1912 int nparam; /* # of positional parameters (without $0) */ 1913 unsigned char malloc; /* if parameter list dynamically allocated */ 1914 char **p; /* parameter list */ 1915 #ifdef CONFIG_ASH_GETOPTS 1916 int optind; /* next parameter to be processed by getopts */ 1917 int optoff; /* used by getopts */ 1918 #endif 1919 }; 1920 1921 1922 #define eflag optlist[0] 1923 #define fflag optlist[1] 1924 #define Iflag optlist[2] 1925 #define iflag optlist[3] 1926 #define mflag optlist[4] 1927 #define nflag optlist[5] 1928 #define sflag optlist[6] 1929 #define xflag optlist[7] 1930 #define vflag optlist[8] 1931 #define Cflag optlist[9] 1932 #define aflag optlist[10] 1933 #define bflag optlist[11] 1934 #define uflag optlist[12] 1935 #define viflag optlist[13] 1936 1937 #ifdef DEBUG 1938 #define nolog optlist[14] 1939 #define debug optlist[15] 1940 #endif 1941 1942 #ifndef CONFIG_FEATURE_COMMAND_EDITING_VI 1943 #define setvimode(on) viflag = 0 /* forcibly keep the option off */ 1944 #endif 1945 1946 /* options.c */ 1947 1948 1949 static const char *const optletters_optnames[] = { 1950 "e" "errexit", 1951 "f" "noglob", 1952 "I" "ignoreeof", 1953 "i" "interactive", 1954 "m" "monitor", 1955 "n" "noexec", 1956 "s" "stdin", 1957 "x" "xtrace", 1958 "v" "verbose", 1959 "C" "noclobber", 1960 "a" "allexport", 1961 "b" "notify", 1962 "u" "nounset", 1963 "\0" "vi", 1964 #ifdef DEBUG 1965 "\0" "nolog", 1966 "\0" "debug", 1967 #endif 1968 }; 1969 1970 #define optletters(n) optletters_optnames[(n)][0] 1971 #define optnames(n) (&optletters_optnames[(n)][1]) 1972 1973 #define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0])) 1974 1975 static char optlist[NOPTS]; 1976 1977 1978 static char *arg0; /* value of $0 */ 1979 static struct shparam shellparam; /* $@ current positional parameters */ 1980 static char **argptr; /* argument list for builtin commands */ 1981 static char *optionarg; /* set by nextopt (like getopt) */ 1982 static char *optptr; /* used by nextopt */ 1983 1984 static char *minusc; /* argument to -c option */ 1985 1986 1987 static void procargs(int, char **); 1988 static void optschanged(void); 1989 static void setparam(char **); 1990 static void freeparam(volatile struct shparam *); 1991 static int shiftcmd(int, char **); 1992 static int setcmd(int, char **); 1993 static int nextopt(const char *); 1994 1995 /* redir.h */ 1996 1997 /* flags passed to redirect */ 1998 #define REDIR_PUSH 01 /* save previous values of file descriptors */ 1999 #define REDIR_SAVEFD2 03 /* set preverrout */ 2000 2001 union node; 2002 static void redirect(union node *, int); 2003 static void popredir(int); 2004 static void clearredir(int); 2005 static int copyfd(int, int); 2006 static int redirectsafe(union node *, int); 2007 2008 /* show.h */ 2009 2010 2011 #ifdef DEBUG 2012 static void showtree(union node *); 2013 static void trace(const char *, ...); 2014 static void tracev(const char *, va_list); 2015 static void trargs(char **); 2016 static void trputc(int); 2017 static void trputs(const char *); 2018 static void opentrace(void); 2019 #endif 2020 2021 /* trap.h */ 2022 2023 2024 /* trap handler commands */ 2025 static char *trap[NSIG]; 2026 /* current value of signal */ 2027 static char sigmode[NSIG - 1]; 2028 /* indicates specified signal received */ 2029 static char gotsig[NSIG - 1]; 2030 2031 static void clear_traps(void); 2032 static void setsignal(int); 2033 static void ignoresig(int); 2034 static void onsig(int); 2035 static int dotrap(void); 2036 static void setinteractive(int); 2037 static void exitshell(void) ATTRIBUTE_NORETURN; 2038 static int decode_signal(const char *, int); 2039 2040 /* 2041 * This routine is called when an error or an interrupt occurs in an 2042 * interactive shell and control is returned to the main command loop. 2043 */ 2044 2045 static void 2046 reset(void) 2047 { 2048 /* from eval.c: */ 2049 { 2050 evalskip = 0; 2051 loopnest = 0; 2052 } 2053 2054 /* from input.c: */ 2055 { 2056 parselleft = parsenleft = 0; /* clear input buffer */ 2057 popallfiles(); 2058 } 2059 2060 /* from parser.c: */ 2061 { 2062 tokpushback = 0; 2063 checkkwd = 0; 2064 } 2065 2066 /* from redir.c: */ 2067 { 2068 clearredir(0); 2069 } 2070 2071 } 2072 2073 #ifdef CONFIG_ASH_ALIAS 2074 static struct alias *atab[ATABSIZE]; 2075 2076 static void setalias(const char *, const char *); 2077 static struct alias *freealias(struct alias *); 2078 static struct alias **__lookupalias(const char *); 2079 2080 static void 2081 setalias(const char *name, const char *val) 2082 { 2083 struct alias *ap, **app; 2084 2085 app = __lookupalias(name); 2086 ap = *app; 2087 INTOFF; 2088 if (ap) { 2089 if (!(ap->flag & ALIASINUSE)) { 2090 ckfree(ap->val); 2091 } 2092 ap->val = savestr(val); 2093 ap->flag &= ~ALIASDEAD; 2094 } else { 2095 /* not found */ 2096 ap = ckmalloc(sizeof (struct alias)); 2097 ap->name = savestr(name); 2098 ap->val = savestr(val); 2099 ap->flag = 0; 2100 ap->next = 0; 2101 *app = ap; 2102 } 2103 INTON; 2104 } 2105 2106 static int 2107 unalias(const char *name) 2108 { 2109 struct alias **app; 2110 2111 app = __lookupalias(name); 2112 2113 if (*app) { 2114 INTOFF; 2115 *app = freealias(*app); 2116 INTON; 2117 return (0); 2118 } 2119 2120 return (1); 2121 } 2122 2123 static void 2124 rmaliases(void) 2125 { 2126 struct alias *ap, **app; 2127 int i; 2128 2129 INTOFF; 2130 for (i = 0; i < ATABSIZE; i++) { 2131 app = &atab[i]; 2132 for (ap = *app; ap; ap = *app) { 2133 *app = freealias(*app); 2134 if (ap == *app) { 2135 app = &ap->next; 2136 } 2137 } 2138 } 2139 INTON; 2140 } 2141 2142 static struct alias * 2143 lookupalias(const char *name, int check) 2144 { 2145 struct alias *ap = *__lookupalias(name); 2146 2147 if (check && ap && (ap->flag & ALIASINUSE)) 2148 return (NULL); 2149 return (ap); 2150 } 2151 2152 /* 2153 * TODO - sort output 2154 */ 2155 static int 2156 aliascmd(int argc, char **argv) 2157 { 2158 char *n, *v; 2159 int ret = 0; 2160 struct alias *ap; 2161 2162 if (argc == 1) { 2163 int i; 2164 2165 for (i = 0; i < ATABSIZE; i++) 2166 for (ap = atab[i]; ap; ap = ap->next) { 2167 printalias(ap); 2168 } 2169 return (0); 2170 } 2171 while ((n = *++argv) != NULL) { 2172 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ 2173 if ((ap = *__lookupalias(n)) == NULL) { 2174 fprintf(stderr, "%s: %s not found\n", "alias", n); 2175 ret = 1; 3158 #endif 3159 3160 /* 3161 * Set the signal handler for the specified signal. The routine figures 3162 * out what it should be set to. 3163 */ 3164 static void 3165 setsignal(int signo) 3166 { 3167 int action; 3168 char *t, tsig; 3169 struct sigaction act; 3170 3171 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) { 3179 switch (signo) { 3180 case SIGINT: 3181 if (iflag || minusc || sflag == 0) 3182 action = S_CATCH; 3183 break; 3184 case SIGQUIT: 3185 #if DEBUG 3186 if (debug) 3187 break; 3188 #endif 3189 /* FALLTHROUGH */ 3190 case SIGTERM: 3191 if (iflag) 3192 action = S_IGN; 3193 break; 3194 #if JOBS 3195 case SIGTSTP: 3196 case SIGTTOU: 3197 if (mflag) 3198 action = S_IGN; 3199 break; 3200 #endif 3201 } 3202 } 3203 3204 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 */ 3216 return; 3217 } 3218 if (act.sa_handler == SIG_IGN) { 3219 if (mflag 3220 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) 3221 ) { 3222 tsig = S_IGN; /* don't hard ignore these */ 2176 3223 } else 2177 printalias(ap);3224 tsig = S_HARD_IGN; 2178 3225 } else { 2179 *v++ = '\0'; 2180 setalias(n, v); 2181 } 2182 } 2183 2184 return (ret); 2185 } 2186 2187 static int 2188 unaliascmd(int argc, char **argv) 2189 { 2190 int i; 2191 2192 while ((i = nextopt("a")) != '\0') { 2193 if (i == 'a') { 2194 rmaliases(); 2195 return (0); 2196 } 2197 } 2198 for (i = 0; *argptr; argptr++) { 2199 if (unalias(*argptr)) { 2200 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr); 2201 i = 1; 2202 } 2203 } 2204 2205 return (i); 2206 } 2207 2208 static struct alias * 2209 freealias(struct alias *ap) { 2210 struct alias *next; 2211 2212 if (ap->flag & ALIASINUSE) { 2213 ap->flag |= ALIASDEAD; 2214 return ap; 2215 } 2216 2217 next = ap->next; 2218 ckfree(ap->name); 2219 ckfree(ap->val); 2220 ckfree(ap); 2221 return next; 2222 } 2223 2224 static void 2225 printalias(const struct alias *ap) { 2226 out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); 2227 } 2228 2229 static struct alias ** 2230 __lookupalias(const char *name) { 2231 unsigned int hashval; 2232 struct alias **app; 2233 const char *p; 2234 unsigned int ch; 2235 2236 p = name; 2237 2238 ch = (unsigned char)*p; 2239 hashval = ch << 4; 2240 while (ch) { 2241 hashval += ch; 2242 ch = (unsigned char)*++p; 2243 } 2244 app = &atab[hashval % ATABSIZE]; 2245 2246 for (; *app; app = &(*app)->next) { 2247 if (equal(name, (*app)->name)) { 2248 break; 2249 } 2250 } 2251 2252 return app; 2253 } 2254 #endif /* CONFIG_ASH_ALIAS */ 2255 2256 2257 /* cd.c */ 2258 2259 /* 2260 * The cd and pwd commands. 2261 */ 2262 2263 #define CD_PHYSICAL 1 2264 #define CD_PRINT 2 2265 2266 static int docd(const char *, int); 2267 static int cdopt(void); 2268 2269 static char *curdir = nullstr; /* current working directory */ 2270 static char *physdir = nullstr; /* physical working directory */ 2271 2272 static int 2273 cdopt(void) 2274 { 2275 int flags = 0; 2276 int i, j; 2277 2278 j = 'L'; 2279 while ((i = nextopt("LP"))) { 2280 if (i != j) { 2281 flags ^= CD_PHYSICAL; 2282 j = i; 2283 } 2284 } 2285 2286 return flags; 2287 } 2288 2289 static int 2290 cdcmd(int argc, char **argv) 2291 { 2292 const char *dest; 2293 const char *path; 2294 const char *p; 2295 char c; 2296 struct stat statb; 2297 int flags; 2298 2299 flags = cdopt(); 2300 dest = *argptr; 2301 if (!dest) 2302 dest = bltinlookup(homestr); 2303 else if (dest[0] == '-' && dest[1] == '\0') { 2304 dest = bltinlookup("OLDPWD"); 2305 flags |= CD_PRINT; 2306 } 2307 if (!dest) 2308 dest = nullstr; 2309 if (*dest == '/') 2310 goto step7; 2311 if (*dest == '.') { 2312 c = dest[1]; 2313 dotdot: 2314 switch (c) { 2315 case '\0': 2316 case '/': 2317 goto step6; 2318 case '.': 2319 c = dest[2]; 2320 if (c != '.') 2321 goto dotdot; 2322 } 2323 } 2324 if (!*dest) 2325 dest = "."; 2326 if (!(path = bltinlookup("CDPATH"))) { 2327 step6: 2328 step7: 2329 p = dest; 2330 goto docd; 2331 } 2332 do { 2333 c = *path; 2334 p = padvance(&path, dest); 2335 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2336 if (c && c != ':') 2337 flags |= CD_PRINT; 2338 docd: 2339 if (!docd(p, flags)) 2340 goto out; 2341 break; 2342 } 2343 } while (path); 2344 sh_error("can't cd to %s", dest); 2345 /* NOTREACHED */ 2346 out: 2347 if (flags & CD_PRINT) 2348 out1fmt(snlfmt, curdir); 2349 return 0; 2350 } 2351 2352 2353 /* 2354 * Update curdir (the name of the current directory) in response to a 2355 * cd command. 2356 */ 2357 2358 static inline const char * 2359 updatepwd(const char *dir) 2360 { 2361 char *new; 2362 char *p; 2363 char *cdcomppath; 2364 const char *lim; 2365 2366 cdcomppath = sstrdup(dir); 2367 STARTSTACKSTR(new); 2368 if (*dir != '/') { 2369 if (curdir == nullstr) 2370 return 0; 2371 new = stputs(curdir, new); 2372 } 2373 new = makestrspace(strlen(dir) + 2, new); 2374 lim = stackblock() + 1; 2375 if (*dir != '/') { 2376 if (new[-1] != '/') 2377 USTPUTC('/', new); 2378 if (new > lim && *lim == '/') 2379 lim++; 2380 } else { 2381 USTPUTC('/', new); 2382 cdcomppath++; 2383 if (dir[1] == '/' && dir[2] != '/') { 2384 USTPUTC('/', new); 2385 cdcomppath++; 2386 lim++; 2387 } 2388 } 2389 p = strtok(cdcomppath, "/"); 2390 while (p) { 2391 switch(*p) { 2392 case '.': 2393 if (p[1] == '.' && p[2] == '\0') { 2394 while (new > lim) { 2395 STUNPUTC(new); 2396 if (new[-1] == '/') 2397 break; 2398 } 2399 break; 2400 } else if (p[1] == '\0') 2401 break; 2402 /* fall through */ 2403 default: 2404 new = stputs(p, new); 2405 USTPUTC('/', new); 2406 } 2407 p = strtok(0, "/"); 2408 } 2409 if (new > lim) 2410 STUNPUTC(new); 2411 *new = 0; 2412 return stackblock(); 2413 } 2414 2415 /* 2416 * Actually do the chdir. We also call hashcd to let the routines in exec.c 2417 * know that the current directory has changed. 2418 */ 2419 2420 static int 2421 docd(const char *dest, int flags) 2422 { 2423 const char *dir = 0; 2424 int err; 2425 2426 TRACE(("docd(\"%s\", %d) called\n", dest, flags)); 2427 2428 INTOFF; 2429 if (!(flags & CD_PHYSICAL)) { 2430 dir = updatepwd(dest); 2431 if (dir) 2432 dest = dir; 2433 } 2434 err = chdir(dest); 2435 if (err) 2436 goto out; 2437 setpwd(dir, 1); 2438 hashcd(); 2439 out: 2440 INTON; 2441 return err; 2442 } 2443 2444 /* 2445 * Find out what the current directory is. If we already know the current 2446 * directory, this routine returns immediately. 2447 */ 2448 static inline char * 2449 getpwd(void) 2450 { 2451 char *dir = getcwd(0, 0); 2452 return dir ? dir : nullstr; 2453 } 2454 2455 static int 2456 pwdcmd(int argc, char **argv) 2457 { 2458 int flags; 2459 const char *dir = curdir; 2460 2461 flags = cdopt(); 2462 if (flags) { 2463 if (physdir == nullstr) 2464 setpwd(dir, 0); 2465 dir = physdir; 2466 } 2467 out1fmt(snlfmt, dir); 2468 return 0; 2469 } 2470 2471 static void 2472 setpwd(const char *val, int setold) 2473 { 2474 char *oldcur, *dir; 2475 2476 oldcur = dir = curdir; 2477 2478 if (setold) { 2479 setvar("OLDPWD", oldcur, VEXPORT); 2480 } 2481 INTOFF; 2482 if (physdir != nullstr) { 2483 if (physdir != oldcur) 2484 free(physdir); 2485 physdir = nullstr; 2486 } 2487 if (oldcur == val || !val) { 2488 char *s = getpwd(); 2489 physdir = s; 2490 if (!val) 2491 dir = s; 2492 } else 2493 dir = savestr(val); 2494 if (oldcur != dir && oldcur != nullstr) { 2495 free(oldcur); 2496 } 2497 curdir = dir; 2498 INTON; 2499 setvar("PWD", dir, VEXPORT); 2500 } 2501 2502 /* error.c */ 2503 2504 /* 2505 * Errors and exceptions. 2506 */ 2507 2508 /* 2509 * Code to handle exceptions in C. 2510 */ 2511 2512 2513 2514 static void exverror(int, const char *, va_list) 2515 ATTRIBUTE_NORETURN; 2516 2517 /* 2518 * Called to raise an exception. Since C doesn't include exceptions, we 2519 * just do a longjmp to the exception handler. The type of exception is 2520 * stored in the global variable "exception". 2521 */ 2522 2523 static void 2524 exraise(int e) 2525 { 2526 #ifdef DEBUG 2527 if (handler == NULL) 2528 abort(); 2529 #endif 2530 INTOFF; 2531 2532 exception = e; 2533 longjmp(handler->loc, 1); 2534 } 2535 2536 2537 /* 2538 * Called from trap.c when a SIGINT is received. (If the user specifies 2539 * that SIGINT is to be trapped or ignored using the trap builtin, then 2540 * this routine is not called.) Suppressint is nonzero when interrupts 2541 * are held using the INTOFF macro. (The test for iflag is just 2542 * defensive programming.) 2543 */ 2544 2545 static void 2546 onint(void) { 2547 int i; 2548 2549 intpending = 0; 2550 #if 0 2551 /* comment by vodz: its strange for me, this programm don`t use other 2552 signal block */ 2553 sigsetmask(0); 2554 #endif 2555 i = EXSIG; 2556 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 2557 if (!(rootshell && iflag)) { 2558 signal(SIGINT, SIG_DFL); 2559 raise(SIGINT); 2560 } 2561 i = EXINT; 2562 } 2563 exraise(i); 2564 /* NOTREACHED */ 2565 } 2566 2567 static void 2568 exvwarning(const char *msg, va_list ap) 2569 { 2570 FILE *errs; 2571 2572 errs = stderr; 2573 fprintf(errs, "%s: ", arg0); 2574 if (commandname) { 2575 const char *fmt = (!iflag || parsefile->fd) ? 2576 "%s: %d: " : "%s: "; 2577 fprintf(errs, fmt, commandname, startlinno); 2578 } 2579 vfprintf(errs, msg, ap); 2580 outcslow('\n', errs); 2581 } 2582 2583 /* 2584 * Exverror is called to raise the error exception. If the second argument 2585 * is not NULL then error prints an error message using printf style 2586 * formatting. It then raises the error exception. 2587 */ 2588 static void 2589 exverror(int cond, const char *msg, va_list ap) 2590 { 2591 #ifdef DEBUG 2592 if (msg) { 2593 TRACE(("exverror(%d, \"", cond)); 2594 TRACEV((msg, ap)); 2595 TRACE(("\") pid=%d\n", getpid())); 2596 } else 2597 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); 2598 if (msg) 2599 #endif 2600 exvwarning(msg, ap); 2601 2602 flushall(); 2603 exraise(cond); 2604 /* NOTREACHED */ 2605 } 2606 2607 2608 static void 2609 sh_error(const char *msg, ...) 2610 { 2611 va_list ap; 2612 2613 va_start(ap, msg); 2614 exverror(EXERROR, msg, ap); 2615 /* NOTREACHED */ 2616 va_end(ap); 2617 } 2618 2619 2620 static void 2621 exerror(int cond, const char *msg, ...) 2622 { 2623 va_list ap; 2624 2625 va_start(ap, msg); 2626 exverror(cond, msg, ap); 2627 /* NOTREACHED */ 2628 va_end(ap); 2629 } 2630 2631 /* 2632 * error/warning routines for external builtins 2633 */ 2634 2635 static void 2636 sh_warnx(const char *fmt, ...) 2637 { 2638 va_list ap; 2639 2640 va_start(ap, fmt); 2641 exvwarning(fmt, ap); 2642 va_end(ap); 2643 } 2644 2645 2646 /* 2647 * Return a string describing an error. The returned string may be a 2648 * pointer to a static buffer that will be overwritten on the next call. 2649 * Action describes the operation that got the error. 2650 */ 2651 2652 static const char * 2653 errmsg(int e, const char *em) 2654 { 2655 if(e == ENOENT || e == ENOTDIR) { 2656 2657 return em; 2658 } 2659 return strerror(e); 2660 } 2661 2662 2663 /* eval.c */ 2664 2665 /* 2666 * Evaluate a command. 2667 */ 2668 2669 /* flags in argument to evaltree */ 2670 #define EV_EXIT 01 /* exit after evaluating tree */ 2671 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 2672 #define EV_BACKCMD 04 /* command executing within back quotes */ 2673 2674 2675 static void evalloop(union node *, int); 2676 static void evalfor(union node *, int); 2677 static void evalcase(union node *, int); 2678 static void evalsubshell(union node *, int); 2679 static void expredir(union node *); 2680 static void evalpipe(union node *, int); 2681 static void evalcommand(union node *, int); 2682 static int evalbltin(const struct builtincmd *, int, char **); 2683 static int evalfun(struct funcnode *, int, char **, int); 2684 static void prehash(union node *); 2685 static int bltincmd(int, char **); 2686 2687 2688 static const struct builtincmd bltin = { 2689 "\0\0", bltincmd 2690 }; 2691 2692 2693 /* 2694 * Called to reset things after an exception. 2695 */ 2696 2697 /* 2698 * The eval command. 2699 */ 2700 2701 static int 2702 evalcmd(int argc, char **argv) 2703 { 2704 char *p; 2705 char *concat; 2706 char **ap; 2707 2708 if (argc > 1) { 2709 p = argv[1]; 2710 if (argc > 2) { 2711 STARTSTACKSTR(concat); 2712 ap = argv + 2; 2713 for (;;) { 2714 concat = stputs(p, concat); 2715 if ((p = *ap++) == NULL) 2716 break; 2717 STPUTC(' ', concat); 2718 } 2719 STPUTC('\0', concat); 2720 p = grabstackstr(concat); 2721 } 2722 evalstring(p, ~SKIPEVAL); 2723 2724 } 2725 return exitstatus; 2726 } 2727 2728 2729 /* 2730 * Execute a command or commands contained in a string. 2731 */ 2732 2733 static int 2734 evalstring(char *s, int mask) 2735 { 2736 union node *n; 2737 struct stackmark smark; 2738 int skip; 2739 2740 setinputstring(s); 2741 setstackmark(&smark); 2742 2743 skip = 0; 2744 while ((n = parsecmd(0)) != NEOF) { 2745 evaltree(n, 0); 2746 popstackmark(&smark); 2747 skip = evalskip; 2748 if (skip) 2749 break; 2750 } 2751 popfile(); 2752 2753 skip &= mask; 2754 evalskip = skip; 2755 return skip; 2756 } 2757 2758 2759 2760 /* 2761 * Evaluate a parse tree. The value is left in the global variable 2762 * exitstatus. 2763 */ 2764 2765 static void 2766 evaltree(union node *n, int flags) 2767 { 2768 int checkexit = 0; 2769 void (*evalfn)(union node *, int); 2770 unsigned isor; 2771 int status; 2772 if (n == NULL) { 2773 TRACE(("evaltree(NULL) called\n")); 2774 goto out; 2775 } 2776 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 2777 getpid(), n, n->type, flags)); 2778 switch (n->type) { 2779 default: 2780 #ifdef DEBUG 2781 out1fmt("Node type = %d\n", n->type); 2782 fflush(stdout); 3226 tsig = S_RESET; /* force to be set */ 3227 } 3228 } 3229 if (tsig == S_HARD_IGN || tsig == action) 3230 return; 3231 switch (action) { 3232 case S_CATCH: 3233 act.sa_handler = onsig; 2783 3234 break; 2784 #endif 2785 case NNOT: 2786 evaltree(n->nnot.com, EV_TESTED); 2787 status = !exitstatus; 2788 goto setstatus; 2789 case NREDIR: 2790 expredir(n->nredir.redirect); 2791 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 2792 if (!status) { 2793 evaltree(n->nredir.n, flags & EV_TESTED); 2794 status = exitstatus; 2795 } 2796 popredir(0); 2797 goto setstatus; 2798 case NCMD: 2799 evalfn = evalcommand; 2800 checkexit: 2801 if (eflag && !(flags & EV_TESTED)) 2802 checkexit = ~0; 2803 goto calleval; 2804 case NFOR: 2805 evalfn = evalfor; 2806 goto calleval; 2807 case NWHILE: 2808 case NUNTIL: 2809 evalfn = evalloop; 2810 goto calleval; 2811 case NSUBSHELL: 2812 case NBACKGND: 2813 evalfn = evalsubshell; 2814 goto calleval; 2815 case NPIPE: 2816 evalfn = evalpipe; 2817 goto checkexit; 2818 case NCASE: 2819 evalfn = evalcase; 2820 goto calleval; 2821 case NAND: 2822 case NOR: 2823 case NSEMI: 2824 #if NAND + 1 != NOR 2825 #error NAND + 1 != NOR 2826 #endif 2827 #if NOR + 1 != NSEMI 2828 #error NOR + 1 != NSEMI 2829 #endif 2830 isor = n->type - NAND; 2831 evaltree( 2832 n->nbinary.ch1, 2833 (flags | ((isor >> 1) - 1)) & EV_TESTED 2834 ); 2835 if (!exitstatus == isor) 2836 break; 2837 if (!evalskip) { 2838 n = n->nbinary.ch2; 2839 evaln: 2840 evalfn = evaltree; 2841 calleval: 2842 evalfn(n, flags); 2843 break; 2844 } 2845 break; 2846 case NIF: 2847 evaltree(n->nif.test, EV_TESTED); 2848 if (evalskip) 2849 break; 2850 if (exitstatus == 0) { 2851 n = n->nif.ifpart; 2852 goto evaln; 2853 } else if (n->nif.elsepart) { 2854 n = n->nif.elsepart; 2855 goto evaln; 2856 } 2857 goto success; 2858 case NDEFUN: 2859 defun(n->narg.text, n->narg.next); 2860 success: 2861 status = 0; 2862 setstatus: 2863 exitstatus = status; 2864 break; 2865 } 2866 out: 2867 if ((checkexit & exitstatus)) 2868 evalskip |= SKIPEVAL; 2869 else if (pendingsigs && dotrap()) 2870 goto exexit; 2871 2872 if (flags & EV_EXIT) { 2873 exexit: 2874 exraise(EXEXIT); 2875 } 2876 } 2877 2878 2879 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 2880 static 2881 #endif 2882 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 2883 2884 2885 static void 2886 evalloop(union node *n, int flags) 2887 { 2888 int status; 2889 2890 loopnest++; 2891 status = 0; 2892 flags &= EV_TESTED; 2893 for (;;) { 2894 int i; 2895 2896 evaltree(n->nbinary.ch1, EV_TESTED); 2897 if (evalskip) { 2898 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 2899 evalskip = 0; 2900 continue; 2901 } 2902 if (evalskip == SKIPBREAK && --skipcount <= 0) 2903 evalskip = 0; 2904 break; 2905 } 2906 i = exitstatus; 2907 if (n->type != NWHILE) 2908 i = !i; 2909 if (i != 0) 2910 break; 2911 evaltree(n->nbinary.ch2, flags); 2912 status = exitstatus; 2913 if (evalskip) 2914 goto skipping; 2915 } 2916 loopnest--; 2917 exitstatus = status; 2918 } 2919 2920 2921 2922 static void 2923 evalfor(union node *n, int flags) 2924 { 2925 struct arglist arglist; 2926 union node *argp; 2927 struct strlist *sp; 2928 struct stackmark smark; 2929 2930 setstackmark(&smark); 2931 arglist.lastp = &arglist.list; 2932 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 2933 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 2934 /* XXX */ 2935 if (evalskip) 2936 goto out; 2937 } 2938 *arglist.lastp = NULL; 2939 2940 exitstatus = 0; 2941 loopnest++; 2942 flags &= EV_TESTED; 2943 for (sp = arglist.list ; sp ; sp = sp->next) { 2944 setvar(n->nfor.var, sp->text, 0); 2945 evaltree(n->nfor.body, flags); 2946 if (evalskip) { 2947 if (evalskip == SKIPCONT && --skipcount <= 0) { 2948 evalskip = 0; 2949 continue; 2950 } 2951 if (evalskip == SKIPBREAK && --skipcount <= 0) 2952 evalskip = 0; 2953 break; 2954 } 2955 } 2956 loopnest--; 2957 out: 2958 popstackmark(&smark); 2959 } 2960 2961 2962 2963 static void 2964 evalcase(union node *n, int flags) 2965 { 2966 union node *cp; 2967 union node *patp; 2968 struct arglist arglist; 2969 struct stackmark smark; 2970 2971 setstackmark(&smark); 2972 arglist.lastp = &arglist.list; 2973 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 2974 exitstatus = 0; 2975 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 2976 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 2977 if (casematch(patp, arglist.list->text)) { 2978 if (evalskip == 0) { 2979 evaltree(cp->nclist.body, flags); 2980 } 2981 goto out; 2982 } 2983 } 2984 } 2985 out: 2986 popstackmark(&smark); 2987 } 2988 2989 2990 2991 /* 2992 * Kick off a subshell to evaluate a tree. 2993 */ 2994 2995 static void 2996 evalsubshell(union node *n, int flags) 2997 { 2998 struct job *jp; 2999 int backgnd = (n->type == NBACKGND); 3000 int status; 3001 3002 expredir(n->nredir.redirect); 3003 if (!backgnd && flags & EV_EXIT && !trap[0]) 3004 goto nofork; 3005 INTOFF; 3006 jp = makejob(n, 1); 3007 if (forkshell(jp, n, backgnd) == 0) { 3008 INTON; 3009 flags |= EV_EXIT; 3010 if (backgnd) 3011 flags &=~ EV_TESTED; 3012 nofork: 3013 redirect(n->nredir.redirect, 0); 3014 evaltreenr(n->nredir.n, flags); 3015 /* never returns */ 3016 } 3017 status = 0; 3018 if (! backgnd) 3019 status = waitforjob(jp); 3020 exitstatus = status; 3021 INTON; 3022 } 3023 3024 3025 3026 /* 3027 * Compute the names of the files in a redirection list. 3028 */ 3029 3030 static void 3031 expredir(union node *n) 3032 { 3033 union node *redir; 3034 3035 for (redir = n ; redir ; redir = redir->nfile.next) { 3036 struct arglist fn; 3037 fn.lastp = &fn.list; 3038 switch (redir->type) { 3039 case NFROMTO: 3040 case NFROM: 3041 case NTO: 3042 case NCLOBBER: 3043 case NAPPEND: 3044 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 3045 redir->nfile.expfname = fn.list->text; 3046 break; 3047 case NFROMFD: 3048 case NTOFD: 3049 if (redir->ndup.vname) { 3050 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 3051 fixredir(redir, fn.list->text, 1); 3052 } 3053 break; 3054 } 3055 } 3056 } 3057 3058 3059 3060 /* 3061 * Evaluate a pipeline. All the processes in the pipeline are children 3062 * of the process creating the pipeline. (This differs from some versions 3063 * of the shell, which make the last process in a pipeline the parent 3064 * of all the rest.) 3065 */ 3066 3067 static void 3068 evalpipe(union node *n, int flags) 3069 { 3070 struct job *jp; 3071 struct nodelist *lp; 3072 int pipelen; 3073 int prevfd; 3074 int pip[2]; 3075 3076 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 3077 pipelen = 0; 3078 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 3079 pipelen++; 3080 flags |= EV_EXIT; 3081 INTOFF; 3082 jp = makejob(n, pipelen); 3083 prevfd = -1; 3084 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 3085 prehash(lp->n); 3086 pip[1] = -1; 3087 if (lp->next) { 3088 if (pipe(pip) < 0) { 3089 close(prevfd); 3090 sh_error("Pipe call failed"); 3091 } 3092 } 3093 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 3094 INTON; 3095 if (pip[1] >= 0) { 3096 close(pip[0]); 3097 } 3098 if (prevfd > 0) { 3099 dup2(prevfd, 0); 3100 close(prevfd); 3101 } 3102 if (pip[1] > 1) { 3103 dup2(pip[1], 1); 3104 close(pip[1]); 3105 } 3106 evaltreenr(lp->n, flags); 3107 /* never returns */ 3108 } 3109 if (prevfd >= 0) 3110 close(prevfd); 3111 prevfd = pip[0]; 3112 close(pip[1]); 3113 } 3114 if (n->npipe.backgnd == 0) { 3115 exitstatus = waitforjob(jp); 3116 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 3117 } 3118 INTON; 3119 } 3120 3121 3122 3123 /* 3124 * Execute a command inside back quotes. If it's a builtin command, we 3125 * want to save its output in a block obtained from malloc. Otherwise 3126 * we fork off a subprocess and get the output of the command via a pipe. 3127 * Should be called with interrupts off. 3128 */ 3129 3130 static void 3131 evalbackcmd(union node *n, struct backcmd *result) 3132 { 3133 int saveherefd; 3134 3135 result->fd = -1; 3136 result->buf = NULL; 3137 result->nleft = 0; 3138 result->jp = NULL; 3139 if (n == NULL) { 3140 goto out; 3141 } 3142 3143 saveherefd = herefd; 3144 herefd = -1; 3145 3146 { 3147 int pip[2]; 3148 struct job *jp; 3149 3150 if (pipe(pip) < 0) 3151 sh_error("Pipe call failed"); 3152 jp = makejob(n, 1); 3153 if (forkshell(jp, n, FORK_NOJOB) == 0) { 3154 FORCEINTON; 3155 close(pip[0]); 3156 if (pip[1] != 1) { 3157 close(1); 3158 copyfd(pip[1], 1); 3159 close(pip[1]); 3160 } 3161 eflag = 0; 3162 evaltreenr(n, EV_EXIT); 3163 /* NOTREACHED */ 3164 } 3165 close(pip[1]); 3166 result->fd = pip[0]; 3167 result->jp = jp; 3168 } 3169 herefd = saveherefd; 3170 out: 3171 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 3172 result->fd, result->buf, result->nleft, result->jp)); 3173 } 3174 3175 #ifdef CONFIG_ASH_CMDCMD 3176 static inline char ** 3177 parse_command_args(char **argv, const char **path) 3178 { 3179 char *cp, c; 3180 3181 for (;;) { 3182 cp = *++argv; 3183 if (!cp) 3184 return 0; 3185 if (*cp++ != '-') 3186 break; 3187 if (!(c = *cp++)) 3188 break; 3189 if (c == '-' && !*cp) { 3190 argv++; 3191 break; 3192 } 3193 do { 3194 switch (c) { 3195 case 'p': 3196 *path = defpath; 3197 break; 3198 default: 3199 /* run 'typecmd' for other options */ 3200 return 0; 3201 } 3202 } while ((c = *cp++)); 3203 } 3204 return argv; 3205 } 3206 #endif 3207 3208 static inline int 3209 isassignment(const char *p) 3210 { 3211 const char *q = endofname(p); 3212 if (p == q) 3213 return 0; 3214 return *q == '='; 3215 } 3216 3217 #ifdef CONFIG_ASH_EXPAND_PRMT 3218 static const char *expandstr(const char *ps); 3219 #else 3220 #define expandstr(s) s 3221 #endif 3222 3223 /* 3224 * Execute a simple command. 3225 */ 3226 3227 static void 3228 evalcommand(union node *cmd, int flags) 3229 { 3230 struct stackmark smark; 3231 union node *argp; 3232 struct arglist arglist; 3233 struct arglist varlist; 3234 char **argv; 3235 int argc; 3236 const struct strlist *sp; 3237 struct cmdentry cmdentry; 3238 struct job *jp; 3239 char *lastarg; 3240 const char *path; 3241 int spclbltin; 3242 int cmd_is_exec; 3243 int status; 3244 char **nargv; 3245 struct builtincmd *bcmd; 3246 int pseudovarflag = 0; 3247 3248 /* First expand the arguments. */ 3249 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 3250 setstackmark(&smark); 3251 back_exitstatus = 0; 3252 3253 cmdentry.cmdtype = CMDBUILTIN; 3254 cmdentry.u.cmd = &bltin; 3255 varlist.lastp = &varlist.list; 3256 *varlist.lastp = NULL; 3257 arglist.lastp = &arglist.list; 3258 *arglist.lastp = NULL; 3259 3260 argc = 0; 3261 if (cmd->ncmd.args) 3262 { 3263 bcmd = find_builtin(cmd->ncmd.args->narg.text); 3264 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 3265 } 3266 3267 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 3268 struct strlist **spp; 3269 3270 spp = arglist.lastp; 3271 if (pseudovarflag && isassignment(argp->narg.text)) 3272 expandarg(argp, &arglist, EXP_VARTILDE); 3273 else 3274 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 3275 3276 for (sp = *spp; sp; sp = sp->next) 3277 argc++; 3278 } 3279 3280 argv = nargv = stalloc(sizeof (char *) * (argc + 1)); 3281 for (sp = arglist.list ; sp ; sp = sp->next) { 3282 TRACE(("evalcommand arg: %s\n", sp->text)); 3283 *nargv++ = sp->text; 3284 } 3285 *nargv = NULL; 3286 3287 lastarg = NULL; 3288 if (iflag && funcnest == 0 && argc > 0) 3289 lastarg = nargv[-1]; 3290 3291 preverrout_fd = 2; 3292 expredir(cmd->ncmd.redirect); 3293 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); 3294 3295 path = vpath.text; 3296 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 3297 struct strlist **spp; 3298 char *p; 3299 3300 spp = varlist.lastp; 3301 expandarg(argp, &varlist, EXP_VARTILDE); 3302 3303 /* 3304 * Modify the command lookup path, if a PATH= assignment 3305 * is present 3306 */ 3307 p = (*spp)->text; 3308 if (varequal(p, path)) 3309 path = p; 3310 } 3311 3312 /* Print the command if xflag is set. */ 3313 if (xflag) { 3314 int n; 3315 const char *p = " %s"; 3316 3317 p++; 3318 dprintf(preverrout_fd, p, expandstr(ps4val())); 3319 3320 sp = varlist.list; 3321 for(n = 0; n < 2; n++) { 3322 while (sp) { 3323 dprintf(preverrout_fd, p, sp->text); 3324 sp = sp->next; 3325 if(*p == '%') { 3326 p--; 3327 } 3328 } 3329 sp = arglist.list; 3330 } 3331 bb_full_write(preverrout_fd, "\n", 1); 3332 } 3333 3334 cmd_is_exec = 0; 3335 spclbltin = -1; 3336 3337 /* Now locate the command. */ 3338 if (argc) { 3339 const char *oldpath; 3340 int cmd_flag = DO_ERR; 3341 3342 path += 5; 3343 oldpath = path; 3344 for (;;) { 3345 find_command(argv[0], &cmdentry, cmd_flag, path); 3346 if (cmdentry.cmdtype == CMDUNKNOWN) { 3347 status = 127; 3348 flusherr(); 3349 goto bail; 3350 } 3351 3352 /* implement bltin and command here */ 3353 if (cmdentry.cmdtype != CMDBUILTIN) 3354 break; 3355 if (spclbltin < 0) 3356 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 3357 if (cmdentry.u.cmd == EXECCMD) 3358 cmd_is_exec++; 3359 #ifdef CONFIG_ASH_CMDCMD 3360 if (cmdentry.u.cmd == COMMANDCMD) { 3361 3362 path = oldpath; 3363 nargv = parse_command_args(argv, &path); 3364 if (!nargv) 3365 break; 3366 argc -= nargv - argv; 3367 argv = nargv; 3368 cmd_flag |= DO_NOFUNC; 3369 } else 3370 #endif 3371 break; 3372 } 3373 } 3374 3375 if (status) { 3376 /* We have a redirection error. */ 3377 if (spclbltin > 0) 3378 exraise(EXERROR); 3379 bail: 3380 exitstatus = status; 3381 goto out; 3382 } 3383 3384 /* Execute the command. */ 3385 switch (cmdentry.cmdtype) { 3386 default: 3387 /* Fork off a child process if necessary. */ 3388 if (!(flags & EV_EXIT) || trap[0]) { 3389 INTOFF; 3390 jp = makejob(cmd, 1); 3391 if (forkshell(jp, cmd, FORK_FG) != 0) { 3392 exitstatus = waitforjob(jp); 3393 INTON; 3394 break; 3395 } 3396 FORCEINTON; 3397 } 3398 listsetvar(varlist.list, VEXPORT|VSTACK); 3399 shellexec(argv, path, cmdentry.u.index); 3400 /* NOTREACHED */ 3401 3402 case CMDBUILTIN: 3403 cmdenviron = varlist.list; 3404 if (cmdenviron) { 3405 struct strlist *list = cmdenviron; 3406 int i = VNOSET; 3407 if (spclbltin > 0 || argc == 0) { 3408 i = 0; 3409 if (cmd_is_exec && argc > 1) 3410 i = VEXPORT; 3411 } 3412 listsetvar(list, i); 3413 } 3414 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 3415 int exit_status; 3416 int i, j; 3417 3418 i = exception; 3419 if (i == EXEXIT) 3420 goto raise; 3421 3422 exit_status = 2; 3423 j = 0; 3424 if (i == EXINT) 3425 j = SIGINT; 3426 if (i == EXSIG) 3427 j = pendingsigs; 3428 if (j) 3429 exit_status = j + 128; 3430 exitstatus = exit_status; 3431 3432 if (i == EXINT || spclbltin > 0) { 3433 raise: 3434 longjmp(handler->loc, 1); 3435 } 3436 FORCEINTON; 3437 } 3438 break; 3439 3440 case CMDFUNCTION: 3441 listsetvar(varlist.list, 0); 3442 if (evalfun(cmdentry.u.func, argc, argv, flags)) 3443 goto raise; 3444 break; 3445 } 3446 3447 out: 3448 popredir(cmd_is_exec); 3449 if (lastarg) 3450 /* dsl: I think this is intended to be used to support 3451 * '_' in 'vi' command mode during line editing... 3452 * However I implemented that within libedit itself. 3453 */ 3454 setvar("_", lastarg, 0); 3455 popstackmark(&smark); 3456 } 3457 3458 static int 3459 evalbltin(const struct builtincmd *cmd, int argc, char **argv) { 3460 char *volatile savecmdname; 3461 struct jmploc *volatile savehandler; 3462 struct jmploc jmploc; 3463 int i; 3464 3465 savecmdname = commandname; 3466 if ((i = setjmp(jmploc.loc))) 3467 goto cmddone; 3468 savehandler = handler; 3469 handler = &jmploc; 3470 commandname = argv[0]; 3471 argptr = argv + 1; 3472 optptr = NULL; /* initialize nextopt */ 3473 exitstatus = (*cmd->builtin)(argc, argv); 3474 flushall(); 3475 cmddone: 3476 exitstatus |= ferror(stdout); 3477 clearerr(stdout); 3478 commandname = savecmdname; 3479 exsig = 0; 3480 handler = savehandler; 3481 3482 return i; 3483 } 3484 3485 static int 3486 evalfun(struct funcnode *func, int argc, char **argv, int flags) 3487 { 3488 volatile struct shparam saveparam; 3489 struct localvar *volatile savelocalvars; 3490 struct jmploc *volatile savehandler; 3491 struct jmploc jmploc; 3492 int e; 3493 3494 saveparam = shellparam; 3495 savelocalvars = localvars; 3496 if ((e = setjmp(jmploc.loc))) { 3497 goto funcdone; 3498 } 3499 INTOFF; 3500 savehandler = handler; 3501 handler = &jmploc; 3502 localvars = NULL; 3503 shellparam.malloc = 0; 3504 func->count++; 3505 funcnest++; 3506 INTON; 3507 shellparam.nparam = argc - 1; 3508 shellparam.p = argv + 1; 3509 #ifdef CONFIG_ASH_GETOPTS 3510 shellparam.optind = 1; 3511 shellparam.optoff = -1; 3512 #endif 3513 evaltree(&func->n, flags & EV_TESTED); 3514 funcdone: 3515 INTOFF; 3516 funcnest--; 3517 freefunc(func); 3518 poplocalvars(); 3519 localvars = savelocalvars; 3520 freeparam(&shellparam); 3521 shellparam = saveparam; 3522 handler = savehandler; 3523 INTON; 3524 evalskip &= ~SKIPFUNC; 3525 return e; 3526 } 3527 3528 3529 static inline int 3530 goodname(const char *p) 3531 { 3532 return !*endofname(p); 3533 } 3534 3535 /* 3536 * Search for a command. This is called before we fork so that the 3537 * location of the command will be available in the parent as well as 3538 * the child. The check for "goodname" is an overly conservative 3539 * check that the name will not be subject to expansion. 3540 */ 3541 3542 static void 3543 prehash(union node *n) 3544 { 3545 struct cmdentry entry; 3546 3547 if (n->type == NCMD && n->ncmd.args) 3548 if (goodname(n->ncmd.args->narg.text)) 3549 find_command(n->ncmd.args->narg.text, &entry, 0, 3550 pathval()); 3551 } 3552 3553 3554 3555 /* 3556 * Builtin commands. Builtin commands whose functions are closely 3557 * tied to evaluation are implemented here. 3558 */ 3559 3560 /* 3561 * No command given. 3562 */ 3563 3564 static int 3565 bltincmd(int argc, char **argv) 3566 { 3567 /* 3568 * Preserve exitstatus of a previous possible redirection 3569 * as POSIX mandates 3570 */ 3571 return back_exitstatus; 3572 } 3573 3574 3575 /* 3576 * Handle break and continue commands. Break, continue, and return are 3577 * all handled by setting the evalskip flag. The evaluation routines 3578 * above all check this flag, and if it is set they start skipping 3579 * commands rather than executing them. The variable skipcount is 3580 * the number of loops to break/continue, or the number of function 3581 * levels to return. (The latter is always 1.) It should probably 3582 * be an error to break out of more loops than exist, but it isn't 3583 * in the standard shell so we don't make it one here. 3584 */ 3585 3586 static int 3587 breakcmd(int argc, char **argv) 3588 { 3589 int n = argc > 1 ? number(argv[1]) : 1; 3590 3591 if (n <= 0) 3592 sh_error(illnum, argv[1]); 3593 if (n > loopnest) 3594 n = loopnest; 3595 if (n > 0) { 3596 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 3597 skipcount = n; 3598 } 3599 return 0; 3600 } 3601 3602 3603 /* 3604 * The return command. 3605 */ 3606 3607 static int 3608 returncmd(int argc, char **argv) 3609 { 3610 /* 3611 * If called outside a function, do what ksh does; 3612 * skip the rest of the file. 3613 */ 3614 evalskip = funcnest ? SKIPFUNC : SKIPFILE; 3615 return argv[1] ? number(argv[1]) : exitstatus; 3616 } 3617 3618 3619 static int 3620 falsecmd(int argc, char **argv) 3621 { 3622 return 1; 3623 } 3624 3625 3626 static int 3627 truecmd(int argc, char **argv) 3628 { 3629 return 0; 3630 } 3631 3632 3633 static int 3634 execcmd(int argc, char **argv) 3635 { 3636 if (argc > 1) { 3637 iflag = 0; /* exit on error */ 3638 mflag = 0; 3639 optschanged(); 3640 shellexec(argv + 1, pathval(), 0); 3641 } 3642 return 0; 3643 } 3644 3645 3646 /* exec.c */ 3647 3648 /* 3649 * When commands are first encountered, they are entered in a hash table. 3650 * This ensures that a full path search will not have to be done for them 3651 * on each invocation. 3652 * 3653 * We should investigate converting to a linear search, even though that 3654 * would make the command name "hash" a misnomer. 3655 */ 3656 3657 #define CMDTABLESIZE 31 /* should be prime */ 3658 #define ARB 1 /* actual size determined at run time */ 3659 3660 3661 3662 struct tblentry { 3663 struct tblentry *next; /* next entry in hash chain */ 3664 union param param; /* definition of builtin function */ 3665 short cmdtype; /* index identifying command */ 3666 char rehash; /* if set, cd done since entry created */ 3667 char cmdname[ARB]; /* name of command */ 3668 }; 3669 3670 3671 static struct tblentry *cmdtable[CMDTABLESIZE]; 3672 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 3673 3674 3675 static void tryexec(char *, char **, char **); 3676 static void clearcmdentry(int); 3677 static struct tblentry *cmdlookup(const char *, int); 3678 static void delete_cmd_entry(void); 3679 3680 3681 /* 3682 * Exec a program. Never returns. If you change this routine, you may 3683 * have to change the find_command routine as well. 3684 */ 3685 3686 static void 3687 shellexec(char **argv, const char *path, int idx) 3688 { 3689 char *cmdname; 3690 int e; 3691 char **envp; 3692 int exerrno; 3693 3694 clearredir(1); 3695 envp = environment(); 3696 if (strchr(argv[0], '/') != NULL 3697 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3698 || find_applet_by_name(argv[0]) 3699 #endif 3700 ) { 3701 tryexec(argv[0], argv, envp); 3702 e = errno; 3703 } else { 3704 e = ENOENT; 3705 while ((cmdname = padvance(&path, argv[0])) != NULL) { 3706 if (--idx < 0 && pathopt == NULL) { 3707 tryexec(cmdname, argv, envp); 3708 if (errno != ENOENT && errno != ENOTDIR) 3709 e = errno; 3710 } 3711 stunalloc(cmdname); 3712 } 3713 } 3714 3715 /* Map to POSIX errors */ 3716 switch (e) { 3717 case EACCES: 3718 exerrno = 126; 3719 break; 3720 case ENOENT: 3721 exerrno = 127; 3235 case S_IGN: 3236 act.sa_handler = SIG_IGN; 3722 3237 break; 3723 3238 default: 3724 exerrno = 2; 3725 break; 3726 } 3727 exitstatus = exerrno; 3728 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", 3729 argv[0], e, suppressint )); 3730 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); 3731 /* NOTREACHED */ 3732 } 3733 3734 3735 static void 3736 tryexec(char *cmd, char **argv, char **envp) 3737 { 3738 int repeated = 0; 3739 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3740 if(find_applet_by_name(cmd) != NULL) { 3741 /* re-exec ourselves with the new arguments */ 3742 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp); 3743 /* If they called chroot or otherwise made the binary no longer 3744 * executable, fall through */ 3745 } 3746 #endif 3747 3748 repeat: 3749 #ifdef SYSV 3750 do { 3751 execve(cmd, argv, envp); 3752 } while (errno == EINTR); 3753 #else 3754 execve(cmd, argv, envp); 3755 #endif 3756 if (repeated++) { 3757 ckfree(argv); 3758 } else if (errno == ENOEXEC) { 3759 char **ap; 3760 char **new; 3761 3762 for (ap = argv; *ap; ap++) 3763 ; 3764 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); 3765 ap[1] = cmd; 3766 *ap = cmd = (char *)DEFAULT_SHELL; 3767 ap += 2; 3768 argv++; 3769 while ((*ap++ = *argv++)) 3770 ; 3771 argv = new; 3772 goto repeat; 3773 } 3774 } 3775 3776 3777 3778 /* 3779 * Do a path search. The variable path (passed by reference) should be 3780 * set to the start of the path before the first call; padvance will update 3781 * this value as it proceeds. Successive calls to padvance will return 3782 * the possible path expansions in sequence. If an option (indicated by 3783 * a percent sign) appears in the path entry then the global variable 3784 * pathopt will be set to point to it; otherwise pathopt will be set to 3785 * NULL. 3786 */ 3787 3788 static char * 3789 padvance(const char **path, const char *name) 3790 { 3791 const char *p; 3792 char *q; 3793 const char *start; 3794 size_t len; 3795 3796 if (*path == NULL) 3797 return NULL; 3798 start = *path; 3799 for (p = start ; *p && *p != ':' && *p != '%' ; p++); 3800 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 3801 while (stackblocksize() < len) 3802 growstackblock(); 3803 q = stackblock(); 3804 if (p != start) { 3805 memcpy(q, start, p - start); 3806 q += p - start; 3807 *q++ = '/'; 3808 } 3809 strcpy(q, name); 3810 pathopt = NULL; 3811 if (*p == '%') { 3812 pathopt = ++p; 3813 while (*p && *p != ':') p++; 3814 } 3815 if (*p == ':') 3816 *path = p + 1; 3817 else 3818 *path = NULL; 3819 return stalloc(len); 3820 } 3821 3822 3823 /*** Command hashing code ***/ 3824 3825 static void 3826 printentry(struct tblentry *cmdp) 3827 { 3828 int idx; 3829 const char *path; 3830 char *name; 3831 3832 idx = cmdp->param.index; 3833 path = pathval(); 3834 do { 3835 name = padvance(&path, cmdp->cmdname); 3836 stunalloc(name); 3837 } while (--idx >= 0); 3838 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 3839 } 3840 3841 3842 static int 3843 hashcmd(int argc, char **argv) 3844 { 3845 struct tblentry **pp; 3846 struct tblentry *cmdp; 3847 int c; 3848 struct cmdentry entry; 3849 char *name; 3850 3851 while ((c = nextopt("r")) != '\0') { 3852 clearcmdentry(0); 3853 return 0; 3854 } 3855 if (*argptr == NULL) { 3856 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { 3857 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { 3858 if (cmdp->cmdtype == CMDNORMAL) 3859 printentry(cmdp); 3860 } 3861 } 3862 return 0; 3863 } 3864 c = 0; 3865 while ((name = *argptr) != NULL) { 3866 if ((cmdp = cmdlookup(name, 0)) != NULL 3867 && (cmdp->cmdtype == CMDNORMAL 3868 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 3869 delete_cmd_entry(); 3870 find_command(name, &entry, DO_ERR, pathval()); 3871 if (entry.cmdtype == CMDUNKNOWN) 3872 c = 1; 3873 argptr++; 3874 } 3875 return c; 3876 } 3877 3878 3879 /* 3880 * Resolve a command name. If you change this routine, you may have to 3881 * change the shellexec routine as well. 3882 */ 3883 3884 static void 3885 find_command(char *name, struct cmdentry *entry, int act, const char *path) 3886 { 3887 struct tblentry *cmdp; 3888 int idx; 3889 int prev; 3890 char *fullname; 3891 struct stat statb; 3892 int e; 3893 int updatetbl; 3894 struct builtincmd *bcmd; 3895 3896 /* If name contains a slash, don't use PATH or hash table */ 3897 if (strchr(name, '/') != NULL) { 3898 entry->u.index = -1; 3899 if (act & DO_ABS) { 3900 while (stat(name, &statb) < 0) { 3901 #ifdef SYSV 3902 if (errno == EINTR) 3903 continue; 3904 #endif 3905 entry->cmdtype = CMDUNKNOWN; 3906 return; 3907 } 3908 } 3909 entry->cmdtype = CMDNORMAL; 3910 return; 3911 } 3912 3913 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3914 if (find_applet_by_name(name)) { 3915 entry->cmdtype = CMDNORMAL; 3916 entry->u.index = -1; 3917 return; 3918 } 3919 #endif 3920 3921 updatetbl = (path == pathval()); 3922 if (!updatetbl) { 3923 act |= DO_ALTPATH; 3924 if (strstr(path, "%builtin") != NULL) 3925 act |= DO_ALTBLTIN; 3926 } 3927 3928 /* If name is in the table, check answer will be ok */ 3929 if ((cmdp = cmdlookup(name, 0)) != NULL) { 3930 int bit; 3931 3932 switch (cmdp->cmdtype) { 3933 default: 3934 #if DEBUG 3935 abort(); 3936 #endif 3937 case CMDNORMAL: 3938 bit = DO_ALTPATH; 3939 break; 3940 case CMDFUNCTION: 3941 bit = DO_NOFUNC; 3942 break; 3943 case CMDBUILTIN: 3944 bit = DO_ALTBLTIN; 3945 break; 3946 } 3947 if (act & bit) { 3948 updatetbl = 0; 3949 cmdp = NULL; 3950 } else if (cmdp->rehash == 0) 3951 /* if not invalidated by cd, we're done */ 3952 goto success; 3953 } 3954 3955 /* If %builtin not in path, check for builtin next */ 3956 bcmd = find_builtin(name); 3957 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || ( 3958 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0 3959 ))) 3960 goto builtin_success; 3961 3962 /* We have to search path. */ 3963 prev = -1; /* where to start */ 3964 if (cmdp && cmdp->rehash) { /* doing a rehash */ 3965 if (cmdp->cmdtype == CMDBUILTIN) 3966 prev = builtinloc; 3967 else 3968 prev = cmdp->param.index; 3969 } 3970 3971 e = ENOENT; 3972 idx = -1; 3973 loop: 3974 while ((fullname = padvance(&path, name)) != NULL) { 3975 stunalloc(fullname); 3976 idx++; 3977 if (pathopt) { 3978 if (prefix(pathopt, "builtin")) { 3979 if (bcmd) 3980 goto builtin_success; 3981 continue; 3982 } else if (!(act & DO_NOFUNC) && 3983 prefix(pathopt, "func")) { 3984 /* handled below */ 3985 } else { 3986 /* ignore unimplemented options */ 3987 continue; 3988 } 3989 } 3990 /* if rehash, don't redo absolute path names */ 3991 if (fullname[0] == '/' && idx <= prev) { 3992 if (idx < prev) 3993 continue; 3994 TRACE(("searchexec \"%s\": no change\n", name)); 3995 goto success; 3996 } 3997 while (stat(fullname, &statb) < 0) { 3998 #ifdef SYSV 3999 if (errno == EINTR) 4000 continue; 4001 #endif 4002 if (errno != ENOENT && errno != ENOTDIR) 4003 e = errno; 4004 goto loop; 4005 } 4006 e = EACCES; /* if we fail, this will be the error */ 4007 if (!S_ISREG(statb.st_mode)) 4008 continue; 4009 if (pathopt) { /* this is a %func directory */ 4010 stalloc(strlen(fullname) + 1); 4011 readcmdfile(fullname); 4012 if ((cmdp = cmdlookup(name, 0)) == NULL || 4013 cmdp->cmdtype != CMDFUNCTION) 4014 sh_error("%s not defined in %s", name, fullname); 4015 stunalloc(fullname); 4016 goto success; 4017 } 4018 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 4019 if (!updatetbl) { 4020 entry->cmdtype = CMDNORMAL; 4021 entry->u.index = idx; 4022 return; 4023 } 4024 INTOFF; 4025 cmdp = cmdlookup(name, 1); 4026 cmdp->cmdtype = CMDNORMAL; 4027 cmdp->param.index = idx; 4028 INTON; 4029 goto success; 4030 } 4031 4032 /* We failed. If there was an entry for this command, delete it */ 4033 if (cmdp && updatetbl) 4034 delete_cmd_entry(); 4035 if (act & DO_ERR) 4036 sh_warnx("%s: %s", name, errmsg(e, E_EXEC)); 4037 entry->cmdtype = CMDUNKNOWN; 4038 return; 4039 4040 builtin_success: 4041 if (!updatetbl) { 4042 entry->cmdtype = CMDBUILTIN; 4043 entry->u.cmd = bcmd; 4044 return; 4045 } 4046 INTOFF; 4047 cmdp = cmdlookup(name, 1); 4048 cmdp->cmdtype = CMDBUILTIN; 4049 cmdp->param.cmd = bcmd; 4050 INTON; 4051 success: 4052 cmdp->rehash = 0; 4053 entry->cmdtype = cmdp->cmdtype; 4054 entry->u = cmdp->param; 4055 } 4056 4057 4058 /* 4059 * Wrapper around strcmp for qsort/bsearch/... 4060 */ 4061 static int pstrcmp(const void *a, const void *b) 4062 { 4063 return strcmp((const char *) a, (*(const char *const *) b) + 1); 4064 } 4065 4066 /* 4067 * Search the table of builtin commands. 4068 */ 4069 4070 static struct builtincmd * 4071 find_builtin(const char *name) 4072 { 4073 struct builtincmd *bp; 4074 4075 bp = bsearch( 4076 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd), 4077 pstrcmp 4078 ); 4079 return bp; 4080 } 4081 4082 4083 4084 /* 4085 * Called when a cd is done. Marks all commands so the next time they 4086 * are executed they will be rehashed. 4087 */ 4088 4089 static void 4090 hashcd(void) 4091 { 4092 struct tblentry **pp; 4093 struct tblentry *cmdp; 4094 4095 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { 4096 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { 4097 if (cmdp->cmdtype == CMDNORMAL || ( 4098 cmdp->cmdtype == CMDBUILTIN && 4099 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) && 4100 builtinloc > 0 4101 )) 4102 cmdp->rehash = 1; 4103 } 4104 } 4105 } 4106 4107 4108 4109 /* 4110 * Fix command hash table when PATH changed. 4111 * Called before PATH is changed. The argument is the new value of PATH; 4112 * pathval() still returns the old value at this point. 4113 * Called with interrupts off. 4114 */ 4115 4116 static void 4117 changepath(const char *newval) 4118 { 4119 const char *old, *new; 4120 int idx; 4121 int firstchange; 4122 int idx_bltin; 4123 4124 old = pathval(); 4125 new = newval; 4126 firstchange = 9999; /* assume no change */ 4127 idx = 0; 4128 idx_bltin = -1; 4129 for (;;) { 4130 if (*old != *new) { 4131 firstchange = idx; 4132 if ((*old == '\0' && *new == ':') 4133 || (*old == ':' && *new == '\0')) 4134 firstchange++; 4135 old = new; /* ignore subsequent differences */ 4136 } 4137 if (*new == '\0') 4138 break; 4139 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 4140 idx_bltin = idx; 4141 if (*new == ':') { 4142 idx++; 4143 } 4144 new++, old++; 4145 } 4146 if (builtinloc < 0 && idx_bltin >= 0) 4147 builtinloc = idx_bltin; /* zap builtins */ 4148 if (builtinloc >= 0 && idx_bltin < 0) 4149 firstchange = 0; 4150 clearcmdentry(firstchange); 4151 builtinloc = idx_bltin; 4152 } 4153 4154 4155 /* 4156 * Clear out command entries. The argument specifies the first entry in 4157 * PATH which has changed. 4158 */ 4159 4160 static void 4161 clearcmdentry(int firstchange) 4162 { 4163 struct tblentry **tblp; 4164 struct tblentry **pp; 4165 struct tblentry *cmdp; 4166 4167 INTOFF; 4168 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { 4169 pp = tblp; 4170 while ((cmdp = *pp) != NULL) { 4171 if ((cmdp->cmdtype == CMDNORMAL && 4172 cmdp->param.index >= firstchange) 4173 || (cmdp->cmdtype == CMDBUILTIN && 4174 builtinloc >= firstchange)) { 4175 *pp = cmdp->next; 4176 ckfree(cmdp); 4177 } else { 4178 pp = &cmdp->next; 4179 } 4180 } 4181 } 4182 INTON; 4183 } 4184 4185 4186 4187 /* 4188 * Locate a command in the command hash table. If "add" is nonzero, 4189 * add the command to the table if it is not already present. The 4190 * variable "lastcmdentry" is set to point to the address of the link 4191 * pointing to the entry, so that delete_cmd_entry can delete the 4192 * entry. 4193 * 4194 * Interrupts must be off if called with add != 0. 4195 */ 4196 4197 static struct tblentry **lastcmdentry; 4198 4199 4200 static struct tblentry * 4201 cmdlookup(const char *name, int add) 4202 { 4203 unsigned int hashval; 4204 const char *p; 4205 struct tblentry *cmdp; 4206 struct tblentry **pp; 4207 4208 p = name; 4209 hashval = (unsigned char)*p << 4; 4210 while (*p) 4211 hashval += (unsigned char)*p++; 4212 hashval &= 0x7FFF; 4213 pp = &cmdtable[hashval % CMDTABLESIZE]; 4214 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { 4215 if (equal(cmdp->cmdname, name)) 4216 break; 4217 pp = &cmdp->next; 4218 } 4219 if (add && cmdp == NULL) { 4220 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB 4221 + strlen(name) + 1); 4222 cmdp->next = NULL; 4223 cmdp->cmdtype = CMDUNKNOWN; 4224 strcpy(cmdp->cmdname, name); 4225 } 4226 lastcmdentry = pp; 4227 return cmdp; 4228 } 4229 4230 /* 4231 * Delete the command entry returned on the last lookup. 4232 */ 4233 4234 static void 4235 delete_cmd_entry(void) 4236 { 4237 struct tblentry *cmdp; 4238 4239 INTOFF; 4240 cmdp = *lastcmdentry; 4241 *lastcmdentry = cmdp->next; 4242 if (cmdp->cmdtype == CMDFUNCTION) 4243 freefunc(cmdp->param.func); 4244 ckfree(cmdp); 4245 INTON; 4246 } 4247 4248 4249 /* 4250 * Add a new command entry, replacing any existing command entry for 4251 * the same name - except special builtins. 4252 */ 4253 4254 static inline void 4255 addcmdentry(char *name, struct cmdentry *entry) 4256 { 4257 struct tblentry *cmdp; 4258 4259 cmdp = cmdlookup(name, 1); 4260 if (cmdp->cmdtype == CMDFUNCTION) { 4261 freefunc(cmdp->param.func); 4262 } 4263 cmdp->cmdtype = entry->cmdtype; 4264 cmdp->param = entry->u; 4265 cmdp->rehash = 0; 4266 } 4267 4268 /* 4269 * Make a copy of a parse tree. 4270 */ 4271 4272 static inline struct funcnode * 4273 copyfunc(union node *n) 4274 { 4275 struct funcnode *f; 4276 size_t blocksize; 4277 4278 funcblocksize = offsetof(struct funcnode, n); 4279 funcstringsize = 0; 4280 calcsize(n); 4281 blocksize = funcblocksize; 4282 f = ckmalloc(blocksize + funcstringsize); 4283 funcblock = (char *) f + offsetof(struct funcnode, n); 4284 funcstring = (char *) f + blocksize; 4285 copynode(n); 4286 f->count = 0; 4287 return f; 4288 } 4289 4290 /* 4291 * Define a shell function. 4292 */ 4293 4294 static void 4295 defun(char *name, union node *func) 4296 { 4297 struct cmdentry entry; 4298 4299 INTOFF; 4300 entry.cmdtype = CMDFUNCTION; 4301 entry.u.func = copyfunc(func); 4302 addcmdentry(name, &entry); 4303 INTON; 4304 } 4305 4306 4307 /* 4308 * Delete a function if it exists. 4309 */ 4310 4311 static void 4312 unsetfunc(const char *name) 4313 { 4314 struct tblentry *cmdp; 4315 4316 if ((cmdp = cmdlookup(name, 0)) != NULL && 4317 cmdp->cmdtype == CMDFUNCTION) 4318 delete_cmd_entry(); 4319 } 4320 4321 /* 4322 * Locate and print what a word is... 4323 */ 4324 4325 4326 #ifdef CONFIG_ASH_CMDCMD 4327 static int 4328 describe_command(char *command, int describe_command_verbose) 4329 #else 4330 #define describe_command_verbose 1 4331 static int 4332 describe_command(char *command) 4333 #endif 4334 { 4335 struct cmdentry entry; 4336 struct tblentry *cmdp; 4337 #ifdef CONFIG_ASH_ALIAS 4338 const struct alias *ap; 4339 #endif 4340 const char *path = pathval(); 4341 4342 if (describe_command_verbose) { 4343 out1str(command); 4344 } 4345 4346 /* First look at the keywords */ 4347 if (findkwd(command)) { 4348 out1str(describe_command_verbose ? " is a shell keyword" : command); 4349 goto out; 4350 } 4351 4352 #ifdef CONFIG_ASH_ALIAS 4353 /* Then look at the aliases */ 4354 if ((ap = lookupalias(command, 0)) != NULL) { 4355 if (describe_command_verbose) { 4356 out1fmt(" is an alias for %s", ap->val); 4357 } else { 4358 out1str("alias "); 4359 printalias(ap); 4360 return 0; 4361 } 4362 goto out; 4363 } 4364 #endif 4365 /* Then check if it is a tracked alias */ 4366 if ((cmdp = cmdlookup(command, 0)) != NULL) { 4367 entry.cmdtype = cmdp->cmdtype; 4368 entry.u = cmdp->param; 4369 } else { 4370 /* Finally use brute force */ 4371 find_command(command, &entry, DO_ABS, path); 4372 } 4373 4374 switch (entry.cmdtype) { 4375 case CMDNORMAL: { 4376 int j = entry.u.index; 4377 char *p; 4378 if (j == -1) { 4379 p = command; 4380 } else { 4381 do { 4382 p = padvance(&path, command); 4383 stunalloc(p); 4384 } while (--j >= 0); 4385 } 4386 if (describe_command_verbose) { 4387 out1fmt(" is%s %s", 4388 (cmdp ? " a tracked alias for" : nullstr), p 4389 ); 4390 } else { 4391 out1str(p); 4392 } 4393 break; 4394 } 4395 4396 case CMDFUNCTION: 4397 if (describe_command_verbose) { 4398 out1str(" is a shell function"); 4399 } else { 4400 out1str(command); 4401 } 4402 break; 4403 4404 case CMDBUILTIN: 4405 if (describe_command_verbose) { 4406 out1fmt(" is a %sshell builtin", 4407 IS_BUILTIN_SPECIAL(entry.u.cmd) ? 4408 "special " : nullstr 4409 ); 4410 } else { 4411 out1str(command); 4412 } 4413 break; 4414 4415 default: 4416 if (describe_command_verbose) { 4417 out1str(": not found\n"); 4418 } 4419 return 127; 4420 } 4421 4422 out: 4423 outstr("\n", stdout); 4424 return 0; 4425 } 4426 4427 static int 4428 typecmd(int argc, char **argv) 4429 { 4430 int i; 4431 int err = 0; 4432 4433 for (i = 1; i < argc; i++) { 4434 #ifdef CONFIG_ASH_CMDCMD 4435 err |= describe_command(argv[i], 1); 4436 #else 4437 err |= describe_command(argv[i]); 4438 #endif 4439 } 4440 return err; 4441 } 4442 4443 #ifdef CONFIG_ASH_CMDCMD 4444 static int 4445 commandcmd(int argc, char **argv) 4446 { 4447 int c; 4448 enum { 4449 VERIFY_BRIEF = 1, 4450 VERIFY_VERBOSE = 2, 4451 } verify = 0; 4452 4453 while ((c = nextopt("pvV")) != '\0') 4454 if (c == 'V') 4455 verify |= VERIFY_VERBOSE; 4456 else if (c == 'v') 4457 verify |= VERIFY_BRIEF; 4458 #ifdef DEBUG 4459 else if (c != 'p') 4460 abort(); 4461 #endif 4462 if (verify) 4463 return describe_command(*argptr, verify - VERIFY_BRIEF); 4464 4465 return 0; 4466 } 4467 #endif 4468 4469 /* expand.c */ 4470 4471 /* 4472 * Routines to expand arguments to commands. We have to deal with 4473 * backquotes, shell variables, and file metacharacters. 4474 */ 4475 4476 /* 4477 * _rmescape() flags 4478 */ 4479 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 4480 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 4481 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ 4482 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 4483 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 4484 4485 /* 4486 * Structure specifying which parts of the string should be searched 4487 * for IFS characters. 4488 */ 4489 4490 struct ifsregion { 4491 struct ifsregion *next; /* next region in list */ 4492 int begoff; /* offset of start of region */ 4493 int endoff; /* offset of end of region */ 4494 int nulonly; /* search for nul bytes only */ 4495 }; 4496 4497 /* output of current string */ 4498 static char *expdest; 4499 /* list of back quote expressions */ 4500 static struct nodelist *argbackq; 4501 /* first struct in list of ifs regions */ 4502 static struct ifsregion ifsfirst; 4503 /* last struct in list */ 4504 static struct ifsregion *ifslastp; 4505 /* holds expanded arg list */ 4506 static struct arglist exparg; 4507 4508 static void argstr(char *, int); 4509 static char *exptilde(char *, char *, int); 4510 static void expbackq(union node *, int, int); 4511 static const char *subevalvar(char *, char *, int, int, int, int, int); 4512 static char *evalvar(char *, int); 4513 static void strtodest(const char *, int, int); 4514 static void memtodest(const char *p, size_t len, int syntax, int quotes); 4515 static ssize_t varvalue(char *, int, int); 4516 static void recordregion(int, int, int); 4517 static void removerecordregions(int); 4518 static void ifsbreakup(char *, struct arglist *); 4519 static void ifsfree(void); 4520 static void expandmeta(struct strlist *, int); 4521 static int patmatch(char *, const char *); 4522 4523 static int cvtnum(arith_t); 4524 static size_t esclen(const char *, const char *); 4525 static char *scanleft(char *, char *, char *, char *, int, int); 4526 static char *scanright(char *, char *, char *, char *, int, int); 4527 static void varunset(const char *, const char *, const char *, int) 4528 ATTRIBUTE_NORETURN; 4529 4530 4531 #define pmatch(a, b) !fnmatch((a), (b), 0) 4532 /* 4533 * Prepare a pattern for a expmeta (internal glob(3)) call. 4534 * 4535 * Returns an stalloced string. 4536 */ 4537 4538 static inline char * 4539 preglob(const char *pattern, int quoted, int flag) { 4540 flag |= RMESCAPE_GLOB; 4541 if (quoted) { 4542 flag |= RMESCAPE_QUOTED; 4543 } 4544 return _rmescapes((char *)pattern, flag); 4545 } 4546 4547 4548 static size_t 4549 esclen(const char *start, const char *p) { 4550 size_t esc = 0; 4551 4552 while (p > start && *--p == CTLESC) { 4553 esc++; 4554 } 4555 return esc; 4556 } 4557 4558 4559 /* 4560 * Expand shell variables and backquotes inside a here document. 4561 */ 4562 4563 static inline void 4564 expandhere(union node *arg, int fd) 4565 { 4566 herefd = fd; 4567 expandarg(arg, (struct arglist *)NULL, 0); 4568 bb_full_write(fd, stackblock(), expdest - (char *)stackblock()); 4569 } 4570 4571 4572 /* 4573 * Perform variable substitution and command substitution on an argument, 4574 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 4575 * perform splitting and file name expansion. When arglist is NULL, perform 4576 * here document expansion. 4577 */ 4578 4579 void 4580 expandarg(union node *arg, struct arglist *arglist, int flag) 4581 { 4582 struct strlist *sp; 4583 char *p; 4584 4585 argbackq = arg->narg.backquote; 4586 STARTSTACKSTR(expdest); 4587 ifsfirst.next = NULL; 4588 ifslastp = NULL; 4589 argstr(arg->narg.text, flag); 4590 p = _STPUTC('\0', expdest); 4591 expdest = p - 1; 4592 if (arglist == NULL) { 4593 return; /* here document expanded */ 4594 } 4595 p = grabstackstr(p); 4596 exparg.lastp = &exparg.list; 4597 /* 4598 * TODO - EXP_REDIR 4599 */ 4600 if (flag & EXP_FULL) { 4601 ifsbreakup(p, &exparg); 4602 *exparg.lastp = NULL; 4603 exparg.lastp = &exparg.list; 4604 expandmeta(exparg.list, flag); 4605 } else { 4606 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 4607 rmescapes(p); 4608 sp = (struct strlist *)stalloc(sizeof (struct strlist)); 4609 sp->text = p; 4610 *exparg.lastp = sp; 4611 exparg.lastp = &sp->next; 4612 } 4613 if (ifsfirst.next) 4614 ifsfree(); 4615 *exparg.lastp = NULL; 4616 if (exparg.list) { 4617 *arglist->lastp = exparg.list; 4618 arglist->lastp = exparg.lastp; 4619 } 4620 } 4621 4622 4623 /* 4624 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 4625 * characters to allow for further processing. Otherwise treat 4626 * $@ like $* since no splitting will be performed. 4627 */ 4628 4629 static void 4630 argstr(char *p, int flag) 4631 { 4632 static const char spclchars[] = { 4633 '=', 4634 ':', 4635 CTLQUOTEMARK, 4636 CTLENDVAR, 4637 CTLESC, 4638 CTLVAR, 4639 CTLBACKQ, 4640 CTLBACKQ | CTLQUOTE, 4641 #ifdef CONFIG_ASH_MATH_SUPPORT 4642 CTLENDARI, 4643 #endif 4644 0 4645 }; 4646 const char *reject = spclchars; 4647 int c; 4648 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 4649 int breakall = flag & EXP_WORD; 4650 int inquotes; 4651 size_t length; 4652 int startloc; 4653 4654 if (!(flag & EXP_VARTILDE)) { 4655 reject += 2; 4656 } else if (flag & EXP_VARTILDE2) { 4657 reject++; 4658 } 4659 inquotes = 0; 4660 length = 0; 4661 if (flag & EXP_TILDE) { 4662 char *q; 4663 4664 flag &= ~EXP_TILDE; 4665 tilde: 4666 q = p; 4667 if (*q == CTLESC && (flag & EXP_QWORD)) 4668 q++; 4669 if (*q == '~') 4670 p = exptilde(p, q, flag); 4671 } 4672 start: 4673 startloc = expdest - (char *)stackblock(); 4674 for (;;) { 4675 length += strcspn(p + length, reject); 4676 c = p[length]; 4677 if (c && (!(c & 0x80) 4678 #ifdef CONFIG_ASH_MATH_SUPPORT 4679 || c == CTLENDARI 4680 #endif 4681 )) { 4682 /* c == '=' || c == ':' || c == CTLENDARI */ 4683 length++; 4684 } 4685 if (length > 0) { 4686 int newloc; 4687 expdest = stnputs(p, length, expdest); 4688 newloc = expdest - (char *)stackblock(); 4689 if (breakall && !inquotes && newloc > startloc) { 4690 recordregion(startloc, newloc, 0); 4691 } 4692 startloc = newloc; 4693 } 4694 p += length + 1; 4695 length = 0; 4696 4697 switch (c) { 4698 case '\0': 4699 goto breakloop; 4700 case '=': 4701 if (flag & EXP_VARTILDE2) { 4702 p--; 4703 continue; 4704 } 4705 flag |= EXP_VARTILDE2; 4706 reject++; 4707 /* fall through */ 4708 case ':': 4709 /* 4710 * sort of a hack - expand tildes in variable 4711 * assignments (after the first '=' and after ':'s). 4712 */ 4713 if (*--p == '~') { 4714 goto tilde; 4715 } 4716 continue; 4717 } 4718 4719 switch (c) { 4720 case CTLENDVAR: /* ??? */ 4721 goto breakloop; 4722 case CTLQUOTEMARK: 4723 /* "$@" syntax adherence hack */ 4724 if ( 4725 !inquotes && 4726 !memcmp(p, dolatstr, DOLATSTRLEN) && 4727 (p[4] == CTLQUOTEMARK || ( 4728 p[4] == CTLENDVAR && 4729 p[5] == CTLQUOTEMARK 4730 )) 4731 ) { 4732 p = evalvar(p + 1, flag) + 1; 4733 goto start; 4734 } 4735 inquotes = !inquotes; 4736 addquote: 4737 if (quotes) { 4738 p--; 4739 length++; 4740 startloc++; 4741 } 4742 break; 4743 case CTLESC: 4744 startloc++; 4745 length++; 4746 goto addquote; 4747 case CTLVAR: 4748 p = evalvar(p, flag); 4749 goto start; 4750 case CTLBACKQ: 4751 c = 0; 4752 case CTLBACKQ|CTLQUOTE: 4753 expbackq(argbackq->n, c, quotes); 4754 argbackq = argbackq->next; 4755 goto start; 4756 #ifdef CONFIG_ASH_MATH_SUPPORT 4757 case CTLENDARI: 4758 p--; 4759 expari(quotes); 4760 goto start; 4761 #endif 4762 } 4763 } 4764 breakloop: 4765 ; 4766 } 4767 4768 static char * 4769 exptilde(char *startp, char *p, int flag) 4770 { 4771 char c; 4772 char *name; 4773 struct passwd *pw; 4774 const char *home; 4775 int quotes = flag & (EXP_FULL | EXP_CASE); 4776 int startloc; 4777 4778 name = p + 1; 4779 4780 while ((c = *++p) != '\0') { 4781 switch(c) { 4782 case CTLESC: 4783 return (startp); 4784 case CTLQUOTEMARK: 4785 return (startp); 4786 case ':': 4787 if (flag & EXP_VARTILDE) 4788 goto done; 4789 break; 4790 case '/': 4791 case CTLENDVAR: 4792 goto done; 4793 } 4794 } 4795 done: 4796 *p = '\0'; 4797 if (*name == '\0') { 4798 home = lookupvar(homestr); 4799 } else { 4800 if ((pw = getpwnam(name)) == NULL) 4801 goto lose; 4802 home = pw->pw_dir; 4803 } 4804 if (!home || !*home) 4805 goto lose; 4806 *p = c; 4807 startloc = expdest - (char *)stackblock(); 4808 strtodest(home, SQSYNTAX, quotes); 4809 recordregion(startloc, expdest - (char *)stackblock(), 0); 4810 return (p); 4811 lose: 4812 *p = c; 4813 return (startp); 4814 } 4815 4816 4817 static void 4818 removerecordregions(int endoff) 4819 { 4820 if (ifslastp == NULL) 4821 return; 4822 4823 if (ifsfirst.endoff > endoff) { 4824 while (ifsfirst.next != NULL) { 4825 struct ifsregion *ifsp; 4826 INTOFF; 4827 ifsp = ifsfirst.next->next; 4828 ckfree(ifsfirst.next); 4829 ifsfirst.next = ifsp; 4830 INTON; 4831 } 4832 if (ifsfirst.begoff > endoff) 4833 ifslastp = NULL; 4834 else { 4835 ifslastp = &ifsfirst; 4836 ifsfirst.endoff = endoff; 4837 } 4838 return; 4839 } 4840 4841 ifslastp = &ifsfirst; 4842 while (ifslastp->next && ifslastp->next->begoff < endoff) 4843 ifslastp=ifslastp->next; 4844 while (ifslastp->next != NULL) { 4845 struct ifsregion *ifsp; 4846 INTOFF; 4847 ifsp = ifslastp->next->next; 4848 ckfree(ifslastp->next); 4849 ifslastp->next = ifsp; 4850 INTON; 4851 } 4852 if (ifslastp->endoff > endoff) 4853 ifslastp->endoff = endoff; 4854 } 4855 4856 4857 #ifdef CONFIG_ASH_MATH_SUPPORT 4858 /* 4859 * Expand arithmetic expression. Backup to start of expression, 4860 * evaluate, place result in (backed up) result, adjust string position. 4861 */ 4862 void 4863 expari(int quotes) 4864 { 4865 char *p, *start; 4866 int begoff; 4867 int flag; 4868 int len; 4869 4870 /* ifsfree(); */ 4871 4872 /* 4873 * This routine is slightly over-complicated for 4874 * efficiency. Next we scan backwards looking for the 4875 * start of arithmetic. 4876 */ 4877 start = stackblock(); 4878 p = expdest - 1; 4879 *p = '\0'; 4880 p--; 4881 do { 4882 int esc; 4883 4884 while (*p != CTLARI) { 4885 p--; 4886 #ifdef DEBUG 4887 if (p < start) { 4888 sh_error("missing CTLARI (shouldn't happen)"); 4889 } 4890 #endif 4891 } 4892 4893 esc = esclen(start, p); 4894 if (!(esc % 2)) { 4895 break; 4896 } 4897 4898 p -= esc + 1; 4899 } while (1); 4900 4901 begoff = p - start; 4902 4903 removerecordregions(begoff); 4904 4905 flag = p[1]; 4906 4907 expdest = p; 4908 4909 if (quotes) 4910 rmescapes(p + 2); 4911 4912 len = cvtnum(dash_arith(p + 2)); 4913 4914 if (flag != '"') 4915 recordregion(begoff, begoff + len, 0); 4916 } 4917 #endif 4918 4919 /* 4920 * Expand stuff in backwards quotes. 4921 */ 4922 4923 static void 4924 expbackq(union node *cmd, int quoted, int quotes) 4925 { 4926 struct backcmd in; 4927 int i; 4928 char buf[128]; 4929 char *p; 4930 char *dest; 4931 int startloc; 4932 int syntax = quoted? DQSYNTAX : BASESYNTAX; 4933 struct stackmark smark; 4934 4935 INTOFF; 4936 setstackmark(&smark); 4937 dest = expdest; 4938 startloc = dest - (char *)stackblock(); 4939 grabstackstr(dest); 4940 evalbackcmd(cmd, (struct backcmd *) &in); 4941 popstackmark(&smark); 4942 4943 p = in.buf; 4944 i = in.nleft; 4945 if (i == 0) 4946 goto read; 4947 for (;;) { 4948 memtodest(p, i, syntax, quotes); 4949 read: 4950 if (in.fd < 0) 4951 break; 4952 i = safe_read(in.fd, buf, sizeof buf); 4953 TRACE(("expbackq: read returns %d\n", i)); 4954 if (i <= 0) 4955 break; 4956 p = buf; 4957 } 4958 4959 if (in.buf) 4960 ckfree(in.buf); 4961 if (in.fd >= 0) { 4962 close(in.fd); 4963 back_exitstatus = waitforjob(in.jp); 4964 } 4965 INTON; 4966 4967 /* Eat all trailing newlines */ 4968 dest = expdest; 4969 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 4970 STUNPUTC(dest); 4971 expdest = dest; 4972 4973 if (quoted == 0) 4974 recordregion(startloc, dest - (char *)stackblock(), 0); 4975 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 4976 (dest - (char *)stackblock()) - startloc, 4977 (dest - (char *)stackblock()) - startloc, 4978 stackblock() + startloc)); 4979 } 4980 4981 4982 static char * 4983 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 4984 int zero) 4985 { 4986 char *loc; 4987 char *loc2; 4988 char c; 4989 4990 loc = startp; 4991 loc2 = rmesc; 4992 do { 4993 int match; 4994 const char *s = loc2; 4995 c = *loc2; 4996 if (zero) { 4997 *loc2 = '\0'; 4998 s = rmesc; 4999 } 5000 match = pmatch(str, s); 5001 *loc2 = c; 5002 if (match) 5003 return loc; 5004 if (quotes && *loc == CTLESC) 5005 loc++; 5006 loc++; 5007 loc2++; 5008 } while (c); 5009 return 0; 5010 } 5011 5012 5013 static char * 5014 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5015 int zero) 5016 { 5017 int esc = 0; 5018 char *loc; 5019 char *loc2; 5020 5021 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 5022 int match; 5023 char c = *loc2; 5024 const char *s = loc2; 5025 if (zero) { 5026 *loc2 = '\0'; 5027 s = rmesc; 5028 } 5029 match = pmatch(str, s); 5030 *loc2 = c; 5031 if (match) 5032 return loc; 5033 loc--; 5034 if (quotes) { 5035 if (--esc < 0) { 5036 esc = esclen(startp, loc); 5037 } 5038 if (esc % 2) { 5039 esc--; 5040 loc--; 5041 } 5042 } 5043 } 5044 return 0; 5045 } 5046 5047 static const char * 5048 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5049 { 5050 char *startp; 5051 char *loc; 5052 int saveherefd = herefd; 5053 struct nodelist *saveargbackq = argbackq; 5054 int amount; 5055 char *rmesc, *rmescend; 5056 int zero; 5057 char *(*scan)(char *, char *, char *, char *, int , int); 5058 5059 herefd = -1; 5060 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5061 STPUTC('\0', expdest); 5062 herefd = saveherefd; 5063 argbackq = saveargbackq; 5064 startp = stackblock() + startloc; 5065 5066 switch (subtype) { 5067 case VSASSIGN: 5068 setvar(str, startp, 0); 5069 amount = startp - expdest; 5070 STADJUST(amount, expdest); 5071 return startp; 5072 5073 case VSQUESTION: 5074 varunset(p, str, startp, varflags); 5075 /* NOTREACHED */ 5076 } 5077 5078 subtype -= VSTRIMRIGHT; 5079 #ifdef DEBUG 5080 if (subtype < 0 || subtype > 3) 5081 abort(); 5082 #endif 5083 5084 rmesc = startp; 5085 rmescend = stackblock() + strloc; 5086 if (quotes) { 5087 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5088 if (rmesc != startp) { 5089 rmescend = expdest; 5090 startp = stackblock() + startloc; 5091 } 5092 } 5093 rmescend--; 5094 str = stackblock() + strloc; 5095 preglob(str, varflags & VSQUOTE, 0); 5096 5097 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 5098 zero = subtype >> 1; 5099 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ 5100 scan = (subtype & 1) ^ zero ? scanleft : scanright; 5101 5102 loc = scan(startp, rmesc, rmescend, str, quotes, zero); 5103 if (loc) { 5104 if (zero) { 5105 memmove(startp, loc, str - loc); 5106 loc = startp + (str - loc) - 1; 5107 } 5108 *loc = '\0'; 5109 amount = loc - expdest; 5110 STADJUST(amount, expdest); 5111 } 5112 return loc; 5113 } 5114 5115 5116 /* 5117 * Expand a variable, and return a pointer to the next character in the 5118 * input string. 5119 */ 5120 static char * 5121 evalvar(char *p, int flag) 5122 { 5123 int subtype; 5124 int varflags; 5125 char *var; 5126 int patloc; 5127 int c; 5128 int startloc; 5129 ssize_t varlen; 5130 int easy; 5131 int quotes; 5132 int quoted; 5133 5134 quotes = flag & (EXP_FULL | EXP_CASE); 5135 varflags = *p++; 5136 subtype = varflags & VSTYPE; 5137 quoted = varflags & VSQUOTE; 5138 var = p; 5139 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5140 startloc = expdest - (char *)stackblock(); 5141 p = strchr(p, '=') + 1; 5142 5143 again: 5144 varlen = varvalue(var, varflags, flag); 5145 if (varflags & VSNUL) 5146 varlen--; 5147 5148 if (subtype == VSPLUS) { 5149 varlen = -1 - varlen; 5150 goto vsplus; 5151 } 5152 5153 if (subtype == VSMINUS) { 5154 vsplus: 5155 if (varlen < 0) { 5156 argstr( 5157 p, flag | EXP_TILDE | 5158 (quoted ? EXP_QWORD : EXP_WORD) 5159 ); 5160 goto end; 5161 } 5162 if (easy) 5163 goto record; 5164 goto end; 5165 } 5166 5167 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5168 if (varlen < 0) { 5169 if (subevalvar(p, var, 0, subtype, startloc, 5170 varflags, 0)) { 5171 varflags &= ~VSNUL; 5172 /* 5173 * Remove any recorded regions beyond 5174 * start of variable 5175 */ 5176 removerecordregions(startloc); 5177 goto again; 5178 } 5179 goto end; 5180 } 5181 if (easy) 5182 goto record; 5183 goto end; 5184 } 5185 5186 if (varlen < 0 && uflag) 5187 varunset(p, var, 0, 0); 5188 5189 if (subtype == VSLENGTH) { 5190 cvtnum(varlen > 0 ? varlen : 0); 5191 goto record; 5192 } 5193 5194 if (subtype == VSNORMAL) { 5195 if (!easy) 5196 goto end; 5197 record: 5198 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5199 goto end; 5200 } 5201 5202 #ifdef DEBUG 5203 switch (subtype) { 5204 case VSTRIMLEFT: 5205 case VSTRIMLEFTMAX: 5206 case VSTRIMRIGHT: 5207 case VSTRIMRIGHTMAX: 5208 break; 5209 default: 5210 abort(); 5211 } 5212 #endif 5213 5214 if (varlen >= 0) { 5215 /* 5216 * Terminate the string and start recording the pattern 5217 * right after it 5218 */ 5219 STPUTC('\0', expdest); 5220 patloc = expdest - (char *)stackblock(); 5221 if (subevalvar(p, NULL, patloc, subtype, 5222 startloc, varflags, quotes) == 0) { 5223 int amount = expdest - ( 5224 (char *)stackblock() + patloc - 1 5225 ); 5226 STADJUST(-amount, expdest); 5227 } 5228 /* Remove any recorded regions beyond start of variable */ 5229 removerecordregions(startloc); 5230 goto record; 5231 } 5232 5233 end: 5234 if (subtype != VSNORMAL) { /* skip to end of alternative */ 5235 int nesting = 1; 5236 for (;;) { 5237 if ((c = *p++) == CTLESC) 5238 p++; 5239 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 5240 if (varlen >= 0) 5241 argbackq = argbackq->next; 5242 } else if (c == CTLVAR) { 5243 if ((*p++ & VSTYPE) != VSNORMAL) 5244 nesting++; 5245 } else if (c == CTLENDVAR) { 5246 if (--nesting == 0) 5247 break; 5248 } 5249 } 5250 } 5251 return p; 5252 } 5253 5254 5255 /* 5256 * Put a string on the stack. 5257 */ 5258 5259 static void 5260 memtodest(const char *p, size_t len, int syntax, int quotes) { 5261 char *q = expdest; 5262 5263 q = makestrspace(len * 2, q); 5264 5265 while (len--) { 5266 int c = SC2INT(*p++); 5267 if (!c) 5268 continue; 5269 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5270 USTPUTC(CTLESC, q); 5271 USTPUTC(c, q); 5272 } 5273 5274 expdest = q; 5275 } 5276 5277 5278 static void 5279 strtodest(const char *p, int syntax, int quotes) 5280 { 5281 memtodest(p, strlen(p), syntax, quotes); 5282 } 5283 5284 5285 /* 5286 * Add the value of a specialized variable to the stack string. 5287 */ 5288 5289 static ssize_t 5290 varvalue(char *name, int varflags, int flags) 5291 { 5292 int num; 5293 char *p; 5294 int i; 5295 int sep = 0; 5296 int sepq = 0; 5297 ssize_t len = 0; 5298 char **ap; 5299 int syntax; 5300 int quoted = varflags & VSQUOTE; 5301 int subtype = varflags & VSTYPE; 5302 int quotes = flags & (EXP_FULL | EXP_CASE); 5303 5304 if (quoted && (flags & EXP_FULL)) 5305 sep = 1 << CHAR_BIT; 5306 5307 syntax = quoted ? DQSYNTAX : BASESYNTAX; 5308 switch (*name) { 5309 case '$': 5310 num = rootpid; 5311 goto numvar; 5312 case '?': 5313 num = exitstatus; 5314 goto numvar; 5315 case '#': 5316 num = shellparam.nparam; 5317 goto numvar; 5318 case '!': 5319 num = backgndpid; 5320 if (num == 0) 5321 return -1; 5322 numvar: 5323 len = cvtnum(num); 5324 break; 5325 case '-': 5326 p = makestrspace(NOPTS, expdest); 5327 for (i = NOPTS - 1; i >= 0; i--) { 5328 if (optlist[i]) { 5329 USTPUTC(optletters(i), p); 5330 len++; 5331 } 5332 } 5333 expdest = p; 5334 break; 5335 case '@': 5336 if (sep) 5337 goto param; 5338 /* fall through */ 5339 case '*': 5340 sep = ifsset() ? SC2INT(ifsval()[0]) : ' '; 5341 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 5342 sepq = 1; 5343 param: 5344 if (!(ap = shellparam.p)) 5345 return -1; 5346 while ((p = *ap++)) { 5347 size_t partlen; 5348 5349 partlen = strlen(p); 5350 len += partlen; 5351 5352 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5353 memtodest(p, partlen, syntax, quotes); 5354 5355 if (*ap && sep) { 5356 char *q; 5357 5358 len++; 5359 if (subtype == VSPLUS || subtype == VSLENGTH) { 5360 continue; 5361 } 5362 q = expdest; 5363 if (sepq) 5364 STPUTC(CTLESC, q); 5365 STPUTC(sep, q); 5366 expdest = q; 5367 } 5368 } 5369 return len; 5370 case '0': 5371 case '1': 5372 case '2': 5373 case '3': 5374 case '4': 5375 case '5': 5376 case '6': 5377 case '7': 5378 case '8': 5379 case '9': 5380 num = atoi(name); 5381 if (num < 0 || num > shellparam.nparam) 5382 return -1; 5383 p = num ? shellparam.p[num - 1] : arg0; 5384 goto value; 5385 default: 5386 p = lookupvar(name); 5387 value: 5388 if (!p) 5389 return -1; 5390 5391 len = strlen(p); 5392 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5393 memtodest(p, len, syntax, quotes); 5394 return len; 5395 } 5396 5397 if (subtype == VSPLUS || subtype == VSLENGTH) 5398 STADJUST(-len, expdest); 5399 return len; 5400 } 5401 5402 5403 /* 5404 * Record the fact that we have to scan this region of the 5405 * string for IFS characters. 5406 */ 5407 5408 static void 5409 recordregion(int start, int end, int nulonly) 5410 { 5411 struct ifsregion *ifsp; 5412 5413 if (ifslastp == NULL) { 5414 ifsp = &ifsfirst; 5415 } else { 5416 INTOFF; 5417 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 5418 ifsp->next = NULL; 5419 ifslastp->next = ifsp; 5420 INTON; 5421 } 5422 ifslastp = ifsp; 5423 ifslastp->begoff = start; 5424 ifslastp->endoff = end; 5425 ifslastp->nulonly = nulonly; 5426 } 5427 5428 5429 /* 5430 * Break the argument string into pieces based upon IFS and add the 5431 * strings to the argument list. The regions of the string to be 5432 * searched for IFS characters have been stored by recordregion. 5433 */ 5434 static void 5435 ifsbreakup(char *string, struct arglist *arglist) 5436 { 5437 struct ifsregion *ifsp; 5438 struct strlist *sp; 5439 char *start; 5440 char *p; 5441 char *q; 5442 const char *ifs, *realifs; 5443 int ifsspc; 5444 int nulonly; 5445 5446 5447 start = string; 5448 if (ifslastp != NULL) { 5449 ifsspc = 0; 5450 nulonly = 0; 5451 realifs = ifsset() ? ifsval() : defifs; 5452 ifsp = &ifsfirst; 5453 do { 5454 p = string + ifsp->begoff; 5455 nulonly = ifsp->nulonly; 5456 ifs = nulonly ? nullstr : realifs; 5457 ifsspc = 0; 5458 while (p < string + ifsp->endoff) { 5459 q = p; 5460 if (*p == CTLESC) 5461 p++; 5462 if (strchr(ifs, *p)) { 5463 if (!nulonly) 5464 ifsspc = (strchr(defifs, *p) != NULL); 5465 /* Ignore IFS whitespace at start */ 5466 if (q == start && ifsspc) { 5467 p++; 5468 start = p; 5469 continue; 5470 } 5471 *q = '\0'; 5472 sp = (struct strlist *)stalloc(sizeof *sp); 5473 sp->text = start; 5474 *arglist->lastp = sp; 5475 arglist->lastp = &sp->next; 5476 p++; 5477 if (!nulonly) { 5478 for (;;) { 5479 if (p >= string + ifsp->endoff) { 5480 break; 5481 } 5482 q = p; 5483 if (*p == CTLESC) 5484 p++; 5485 if (strchr(ifs, *p) == NULL ) { 5486 p = q; 5487 break; 5488 } else if (strchr(defifs, *p) == NULL) { 5489 if (ifsspc) { 5490 p++; 5491 ifsspc = 0; 5492 } else { 5493 p = q; 5494 break; 5495 } 5496 } else 5497 p++; 5498 } 5499 } 5500 start = p; 5501 } else 5502 p++; 5503 } 5504 } while ((ifsp = ifsp->next) != NULL); 5505 if (nulonly) 5506 goto add; 5507 } 5508 5509 if (!*start) 5510 return; 5511 5512 add: 5513 sp = (struct strlist *)stalloc(sizeof *sp); 5514 sp->text = start; 5515 *arglist->lastp = sp; 5516 arglist->lastp = &sp->next; 5517 } 5518 5519 static void 5520 ifsfree(void) 5521 { 5522 struct ifsregion *p; 5523 5524 INTOFF; 5525 p = ifsfirst.next; 5526 do { 5527 struct ifsregion *ifsp; 5528 ifsp = p->next; 5529 ckfree(p); 5530 p = ifsp; 5531 } while (p); 5532 ifslastp = NULL; 5533 ifsfirst.next = NULL; 5534 INTON; 5535 } 5536 5537 static void expmeta(char *, char *); 5538 static struct strlist *expsort(struct strlist *); 5539 static struct strlist *msort(struct strlist *, int); 5540 5541 static char *expdir; 5542 5543 5544 static void 5545 expandmeta(struct strlist *str, int flag) 5546 { 5547 static const char metachars[] = { 5548 '*', '?', '[', 0 5549 }; 5550 /* TODO - EXP_REDIR */ 5551 5552 while (str) { 5553 struct strlist **savelastp; 5554 struct strlist *sp; 5555 char *p; 5556 5557 if (fflag) 5558 goto nometa; 5559 if (!strpbrk(str->text, metachars)) 5560 goto nometa; 5561 savelastp = exparg.lastp; 5562 5563 INTOFF; 5564 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 5565 { 5566 int i = strlen(str->text); 5567 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 5568 } 5569 5570 expmeta(expdir, p); 5571 ckfree(expdir); 5572 if (p != str->text) 5573 ckfree(p); 5574 INTON; 5575 if (exparg.lastp == savelastp) { 5576 /* 5577 * no matches 5578 */ 5579 nometa: 5580 *exparg.lastp = str; 5581 rmescapes(str->text); 5582 exparg.lastp = &str->next; 5583 } else { 5584 *exparg.lastp = NULL; 5585 *savelastp = sp = expsort(*savelastp); 5586 while (sp->next != NULL) 5587 sp = sp->next; 5588 exparg.lastp = &sp->next; 5589 } 5590 str = str->next; 5591 } 5592 } 5593 5594 /* 5595 * Add a file name to the list. 5596 */ 5597 5598 static void 5599 addfname(const char *name) 5600 { 5601 struct strlist *sp; 5602 5603 sp = (struct strlist *)stalloc(sizeof *sp); 5604 sp->text = sstrdup(name); 5605 *exparg.lastp = sp; 5606 exparg.lastp = &sp->next; 5607 } 5608 5609 5610 /* 5611 * Do metacharacter (i.e. *, ?, [...]) expansion. 5612 */ 5613 5614 static void 5615 expmeta(char *enddir, char *name) 5616 { 5617 char *p; 5618 const char *cp; 5619 char *start; 5620 char *endname; 5621 int metaflag; 5622 struct stat statb; 5623 DIR *dirp; 5624 struct dirent *dp; 5625 int atend; 5626 int matchdot; 5627 5628 metaflag = 0; 5629 start = name; 5630 for (p = name; *p; p++) { 5631 if (*p == '*' || *p == '?') 5632 metaflag = 1; 5633 else if (*p == '[') { 5634 char *q = p + 1; 5635 if (*q == '!') 5636 q++; 5637 for (;;) { 5638 if (*q == '\\') 5639 q++; 5640 if (*q == '/' || *q == '\0') 5641 break; 5642 if (*++q == ']') { 5643 metaflag = 1; 5644 break; 5645 } 5646 } 5647 } else if (*p == '\\') 5648 p++; 5649 else if (*p == '/') { 5650 if (metaflag) 5651 goto out; 5652 start = p + 1; 5653 } 5654 } 5655 out: 5656 if (metaflag == 0) { /* we've reached the end of the file name */ 5657 if (enddir != expdir) 5658 metaflag++; 5659 p = name; 5660 do { 5661 if (*p == '\\') 5662 p++; 5663 *enddir++ = *p; 5664 } while (*p++); 5665 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 5666 addfname(expdir); 5667 return; 5668 } 5669 endname = p; 5670 if (name < start) { 5671 p = name; 5672 do { 5673 if (*p == '\\') 5674 p++; 5675 *enddir++ = *p++; 5676 } while (p < start); 5677 } 5678 if (enddir == expdir) { 5679 cp = "."; 5680 } else if (enddir == expdir + 1 && *expdir == '/') { 5681 cp = "/"; 5682 } else { 5683 cp = expdir; 5684 enddir[-1] = '\0'; 5685 } 5686 if ((dirp = opendir(cp)) == NULL) 5687 return; 5688 if (enddir != expdir) 5689 enddir[-1] = '/'; 5690 if (*endname == 0) { 5691 atend = 1; 5692 } else { 5693 atend = 0; 5694 *endname++ = '\0'; 5695 } 5696 matchdot = 0; 5697 p = start; 5698 if (*p == '\\') 5699 p++; 5700 if (*p == '.') 5701 matchdot++; 5702 while (! intpending && (dp = readdir(dirp)) != NULL) { 5703 if (dp->d_name[0] == '.' && ! matchdot) 5704 continue; 5705 if (pmatch(start, dp->d_name)) { 5706 if (atend) { 5707 scopy(dp->d_name, enddir); 5708 addfname(expdir); 5709 } else { 5710 for (p = enddir, cp = dp->d_name; 5711 (*p++ = *cp++) != '\0';) 5712 continue; 5713 p[-1] = '/'; 5714 expmeta(p, endname); 5715 } 5716 } 5717 } 5718 closedir(dirp); 5719 if (! atend) 5720 endname[-1] = '/'; 5721 } 5722 5723 /* 5724 * Sort the results of file name expansion. It calculates the number of 5725 * strings to sort and then calls msort (short for merge sort) to do the 5726 * work. 5727 */ 5728 5729 static struct strlist * 5730 expsort(struct strlist *str) 5731 { 5732 int len; 5733 struct strlist *sp; 5734 5735 len = 0; 5736 for (sp = str ; sp ; sp = sp->next) 5737 len++; 5738 return msort(str, len); 5739 } 5740 5741 5742 static struct strlist * 5743 msort(struct strlist *list, int len) 5744 { 5745 struct strlist *p, *q = NULL; 5746 struct strlist **lpp; 5747 int half; 5748 int n; 5749 5750 if (len <= 1) 5751 return list; 5752 half = len >> 1; 5753 p = list; 5754 for (n = half ; --n >= 0 ; ) { 5755 q = p; 5756 p = p->next; 5757 } 5758 q->next = NULL; /* terminate first half of list */ 5759 q = msort(list, half); /* sort first half of list */ 5760 p = msort(p, len - half); /* sort second half */ 5761 lpp = &list; 5762 for (;;) { 5763 #ifdef CONFIG_LOCALE_SUPPORT 5764 if (strcoll(p->text, q->text) < 0) 5765 #else 5766 if (strcmp(p->text, q->text) < 0) 5767 #endif 5768 { 5769 *lpp = p; 5770 lpp = &p->next; 5771 if ((p = *lpp) == NULL) { 5772 *lpp = q; 5773 break; 5774 } 5775 } else { 5776 *lpp = q; 5777 lpp = &q->next; 5778 if ((q = *lpp) == NULL) { 5779 *lpp = p; 5780 break; 5781 } 5782 } 5783 } 5784 return list; 5785 } 5786 5787 5788 /* 5789 * Returns true if the pattern matches the string. 5790 */ 5791 5792 static inline int 5793 patmatch(char *pattern, const char *string) 5794 { 5795 return pmatch(preglob(pattern, 0, 0), string); 5796 } 5797 5798 5799 /* 5800 * Remove any CTLESC characters from a string. 5801 */ 5802 5803 static char * 5804 _rmescapes(char *str, int flag) 5805 { 5806 char *p, *q, *r; 5807 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; 5808 unsigned inquotes; 5809 int notescaped; 5810 int globbing; 5811 5812 p = strpbrk(str, qchars); 5813 if (!p) { 5814 return str; 5815 } 5816 q = p; 5817 r = str; 5818 if (flag & RMESCAPE_ALLOC) { 5819 size_t len = p - str; 5820 size_t fulllen = len + strlen(p) + 1; 5821 5822 if (flag & RMESCAPE_GROW) { 5823 r = makestrspace(fulllen, expdest); 5824 } else if (flag & RMESCAPE_HEAP) { 5825 r = ckmalloc(fulllen); 5826 } else { 5827 r = stalloc(fulllen); 5828 } 5829 q = r; 5830 if (len > 0) { 5831 q = mempcpy(q, str, len); 5832 } 5833 } 5834 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5835 globbing = flag & RMESCAPE_GLOB; 5836 notescaped = globbing; 5837 while (*p) { 5838 if (*p == CTLQUOTEMARK) { 5839 inquotes = ~inquotes; 5840 p++; 5841 notescaped = globbing; 5842 continue; 5843 } 5844 if (*p == '\\') { 5845 /* naked back slash */ 5846 notescaped = 0; 5847 goto copy; 5848 } 5849 if (*p == CTLESC) { 5850 p++; 5851 if (notescaped && inquotes && *p != '/') { 5852 *q++ = '\\'; 5853 } 5854 } 5855 notescaped = globbing; 5856 copy: 5857 *q++ = *p++; 5858 } 5859 *q = '\0'; 5860 if (flag & RMESCAPE_GROW) { 5861 expdest = r; 5862 STADJUST(q - r + 1, expdest); 5863 } 5864 return r; 5865 } 5866 5867 5868 /* 5869 * See if a pattern matches in a case statement. 5870 */ 5871 5872 int 5873 casematch(union node *pattern, char *val) 5874 { 5875 struct stackmark smark; 5876 int result; 5877 5878 setstackmark(&smark); 5879 argbackq = pattern->narg.backquote; 5880 STARTSTACKSTR(expdest); 5881 ifslastp = NULL; 5882 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 5883 STACKSTRNUL(expdest); 5884 result = patmatch(stackblock(), val); 5885 popstackmark(&smark); 5886 return result; 5887 } 5888 5889 /* 5890 * Our own itoa(). 5891 */ 5892 5893 static int 5894 cvtnum(arith_t num) 5895 { 5896 int len; 5897 5898 expdest = makestrspace(32, expdest); 5899 #ifdef CONFIG_ASH_MATH_SUPPORT_64 5900 len = fmtstr(expdest, 32, "%lld", (long long) num); 5901 #else 5902 len = fmtstr(expdest, 32, "%ld", num); 5903 #endif 5904 STADJUST(len, expdest); 5905 return len; 5906 } 5907 5908 static void 5909 varunset(const char *end, const char *var, const char *umsg, int varflags) 5910 { 5911 const char *msg; 5912 const char *tail; 5913 5914 tail = nullstr; 5915 msg = "parameter not set"; 5916 if (umsg) { 5917 if (*end == CTLENDVAR) { 5918 if (varflags & VSNUL) 5919 tail = " or null"; 5920 } else 5921 msg = umsg; 5922 } 5923 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5924 } 5925 5926 5927 /* input.c */ 5928 5929 /* 5930 * This implements the input routines used by the parser. 5931 */ 5932 5933 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 5934 5935 static void pushfile(void); 5936 5937 /* 5938 * Read a character from the script, returning PEOF on end of file. 5939 * Nul characters in the input are silently discarded. 5940 */ 5941 5942 5943 #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) 5944 5945 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 5946 #define pgetc_macro() pgetc() 5947 static int 5948 pgetc(void) 5949 { 5950 return pgetc_as_macro(); 5951 } 5952 #else 5953 #define pgetc_macro() pgetc_as_macro() 5954 static int 5955 pgetc(void) 5956 { 5957 return pgetc_macro(); 5958 } 5959 #endif 5960 5961 5962 /* 5963 * Same as pgetc(), but ignores PEOA. 5964 */ 5965 #ifdef CONFIG_ASH_ALIAS 5966 static int pgetc2(void) 5967 { 5968 int c; 5969 5970 do { 5971 c = pgetc_macro(); 5972 } while (c == PEOA); 5973 return c; 5974 } 5975 #else 5976 static inline int pgetc2(void) 5977 { 5978 return pgetc_macro(); 5979 } 5980 #endif 5981 5982 /* 5983 * Read a line from the script. 5984 */ 5985 5986 static inline char * 5987 pfgets(char *line, int len) 5988 { 5989 char *p = line; 5990 int nleft = len; 5991 int c; 5992 5993 while (--nleft > 0) { 5994 c = pgetc2(); 5995 if (c == PEOF) { 5996 if (p == line) 5997 return NULL; 5998 break; 5999 } 6000 *p++ = c; 6001 if (c == '\n') 6002 break; 6003 } 6004 *p = '\0'; 6005 return line; 6006 } 6007 6008 6009 6010 #ifdef CONFIG_FEATURE_COMMAND_EDITING 6011 #ifdef CONFIG_ASH_EXPAND_PRMT 6012 static char *cmdedit_prompt; 6013 #else 6014 static const char *cmdedit_prompt; 6015 #endif 6016 static inline void putprompt(const char *s) 6017 { 6018 #ifdef CONFIG_ASH_EXPAND_PRMT 6019 free(cmdedit_prompt); 6020 cmdedit_prompt = bb_xstrdup(s); 6021 #else 6022 cmdedit_prompt = s; 6023 #endif 6024 } 6025 #else 6026 static inline void putprompt(const char *s) 6027 { 6028 out2str(s); 6029 } 6030 #endif 6031 6032 static inline int 6033 preadfd(void) 6034 { 6035 int nr; 6036 char *buf = parsefile->buf; 6037 parsenextc = buf; 6038 6039 retry: 6040 #ifdef CONFIG_FEATURE_COMMAND_EDITING 6041 if (!iflag || parsefile->fd) 6042 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 6043 else { 6044 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION 6045 cmdedit_path_lookup = pathval(); 6046 #endif 6047 nr = cmdedit_read_input((char *) cmdedit_prompt, buf); 6048 if(nr == 0) { 6049 /* Ctrl+C presend */ 6050 if(trap[SIGINT]) { 6051 buf[0] = '\n'; 6052 buf[1] = 0; 6053 raise(SIGINT); 6054 return 1; 6055 } 6056 goto retry; 6057 } 6058 if(nr < 0 && errno == 0) { 6059 /* Ctrl+D presend */ 6060 nr = 0; 6061 } 6062 } 6063 #else 6064 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 6065 #endif 6066 6067 if (nr < 0) { 6068 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 6069 int flags = fcntl(0, F_GETFL, 0); 6070 if (flags >= 0 && flags & O_NONBLOCK) { 6071 flags &=~ O_NONBLOCK; 6072 if (fcntl(0, F_SETFL, flags) >= 0) { 6073 out2str("sh: turning off NDELAY mode\n"); 6074 goto retry; 6075 } 6076 } 6077 } 6078 } 6079 return nr; 6080 } 6081 6082 /* 6083 * Refill the input buffer and return the next input character: 6084 * 6085 * 1) If a string was pushed back on the input, pop it; 6086 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 6087 * from a string so we can't refill the buffer, return EOF. 6088 * 3) If the is more stuff in this buffer, use it else call read to fill it. 6089 * 4) Process input up to the next newline, deleting nul characters. 6090 */ 6091 6092 int 6093 preadbuffer(void) 6094 { 6095 char *q; 6096 int more; 6097 char savec; 6098 6099 while (parsefile->strpush) { 6100 #ifdef CONFIG_ASH_ALIAS 6101 if (parsenleft == -1 && parsefile->strpush->ap && 6102 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 6103 return PEOA; 6104 } 6105 #endif 6106 popstring(); 6107 if (--parsenleft >= 0) 6108 return SC2INT(*parsenextc++); 6109 } 6110 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 6111 return PEOF; 6112 flushall(); 6113 6114 more = parselleft; 6115 if (more <= 0) { 6116 again: 6117 if ((more = preadfd()) <= 0) { 6118 parselleft = parsenleft = EOF_NLEFT; 6119 return PEOF; 6120 } 6121 } 6122 6123 q = parsenextc; 6124 6125 /* delete nul characters */ 6126 for (;;) { 6127 int c; 6128 6129 more--; 6130 c = *q; 6131 6132 if (!c) 6133 memmove(q, q + 1, more); 6134 else { 6135 q++; 6136 if (c == '\n') { 6137 parsenleft = q - parsenextc - 1; 6138 break; 6139 } 6140 } 6141 6142 if (more <= 0) { 6143 parsenleft = q - parsenextc - 1; 6144 if (parsenleft < 0) 6145 goto again; 6146 break; 6147 } 6148 } 6149 parselleft = more; 6150 6151 savec = *q; 6152 *q = '\0'; 6153 6154 if (vflag) { 6155 out2str(parsenextc); 6156 } 6157 6158 *q = savec; 6159 6160 return SC2INT(*parsenextc++); 6161 } 6162 6163 /* 6164 * Undo the last call to pgetc. Only one character may be pushed back. 6165 * PEOF may be pushed back. 6166 */ 6167 6168 void 6169 pungetc(void) 6170 { 6171 parsenleft++; 6172 parsenextc--; 6173 } 6174 6175 /* 6176 * Push a string back onto the input at this current parsefile level. 6177 * We handle aliases this way. 6178 */ 6179 void 6180 pushstring(char *s, void *ap) 6181 { 6182 struct strpush *sp; 6183 size_t len; 6184 6185 len = strlen(s); 6186 INTOFF; 6187 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 6188 if (parsefile->strpush) { 6189 sp = ckmalloc(sizeof (struct strpush)); 6190 sp->prev = parsefile->strpush; 6191 parsefile->strpush = sp; 6192 } else 6193 sp = parsefile->strpush = &(parsefile->basestrpush); 6194 sp->prevstring = parsenextc; 6195 sp->prevnleft = parsenleft; 6196 #ifdef CONFIG_ASH_ALIAS 6197 sp->ap = (struct alias *)ap; 6198 if (ap) { 6199 ((struct alias *)ap)->flag |= ALIASINUSE; 6200 sp->string = s; 6201 } 6202 #endif 6203 parsenextc = s; 6204 parsenleft = len; 6205 INTON; 6206 } 6207 6208 void 6209 popstring(void) 6210 { 6211 struct strpush *sp = parsefile->strpush; 6212 6213 INTOFF; 6214 #ifdef CONFIG_ASH_ALIAS 6215 if (sp->ap) { 6216 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 6217 checkkwd |= CHKALIAS; 6218 } 6219 if (sp->string != sp->ap->val) { 6220 ckfree(sp->string); 6221 } 6222 sp->ap->flag &= ~ALIASINUSE; 6223 if (sp->ap->flag & ALIASDEAD) { 6224 unalias(sp->ap->name); 6225 } 6226 } 6227 #endif 6228 parsenextc = sp->prevstring; 6229 parsenleft = sp->prevnleft; 6230 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 6231 parsefile->strpush = sp->prev; 6232 if (sp != &(parsefile->basestrpush)) 6233 ckfree(sp); 6234 INTON; 6235 } 6236 6237 /* 6238 * Set the input to take input from a file. If push is set, push the 6239 * old input onto the stack first. 6240 */ 6241 6242 static int 6243 setinputfile(const char *fname, int flags) 6244 { 6245 int fd; 6246 int fd2; 6247 6248 INTOFF; 6249 if ((fd = open(fname, O_RDONLY)) < 0) { 6250 if (flags & INPUT_NOFILE_OK) 6251 goto out; 6252 sh_error("Can't open %s", fname); 6253 } 6254 if (fd < 10) { 6255 fd2 = copyfd(fd, 10); 6256 close(fd); 6257 if (fd2 < 0) 6258 sh_error("Out of file descriptors"); 6259 fd = fd2; 6260 } 6261 setinputfd(fd, flags & INPUT_PUSH_FILE); 6262 out: 6263 INTON; 6264 return fd; 6265 } 6266 6267 6268 /* 6269 * Like setinputfile, but takes an open file descriptor. Call this with 6270 * interrupts off. 6271 */ 6272 6273 static void 6274 setinputfd(int fd, int push) 6275 { 6276 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 6277 if (push) { 6278 pushfile(); 6279 parsefile->buf = 0; 6280 } 6281 parsefile->fd = fd; 6282 if (parsefile->buf == NULL) 6283 parsefile->buf = ckmalloc(IBUFSIZ); 6284 parselleft = parsenleft = 0; 6285 plinno = 1; 6286 } 6287 6288 6289 /* 6290 * Like setinputfile, but takes input from a string. 6291 */ 6292 6293 static void 6294 setinputstring(char *string) 6295 { 6296 INTOFF; 6297 pushfile(); 6298 parsenextc = string; 6299 parsenleft = strlen(string); 6300 parsefile->buf = NULL; 6301 plinno = 1; 6302 INTON; 6303 } 6304 6305 6306 /* 6307 * To handle the "." command, a stack of input files is used. Pushfile 6308 * adds a new entry to the stack and popfile restores the previous level. 6309 */ 6310 6311 static void 6312 pushfile(void) 6313 { 6314 struct parsefile *pf; 6315 6316 parsefile->nleft = parsenleft; 6317 parsefile->lleft = parselleft; 6318 parsefile->nextc = parsenextc; 6319 parsefile->linno = plinno; 6320 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 6321 pf->prev = parsefile; 6322 pf->fd = -1; 6323 pf->strpush = NULL; 6324 pf->basestrpush.prev = NULL; 6325 parsefile = pf; 6326 } 6327 6328 6329 static void 6330 popfile(void) 6331 { 6332 struct parsefile *pf = parsefile; 6333 6334 INTOFF; 6335 if (pf->fd >= 0) 6336 close(pf->fd); 6337 if (pf->buf) 6338 ckfree(pf->buf); 6339 while (pf->strpush) 6340 popstring(); 6341 parsefile = pf->prev; 6342 ckfree(pf); 6343 parsenleft = parsefile->nleft; 6344 parselleft = parsefile->lleft; 6345 parsenextc = parsefile->nextc; 6346 plinno = parsefile->linno; 6347 INTON; 6348 } 6349 6350 6351 /* 6352 * Return to top level. 6353 */ 6354 6355 static void 6356 popallfiles(void) 6357 { 6358 while (parsefile != &basepf) 6359 popfile(); 6360 } 6361 6362 6363 /* 6364 * Close the file(s) that the shell is reading commands from. Called 6365 * after a fork is done. 6366 */ 6367 6368 static void 6369 closescript(void) 6370 { 6371 popallfiles(); 6372 if (parsefile->fd > 0) { 6373 close(parsefile->fd); 6374 parsefile->fd = 0; 6375 } 6376 } 6377 6378 /* jobs.c */ 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); 3245 } 6379 3246 6380 3247 /* mode flags for set_curjob */ … … 6387 3254 #define DOWAIT_BLOCK 1 6388 3255 3256 #if JOBS 3257 /* pgrp of shell on invocation */ 3258 static int initialpgrp; 3259 static int ttyfd = -1; 3260 #endif 6389 3261 /* array of jobs */ 6390 3262 static struct job *jobtab; 6391 3263 /* size of array */ 6392 3264 static unsigned njobs; 6393 #if JOBS6394 /* pgrp of shell on invocation */6395 static int initialpgrp;6396 static int ttyfd = -1;6397 #endif6398 3265 /* current job */ 6399 3266 static struct job *curjob; 6400 3267 /* number of presumed living untracked jobs */ 6401 3268 static int jobless; 6402 6403 static void set_curjob(struct job *, unsigned);6404 #if JOBS6405 static int restartjob(struct job *, int);6406 static void xtcsetpgrp(int, pid_t);6407 static char *commandtext(union node *);6408 static void cmdlist(union node *, int);6409 static void cmdtxt(union node *);6410 static void cmdputs(const char *);6411 static void showpipe(struct job *, FILE *);6412 #endif6413 static int sprint_status(char *, int, int);6414 static void freejob(struct job *);6415 static struct job *getjob(const char *, int);6416 static struct job *growjobtab(void);6417 static void forkchild(struct job *, union node *, int);6418 static void forkparent(struct job *, union node *, int, pid_t);6419 static int dowait(int, struct job *);6420 static int getstatus(struct job *);6421 3269 6422 3270 static void … … 6440 3288 switch (mode) { 6441 3289 default: 6442 #if defDEBUG3290 #if DEBUG 6443 3291 abort(); 6444 3292 #endif … … 6468 3316 } 6469 3317 3318 #if JOBS || DEBUG 3319 static int 3320 jobno(const struct job *jp) 3321 { 3322 return jp - jobtab + 1; 3323 } 3324 #endif 3325 3326 /* 3327 * Convert a job name to a job structure. 3328 */ 3329 static struct job * 3330 getjob(const char *name, int getctl) 3331 { 3332 struct job *jp; 3333 struct job *found; 3334 const char *err_msg = "No such job: %s"; 3335 unsigned num; 3336 int c; 3337 const char *p; 3338 char *(*match)(const char *, const char *); 3339 3340 jp = curjob; 3341 p = name; 3342 if (!p) 3343 goto currentjob; 3344 3345 if (*p != '%') 3346 goto err; 3347 3348 c = *++p; 3349 if (!c) 3350 goto currentjob; 3351 3352 if (!p[1]) { 3353 if (c == '+' || c == '%') { 3354 currentjob: 3355 err_msg = "No current job"; 3356 goto check; 3357 } 3358 if (c == '-') { 3359 if (jp) 3360 jp = jp->prev_job; 3361 err_msg = "No previous job"; 3362 check: 3363 if (!jp) 3364 goto err; 3365 goto gotit; 3366 } 3367 } 3368 3369 if (is_number(p)) { 3370 num = atoi(p); 3371 if (num < njobs) { 3372 jp = jobtab + num - 1; 3373 if (jp->used) 3374 goto gotit; 3375 goto err; 3376 } 3377 } 3378 3379 match = prefix; 3380 if (*p == '?') { 3381 match = strstr; 3382 p++; 3383 } 3384 3385 found = 0; 3386 while (1) { 3387 if (!jp) 3388 goto err; 3389 if (match(jp->ps[0].cmd, p)) { 3390 if (found) 3391 goto err; 3392 found = jp; 3393 err_msg = "%s: ambiguous"; 3394 } 3395 jp = jp->prev_job; 3396 } 3397 3398 gotit: 6470 3399 #if JOBS 3400 err_msg = "job %s not created under job control"; 3401 if (getctl && jp->jobctl == 0) 3402 goto err; 3403 #endif 3404 return jp; 3405 err: 3406 ash_msg_and_raise_error(err_msg, name); 3407 } 3408 3409 /* 3410 * Mark a job structure as unused. 3411 */ 3412 static void 3413 freejob(struct job *jp) 3414 { 3415 struct procstat *ps; 3416 int i; 3417 3418 INT_OFF; 3419 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 3420 if (ps->cmd != nullstr) 3421 free(ps->cmd); 3422 } 3423 if (jp->ps != &jp->ps0) 3424 free(jp->ps); 3425 jp->used = 0; 3426 set_curjob(jp, CUR_DELETE); 3427 INT_ON; 3428 } 3429 3430 #if JOBS 3431 static void 3432 xtcsetpgrp(int fd, pid_t pgrp) 3433 { 3434 if (tcsetpgrp(fd, pgrp)) 3435 ash_msg_and_raise_error("cannot set tty process group (%m)"); 3436 } 3437 6471 3438 /* 6472 3439 * Turn job control on and off. … … 6478 3445 * Called with interrupts off. 6479 3446 */ 6480 6481 void 3447 static void 6482 3448 setjobctl(int on) 6483 3449 { … … 6491 3457 ofd = fd = open(_PATH_TTY, O_RDWR); 6492 3458 if (fd < 0) { 3459 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails. 3460 * That sometimes helps to acquire controlling tty. 3461 * Obviously, a workaround for bugs when someone 3462 * failed to provide a controlling tty to bash! :) */ 6493 3463 fd += 3; 6494 3464 while (!isatty(fd) && --fd >= 0) … … 6501 3471 fcntl(fd, F_SETFD, FD_CLOEXEC); 6502 3472 do { /* while we are in the background */ 6503 if ((pgrp = tcgetpgrp(fd)) < 0) { 6504 out: 6505 sh_warnx("can't access tty; job control turned off"); 3473 pgrp = tcgetpgrp(fd); 3474 if (pgrp < 0) { 3475 out: 3476 ash_msg("can't access tty; job control turned off"); 6506 3477 mflag = on = 0; 6507 3478 goto close; … … 6523 3494 fd = ttyfd; 6524 3495 pgrp = initialpgrp; 6525 xtcsetpgrp(fd, pgrp); 3496 /* was xtcsetpgrp, but this can make exiting ash 3497 * with pty already deleted loop forever */ 3498 tcsetpgrp(fd, pgrp); 6526 3499 setpgid(0, pgrp); 6527 3500 setsignal(SIGTSTP); 6528 3501 setsignal(SIGTTOU); 6529 3502 setsignal(SIGTTIN); 6530 close:3503 close: 6531 3504 close(fd); 6532 3505 fd = -1; … … 6539 3512 killcmd(int argc, char **argv) 6540 3513 { 6541 int signo = -1; 6542 int list = 0; 6543 int i; 6544 pid_t pid; 6545 struct job *jp; 6546 6547 if (argc <= 1) { 6548 usage: 6549 sh_error( 6550 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" 6551 "kill -l [exitstatus]" 6552 ); 6553 } 6554 6555 if (**++argv == '-') { 6556 signo = decode_signal(*argv + 1, 1); 6557 if (signo < 0) { 6558 int c; 6559 6560 while ((c = nextopt("ls:")) != '\0') 6561 switch (c) { 6562 default: 6563 #ifdef DEBUG 6564 abort(); 6565 #endif 6566 case 'l': 6567 list = 1; 6568 break; 6569 case 's': 6570 signo = decode_signal(optionarg, 1); 6571 if (signo < 0) { 6572 sh_error( 6573 "invalid signal number or name: %s", 6574 optionarg 6575 ); 6576 } 6577 break; 6578 } 6579 argv = argptr; 6580 } else 6581 argv++; 6582 } 6583 6584 if (!list && signo < 0) 6585 signo = SIGTERM; 6586 6587 if ((signo < 0 || !*argv) ^ list) { 6588 goto usage; 6589 } 6590 6591 if (list) { 6592 const char *name; 6593 6594 if (!*argv) { 6595 for (i = 1; i < NSIG; i++) { 6596 name = u_signal_names(0, &i, 1); 6597 if (name) 6598 out1fmt(snlfmt, name); 3514 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3515 int i = 1; 3516 do { 3517 if (argv[i][0] == '%') { 3518 struct job *jp = getjob(argv[i], 0); 3519 unsigned pid = jp->ps[0].pid; 3520 /* Enough space for ' -NNN<nul>' */ 3521 argv[i] = alloca(sizeof(int)*3 + 3); 3522 /* kill_main has matching code to expect 3523 * leading space. Needed to not confuse 3524 * negative pids with "kill -SIGNAL_NO" syntax */ 3525 sprintf(argv[i], " -%u", pid); 6599 3526 } 6600 return 0; 6601 } 6602 name = u_signal_names(*argptr, &signo, -1); 6603 if (name) 6604 out1fmt(snlfmt, name); 6605 else 6606 sh_error("invalid signal number or exit status: %s", *argptr); 6607 return 0; 6608 } 6609 6610 i = 0; 6611 do { 6612 if (**argv == '%') { 6613 jp = getjob(*argv, 0); 6614 pid = -jp->ps[0].pid; 6615 } else { 6616 pid = **argv == '-' ? 6617 -number(*argv + 1) : number(*argv); 6618 } 6619 if (kill(pid, signo) != 0) { 6620 sh_warnx("(%d) - %m", pid); 6621 i = 1; 6622 } 6623 } while (*++argv); 6624 6625 return i; 6626 } 6627 #endif /* JOBS */ 6628 6629 #if defined(JOBS) || defined(DEBUG) 6630 static int 6631 jobno(const struct job *jp) 6632 { 6633 return jp - jobtab + 1; 6634 } 6635 #endif 6636 6637 #if JOBS 6638 static int 6639 fgcmd(int argc, char **argv) 6640 { 6641 struct job *jp; 6642 FILE *out; 6643 int mode; 6644 int retval; 6645 6646 mode = (**argv == 'f') ? FORK_FG : FORK_BG; 6647 nextopt(nullstr); 6648 argv = argptr; 6649 out = stdout; 6650 do { 6651 jp = getjob(*argv, 1); 6652 if (mode == FORK_BG) { 6653 set_curjob(jp, CUR_RUNNING); 6654 fprintf(out, "[%d] ", jobno(jp)); 6655 } 6656 outstr(jp->ps->cmd, out); 6657 showpipe(jp, out); 6658 retval = restartjob(jp, mode); 6659 } while (*argv && *++argv); 6660 return retval; 6661 } 6662 6663 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd"))); 3527 } while (argv[++i]); 3528 } 3529 return kill_main(argc, argv); 3530 } 3531 3532 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); 3542 flush_stdout_stderr(); 3543 } 6664 3544 6665 3545 … … 6672 3552 pid_t pgid; 6673 3553 6674 INT OFF;3554 INT_OFF; 6675 3555 if (jp->state == JOBDONE) 6676 3556 goto out; … … 6686 3566 ps->status = -1; 6687 3567 } 6688 } while (ps++, --i); 6689 out: 3568 ps++; 3569 } while (--i); 3570 out: 6690 3571 status = (mode == FORK_FG) ? waitforjob(jp) : 0; 6691 INT ON;3572 INT_ON; 6692 3573 return status; 3574 } 3575 3576 static int 3577 fg_bgcmd(int argc, char **argv) 3578 { 3579 struct job *jp; 3580 FILE *out; 3581 int mode; 3582 int retval; 3583 3584 mode = (**argv == 'f') ? FORK_FG : FORK_BG; 3585 nextopt(nullstr); 3586 argv = argptr; 3587 out = stdout; 3588 do { 3589 jp = getjob(*argv, 1); 3590 if (mode == FORK_BG) { 3591 set_curjob(jp, CUR_RUNNING); 3592 fprintf(out, "[%d] ", jobno(jp)); 3593 } 3594 outstr(jp->ps->cmd, out); 3595 showpipe(jp, out); 3596 retval = restartjob(jp, mode); 3597 } while (*argv && *++argv); 3598 return retval; 6693 3599 } 6694 3600 #endif … … 6728 3634 col = fmtstr(s, 16, "Done"); 6729 3635 } 6730 6731 out: 3636 out: 6732 3637 return col; 6733 3638 } 6734 6735 #if JOBS6736 static void6737 showjob(FILE *out, struct job *jp, int mode)6738 {6739 struct procstat *ps;6740 struct procstat *psend;6741 int col;6742 int indent;6743 char s[80];6744 6745 ps = jp->ps;6746 6747 if (mode & SHOW_PGID) {6748 /* just output process (group) id of pipeline */6749 fprintf(out, "%d\n", ps->pid);6750 return;6751 }6752 6753 col = fmtstr(s, 16, "[%d] ", jobno(jp));6754 indent = col;6755 6756 if (jp == curjob)6757 s[col - 2] = '+';6758 else if (curjob && jp == curjob->prev_job)6759 s[col - 2] = '-';6760 6761 if (mode & SHOW_PID)6762 col += fmtstr(s + col, 16, "%d ", ps->pid);6763 6764 psend = ps + jp->nprocs;6765 6766 if (jp->state == JOBRUNNING) {6767 scopy("Running", s + col);6768 col += strlen("Running");6769 } else {6770 int status = psend[-1].status;6771 #if JOBS6772 if (jp->state == JOBSTOPPED)6773 status = jp->stopstatus;6774 #endif6775 col += sprint_status(s + col, status, 0);6776 }6777 6778 goto start;6779 6780 do {6781 /* for each process */6782 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;6783 6784 start:6785 fprintf(out, "%s%*c%s",6786 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd6787 );6788 if (!(mode & SHOW_PID)) {6789 showpipe(jp, out);6790 break;6791 }6792 if (++ps == psend) {6793 outcslow('\n', out);6794 break;6795 }6796 } while (1);6797 6798 jp->changed = 0;6799 6800 if (jp->state == JOBDONE) {6801 TRACE(("showjob: freeing job %d\n", jobno(jp)));6802 freejob(jp);6803 }6804 }6805 6806 6807 static int6808 jobscmd(int argc, char **argv)6809 {6810 int mode, m;6811 FILE *out;6812 6813 mode = 0;6814 while ((m = nextopt("lp")))6815 if (m == 'l')6816 mode = SHOW_PID;6817 else6818 mode = SHOW_PGID;6819 6820 out = stdout;6821 argv = argptr;6822 if (*argv)6823 do6824 showjob(out, getjob(*argv,0), mode);6825 while (*++argv);6826 else6827 showjobs(out, mode);6828 6829 return 0;6830 }6831 6832 6833 /*6834 * Print a list of jobs. If "change" is nonzero, only print jobs whose6835 * statuses have changed since the last call to showjobs.6836 */6837 6838 static void6839 showjobs(FILE *out, int mode)6840 {6841 struct job *jp;6842 6843 TRACE(("showjobs(%x) called\n", mode));6844 6845 /* If not even one one job changed, there is nothing to do */6846 while (dowait(DOWAIT_NORMAL, NULL) > 0)6847 continue;6848 6849 for (jp = curjob; jp; jp = jp->prev_job) {6850 if (!(mode & SHOW_CHANGED) || jp->changed)6851 showjob(out, jp, mode);6852 }6853 }6854 #endif /* JOBS */6855 6856 /*6857 * Mark a job structure as unused.6858 */6859 6860 static void6861 freejob(struct job *jp)6862 {6863 struct procstat *ps;6864 int i;6865 6866 INTOFF;6867 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {6868 if (ps->cmd != nullstr)6869 ckfree(ps->cmd);6870 }6871 if (jp->ps != &jp->ps0)6872 ckfree(jp->ps);6873 jp->used = 0;6874 set_curjob(jp, CUR_DELETE);6875 INTON;6876 }6877 6878 6879 static int6880 waitcmd(int argc, char **argv)6881 {6882 struct job *job;6883 int retval;6884 struct job *jp;6885 6886 EXSIGON();6887 6888 nextopt(nullstr);6889 retval = 0;6890 6891 argv = argptr;6892 if (!*argv) {6893 /* wait for all jobs */6894 for (;;) {6895 jp = curjob;6896 while (1) {6897 if (!jp) {6898 /* no running procs */6899 goto out;6900 }6901 if (jp->state == JOBRUNNING)6902 break;6903 jp->waited = 1;6904 jp = jp->prev_job;6905 }6906 dowait(DOWAIT_BLOCK, 0);6907 }6908 }6909 6910 retval = 127;6911 do {6912 if (**argv != '%') {6913 pid_t pid = number(*argv);6914 job = curjob;6915 goto start;6916 do {6917 if (job->ps[job->nprocs - 1].pid == pid)6918 break;6919 job = job->prev_job;6920 start:6921 if (!job)6922 goto repeat;6923 } while (1);6924 } else6925 job = getjob(*argv, 0);6926 /* loop until process terminated or stopped */6927 while (job->state == JOBRUNNING)6928 dowait(DOWAIT_BLOCK, 0);6929 job->waited = 1;6930 retval = getstatus(job);6931 repeat:6932 ;6933 } while (*++argv);6934 6935 out:6936 return retval;6937 }6938 6939 6940 /*6941 * Convert a job name to a job structure.6942 */6943 6944 static struct job *6945 getjob(const char *name, int getctl)6946 {6947 struct job *jp;6948 struct job *found;6949 const char *err_msg = "No such job: %s";6950 unsigned num;6951 int c;6952 const char *p;6953 char *(*match)(const char *, const char *);6954 6955 jp = curjob;6956 p = name;6957 if (!p)6958 goto currentjob;6959 6960 if (*p != '%')6961 goto err;6962 6963 c = *++p;6964 if (!c)6965 goto currentjob;6966 6967 if (!p[1]) {6968 if (c == '+' || c == '%') {6969 currentjob:6970 err_msg = "No current job";6971 goto check;6972 } else if (c == '-') {6973 if (jp)6974 jp = jp->prev_job;6975 err_msg = "No previous job";6976 check:6977 if (!jp)6978 goto err;6979 goto gotit;6980 }6981 }6982 6983 if (is_number(p)) {6984 num = atoi(p);6985 if (num < njobs) {6986 jp = jobtab + num - 1;6987 if (jp->used)6988 goto gotit;6989 goto err;6990 }6991 }6992 6993 match = prefix;6994 if (*p == '?') {6995 match = strstr;6996 p++;6997 }6998 6999 found = 0;7000 while (1) {7001 if (!jp)7002 goto err;7003 if (match(jp->ps[0].cmd, p)) {7004 if (found)7005 goto err;7006 found = jp;7007 err_msg = "%s: ambiguous";7008 }7009 jp = jp->prev_job;7010 }7011 7012 gotit:7013 #if JOBS7014 err_msg = "job %s not created under job control";7015 if (getctl && jp->jobctl == 0)7016 goto err;7017 #endif7018 return jp;7019 err:7020 sh_error(err_msg, name);7021 }7022 7023 7024 /*7025 * Return a new job structure.7026 * Called with interrupts off.7027 */7028 7029 static struct job *7030 makejob(union node *node, int nprocs)7031 {7032 int i;7033 struct job *jp;7034 7035 for (i = njobs, jp = jobtab ; ; jp++) {7036 if (--i < 0) {7037 jp = growjobtab();7038 break;7039 }7040 if (jp->used == 0)7041 break;7042 if (jp->state != JOBDONE || !jp->waited)7043 continue;7044 #if JOBS7045 if (jobctl)7046 continue;7047 #endif7048 freejob(jp);7049 break;7050 }7051 memset(jp, 0, sizeof(*jp));7052 #if JOBS7053 if (jobctl)7054 jp->jobctl = 1;7055 #endif7056 jp->prev_job = curjob;7057 curjob = jp;7058 jp->used = 1;7059 jp->ps = &jp->ps0;7060 if (nprocs > 1) {7061 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));7062 }7063 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,7064 jobno(jp)));7065 return jp;7066 }7067 7068 static struct job *7069 growjobtab(void)7070 {7071 size_t len;7072 ptrdiff_t offset;7073 struct job *jp, *jq;7074 7075 len = njobs * sizeof(*jp);7076 jq = jobtab;7077 jp = ckrealloc(jq, len + 4 * sizeof(*jp));7078 7079 offset = (char *)jp - (char *)jq;7080 if (offset) {7081 /* Relocate pointers */7082 size_t l = len;7083 7084 jq = (struct job *)((char *)jq + l);7085 while (l) {7086 l -= sizeof(*jp);7087 jq--;7088 #define joff(p) ((struct job *)((char *)(p) + l))7089 #define jmove(p) (p) = (void *)((char *)(p) + offset)7090 if (xlikely(joff(jp)->ps == &jq->ps0))7091 jmove(joff(jp)->ps);7092 if (joff(jp)->prev_job)7093 jmove(joff(jp)->prev_job);7094 }7095 if (curjob)7096 jmove(curjob);7097 #undef joff7098 #undef jmove7099 }7100 7101 njobs += 4;7102 jobtab = jp;7103 jp = (struct job *)((char *)jp + len);7104 jq = jp + 3;7105 do {7106 jq->used = 0;7107 } while (--jq >= jp);7108 return jp;7109 }7110 7111 7112 /*7113 * Fork off a subshell. If we are doing job control, give the subshell its7114 * own process group. Jp is a job structure that the job is to be added to.7115 * N is the command that will be evaluated by the child. Both jp and n may7116 * be NULL. The mode parameter can be one of the following:7117 * FORK_FG - Fork off a foreground process.7118 * FORK_BG - Fork off a background process.7119 * FORK_NOJOB - Like FORK_FG, but don't give the process its own7120 * process group even if job control is on.7121 *7122 * When job control is turned off, background processes have their standard7123 * input redirected to /dev/null (except for the second and later processes7124 * in a pipeline).7125 *7126 * Called with interrupts off.7127 */7128 7129 static inline void7130 forkchild(struct job *jp, union node *n, int mode)7131 {7132 int oldlvl;7133 7134 TRACE(("Child shell %d\n", getpid()));7135 oldlvl = shlvl;7136 shlvl++;7137 7138 closescript();7139 clear_traps();7140 #if JOBS7141 /* do job control only in root shell */7142 jobctl = 0;7143 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {7144 pid_t pgrp;7145 7146 if (jp->nprocs == 0)7147 pgrp = getpid();7148 else7149 pgrp = jp->ps[0].pid;7150 /* This can fail because we are doing it in the parent also */7151 (void)setpgid(0, pgrp);7152 if (mode == FORK_FG)7153 xtcsetpgrp(ttyfd, pgrp);7154 setsignal(SIGTSTP);7155 setsignal(SIGTTOU);7156 } else7157 #endif7158 if (mode == FORK_BG) {7159 ignoresig(SIGINT);7160 ignoresig(SIGQUIT);7161 if (jp->nprocs == 0) {7162 close(0);7163 if (open(bb_dev_null, O_RDONLY) != 0)7164 sh_error("Can't open %s", bb_dev_null);7165 }7166 }7167 if (!oldlvl && iflag) {7168 setsignal(SIGINT);7169 setsignal(SIGQUIT);7170 setsignal(SIGTERM);7171 }7172 for (jp = curjob; jp; jp = jp->prev_job)7173 freejob(jp);7174 jobless = 0;7175 }7176 7177 static inline void7178 forkparent(struct job *jp, union node *n, int mode, pid_t pid)7179 {7180 TRACE(("In parent shell: child = %d\n", pid));7181 if (!jp) {7182 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);7183 jobless++;7184 return;7185 }7186 #if JOBS7187 if (mode != FORK_NOJOB && jp->jobctl) {7188 int pgrp;7189 7190 if (jp->nprocs == 0)7191 pgrp = pid;7192 else7193 pgrp = jp->ps[0].pid;7194 /* This can fail because we are doing it in the child also */7195 (void)setpgid(pid, pgrp);7196 }7197 #endif7198 if (mode == FORK_BG) {7199 backgndpid = pid; /* set $! */7200 set_curjob(jp, CUR_RUNNING);7201 }7202 if (jp) {7203 struct procstat *ps = &jp->ps[jp->nprocs++];7204 ps->pid = pid;7205 ps->status = -1;7206 ps->cmd = nullstr;7207 #if JOBS7208 if (jobctl && n)7209 ps->cmd = commandtext(n);7210 #endif7211 }7212 }7213 7214 static int7215 forkshell(struct job *jp, union node *n, int mode)7216 {7217 int pid;7218 7219 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));7220 pid = fork();7221 if (pid < 0) {7222 TRACE(("Fork failed, errno=%d", errno));7223 if (jp)7224 freejob(jp);7225 sh_error("Cannot fork");7226 }7227 if (pid == 0)7228 forkchild(jp, n, mode);7229 else7230 forkparent(jp, n, mode, pid);7231 return pid;7232 }7233 7234 /*7235 * Wait for job to finish.7236 *7237 * Under job control we have the problem that while a child process is7238 * running interrupts generated by the user are sent to the child but not7239 * to the shell. This means that an infinite loop started by an inter-7240 * active user may be hard to kill. With job control turned off, an7241 * interactive user may place an interactive program inside a loop. If7242 * the interactive program catches interrupts, the user doesn't want7243 * these interrupts to also abort the loop. The approach we take here7244 * is to have the shell ignore interrupt signals while waiting for a7245 * foreground process to terminate, and then send itself an interrupt7246 * signal if the child process was terminated by an interrupt signal.7247 * Unfortunately, some programs want to do a bit of cleanup and then7248 * exit on interrupt; unless these processes terminate themselves by7249 * sending a signal to themselves (instead of calling exit) they will7250 * confuse this approach.7251 *7252 * Called with interrupts off.7253 */7254 7255 int7256 waitforjob(struct job *jp)7257 {7258 int st;7259 7260 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));7261 while (jp->state == JOBRUNNING) {7262 dowait(DOWAIT_BLOCK, jp);7263 }7264 st = getstatus(jp);7265 #if JOBS7266 if (jp->jobctl) {7267 xtcsetpgrp(ttyfd, rootpid);7268 /*7269 * This is truly gross.7270 * If we're doing job control, then we did a TIOCSPGRP which7271 * caused us (the shell) to no longer be in the controlling7272 * session -- so we wouldn't have seen any ^C/SIGINT. So, we7273 * intuit from the subprocess exit status whether a SIGINT7274 * occurred, and if so interrupt ourselves. Yuck. - mycroft7275 */7276 if (jp->sigint)7277 raise(SIGINT);7278 }7279 if (jp->state == JOBDONE)7280 #endif7281 freejob(jp);7282 return st;7283 }7284 7285 3639 7286 3640 /* … … 7312 3666 * and the jobs command may give out of date information. 7313 3667 */ 7314 7315 static inline int 3668 static int 7316 3669 waitproc(int block, int *status) 7317 3670 { … … 7330 3683 * Wait for a process to terminate. 7331 3684 */ 7332 7333 3685 static int 7334 3686 dowait(int block, struct job *job) … … 7345 3697 if (pid <= 0) 7346 3698 return pid; 7347 INT OFF;3699 INT_OFF; 7348 3700 thisjob = NULL; 7349 3701 for (jp = curjob; jp; jp = jp->prev_job) { … … 7357 3709 do { 7358 3710 if (sp->pid == pid) { 7359 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status)); 3711 TRACE(("Job %d: changing status of proc %d " 3712 "from 0x%x to 0x%x\n", 3713 jobno(jp), pid, sp->status, status)); 7360 3714 sp->status = status; 7361 3715 thisjob = jp; … … 7382 3736 goto out; 7383 3737 7384 gotjob:3738 gotjob: 7385 3739 if (state != JOBRUNNING) { 7386 3740 thisjob->changed = 1; 7387 3741 7388 3742 if (thisjob->state != state) { 7389 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state)); 3743 TRACE(("Job %d: changing state from %d to %d\n", 3744 jobno(thisjob), thisjob->state, state)); 7390 3745 thisjob->state = state; 7391 3746 #if JOBS … … 7397 3752 } 7398 3753 7399 out:7400 INT ON;3754 out: 3755 INT_ON; 7401 3756 7402 3757 if (thisjob && thisjob == job) { … … 7414 3769 } 7415 3770 7416 7417 /* 7418 * return 1 if there are stopped jobs, otherwise 0 7419 */ 7420 7421 int 7422 stoppedjobs(void) 3771 #if JOBS 3772 static void 3773 showjob(FILE *out, struct job *jp, int mode) 3774 { 3775 struct procstat *ps; 3776 struct procstat *psend; 3777 int col; 3778 int indent_col; 3779 char s[80]; 3780 3781 ps = jp->ps; 3782 3783 if (mode & SHOW_PGID) { 3784 /* just output process (group) id of pipeline */ 3785 fprintf(out, "%d\n", ps->pid); 3786 return; 3787 } 3788 3789 col = fmtstr(s, 16, "[%d] ", jobno(jp)); 3790 indent_col = col; 3791 3792 if (jp == curjob) 3793 s[col - 2] = '+'; 3794 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->pid); 3799 3800 psend = ps + jp->nprocs; 3801 3802 if (jp->state == JOBRUNNING) { 3803 strcpy(s + col, "Running"); 3804 col += sizeof("Running") - 1; 3805 } else { 3806 int status = psend[-1].status; 3807 if (jp->state == JOBSTOPPED) 3808 status = jp->stopstatus; 3809 col += sprint_status(s + col, status, 0); 3810 } 3811 3812 goto start; 3813 3814 do { 3815 /* for each process */ 3816 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3; 3817 start: 3818 fprintf(out, "%s%*c%s", 3819 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd 3820 ); 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); 3830 3831 jp->changed = 0; 3832 3833 if (jp->state == JOBDONE) { 3834 TRACE(("showjob: freeing job %d\n", jobno(jp))); 3835 freejob(jp); 3836 } 3837 } 3838 3839 /* 3840 * Print a list of jobs. If "change" is nonzero, only print jobs whose 3841 * statuses have changed since the last call to showjobs. 3842 */ 3843 static void 3844 showjobs(FILE *out, int mode) 7423 3845 { 7424 3846 struct job *jp; 3847 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_NORMAL, NULL) > 0) 3852 continue; 3853 3854 for (jp = curjob; jp; jp = jp->prev_job) { 3855 if (!(mode & SHOW_CHANGED) || jp->changed) { 3856 showjob(out, jp, mode); 3857 } 3858 } 3859 } 3860 3861 static int 3862 jobscmd(int argc, char **argv) 3863 { 3864 int mode, m; 3865 3866 mode = 0; 3867 while ((m = nextopt("lp"))) { 3868 if (m == 'l') 3869 mode = SHOW_PID; 3870 else 3871 mode = SHOW_PGID; 3872 } 3873 3874 argv = argptr; 3875 if (*argv) { 3876 do 3877 showjob(stdout, getjob(*argv,0), mode); 3878 while (*++argv); 3879 } else 3880 showjobs(stdout, mode); 3881 3882 return 0; 3883 } 3884 #endif /* JOBS */ 3885 3886 static int 3887 getstatus(struct job *job) 3888 { 3889 int status; 7425 3890 int retval; 7426 3891 3892 status = job->ps[job->nprocs - 1].status; 3893 retval = WEXITSTATUS(status); 3894 if (!WIFEXITED(status)) { 3895 #if JOBS 3896 retval = WSTOPSIG(status); 3897 if (!WIFSTOPPED(status)) 3898 #endif 3899 { 3900 /* XXX: limits number of signals */ 3901 retval = WTERMSIG(status); 3902 #if JOBS 3903 if (retval == SIGINT) 3904 job->sigint = 1; 3905 #endif 3906 } 3907 retval += 128; 3908 } 3909 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", 3910 jobno(job), job->nprocs, status, retval)); 3911 return retval; 3912 } 3913 3914 static int 3915 waitcmd(int argc, char **argv) 3916 { 3917 struct job *job; 3918 int retval; 3919 struct job *jp; 3920 3921 EXSIGON; 3922 3923 nextopt(nullstr); 7427 3924 retval = 0; 7428 if (job_warning) 7429 goto out; 7430 jp = curjob; 7431 if (jp && jp->state == JOBSTOPPED) { 7432 out2str("You have stopped jobs.\n"); 7433 job_warning = 2; 7434 retval++; 7435 } 7436 7437 out: 3925 3926 argv = argptr; 3927 if (!*argv) { 3928 /* wait for all jobs */ 3929 for (;;) { 3930 jp = curjob; 3931 while (1) { 3932 if (!jp) { 3933 /* no running procs */ 3934 goto out; 3935 } 3936 if (jp->state == JOBRUNNING) 3937 break; 3938 jp->waited = 1; 3939 jp = jp->prev_job; 3940 } 3941 dowait(DOWAIT_BLOCK, 0); 3942 } 3943 } 3944 3945 retval = 127; 3946 do { 3947 if (**argv != '%') { 3948 pid_t pid = number(*argv); 3949 job = curjob; 3950 goto start; 3951 do { 3952 if (job->ps[job->nprocs - 1].pid == pid) 3953 break; 3954 job = job->prev_job; 3955 start: 3956 if (!job) 3957 goto repeat; 3958 } while (1); 3959 } else 3960 job = getjob(*argv, 0); 3961 /* loop until process terminated or stopped */ 3962 while (job->state == JOBRUNNING) 3963 dowait(DOWAIT_BLOCK, 0); 3964 job->waited = 1; 3965 retval = getstatus(job); 3966 repeat: 3967 ; 3968 } while (*++argv); 3969 3970 out: 7438 3971 return retval; 7439 3972 } 7440 3973 3974 static struct job * 3975 growjobtab(void) 3976 { 3977 size_t len; 3978 ptrdiff_t offset; 3979 struct job *jp, *jq; 3980 3981 len = njobs * sizeof(*jp); 3982 jq = jobtab; 3983 jp = ckrealloc(jq, len + 4 * sizeof(*jp)); 3984 3985 offset = (char *)jp - (char *)jq; 3986 if (offset) { 3987 /* Relocate pointers */ 3988 size_t l = len; 3989 3990 jq = (struct job *)((char *)jq + l); 3991 while (l) { 3992 l -= sizeof(*jp); 3993 jq--; 3994 #define joff(p) ((struct job *)((char *)(p) + l)) 3995 #define jmove(p) (p) = (void *)((char *)(p) + offset) 3996 if (joff(jp)->ps == &jq->ps0) 3997 jmove(joff(jp)->ps); 3998 if (joff(jp)->prev_job) 3999 jmove(joff(jp)->prev_job); 4000 } 4001 if (curjob) 4002 jmove(curjob); 4003 #undef joff 4004 #undef jmove 4005 } 4006 4007 njobs += 4; 4008 jobtab = jp; 4009 jp = (struct job *)((char *)jp + len); 4010 jq = jp + 3; 4011 do { 4012 jq->used = 0; 4013 } while (--jq >= jp); 4014 return jp; 4015 } 4016 4017 /* 4018 * Return a new job structure. 4019 * Called with interrupts off. 4020 */ 4021 static struct job * 4022 makejob(union node *node, int nprocs) 4023 { 4024 int i; 4025 struct job *jp; 4026 4027 for (i = njobs, jp = jobtab; ; jp++) { 4028 if (--i < 0) { 4029 jp = growjobtab(); 4030 break; 4031 } 4032 if (jp->used == 0) 4033 break; 4034 if (jp->state != JOBDONE || !jp->waited) 4035 continue; 4036 #if JOBS 4037 if (jobctl) 4038 continue; 4039 #endif 4040 freejob(jp); 4041 break; 4042 } 4043 memset(jp, 0, sizeof(*jp)); 4044 #if JOBS 4045 /* jp->jobctl is a bitfield. 4046 * "jp->jobctl |= jobctl" likely to give awful code */ 4047 if (jobctl) 4048 jp->jobctl = 1; 4049 #endif 4050 jp->prev_job = curjob; 4051 curjob = jp; 4052 jp->used = 1; 4053 jp->ps = &jp->ps0; 4054 if (nprocs > 1) { 4055 jp->ps = ckmalloc(nprocs * sizeof(struct procstat)); 4056 } 4057 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, 4058 jobno(jp))); 4059 return jp; 4060 } 4061 4062 #if JOBS 7441 4063 /* 7442 4064 * Return a string identifying a command (to be printed by the 7443 4065 * jobs command). 7444 4066 */ 7445 7446 #if JOBS7447 4067 static char *cmdnextc; 7448 7449 static char *7450 commandtext(union node *n)7451 {7452 char *name;7453 7454 STARTSTACKSTR(cmdnextc);7455 cmdtxt(n);7456 name = stackblock();7457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",7458 name, cmdnextc, cmdnextc));7459 return savestr(name);7460 }7461 7462 static void7463 cmdtxt(union node *n)7464 {7465 union node *np;7466 struct nodelist *lp;7467 const char *p;7468 char s[2];7469 7470 if (!n)7471 return;7472 switch (n->type) {7473 default:7474 #if DEBUG7475 abort();7476 #endif7477 case NPIPE:7478 lp = n->npipe.cmdlist;7479 for (;;) {7480 cmdtxt(lp->n);7481 lp = lp->next;7482 if (!lp)7483 break;7484 cmdputs(" | ");7485 }7486 break;7487 case NSEMI:7488 p = "; ";7489 goto binop;7490 case NAND:7491 p = " && ";7492 goto binop;7493 case NOR:7494 p = " || ";7495 binop:7496 cmdtxt(n->nbinary.ch1);7497 cmdputs(p);7498 n = n->nbinary.ch2;7499 goto donode;7500 case NREDIR:7501 case NBACKGND:7502 n = n->nredir.n;7503 goto donode;7504 case NNOT:7505 cmdputs("!");7506 n = n->nnot.com;7507 donode:7508 cmdtxt(n);7509 break;7510 case NIF:7511 cmdputs("if ");7512 cmdtxt(n->nif.test);7513 cmdputs("; then ");7514 n = n->nif.ifpart;7515 if (n->nif.elsepart) {7516 cmdtxt(n);7517 cmdputs("; else ");7518 n = n->nif.elsepart;7519 }7520 p = "; fi";7521 goto dotail;7522 case NSUBSHELL:7523 cmdputs("(");7524 n = n->nredir.n;7525 p = ")";7526 goto dotail;7527 case NWHILE:7528 p = "while ";7529 goto until;7530 case NUNTIL:7531 p = "until ";7532 until:7533 cmdputs(p);7534 cmdtxt(n->nbinary.ch1);7535 n = n->nbinary.ch2;7536 p = "; done";7537 dodo:7538 cmdputs("; do ");7539 dotail:7540 cmdtxt(n);7541 goto dotail2;7542 case NFOR:7543 cmdputs("for ");7544 cmdputs(n->nfor.var);7545 cmdputs(" in ");7546 cmdlist(n->nfor.args, 1);7547 n = n->nfor.body;7548 p = "; done";7549 goto dodo;7550 case NDEFUN:7551 cmdputs(n->narg.text);7552 p = "() { ... }";7553 goto dotail2;7554 case NCMD:7555 cmdlist(n->ncmd.args, 1);7556 cmdlist(n->ncmd.redirect, 0);7557 break;7558 case NARG:7559 p = n->narg.text;7560 dotail2:7561 cmdputs(p);7562 break;7563 case NHERE:7564 case NXHERE:7565 p = "<<...";7566 goto dotail2;7567 case NCASE:7568 cmdputs("case ");7569 cmdputs(n->ncase.expr->narg.text);7570 cmdputs(" in ");7571 for (np = n->ncase.cases; np; np = np->nclist.next) {7572 cmdtxt(np->nclist.pattern);7573 cmdputs(") ");7574 cmdtxt(np->nclist.body);7575 cmdputs(";; ");7576 }7577 p = "esac";7578 goto dotail2;7579 case NTO:7580 p = ">";7581 goto redir;7582 case NCLOBBER:7583 p = ">|";7584 goto redir;7585 case NAPPEND:7586 p = ">>";7587 goto redir;7588 case NTOFD:7589 p = ">&";7590 goto redir;7591 case NFROM:7592 p = "<";7593 goto redir;7594 case NFROMFD:7595 p = "<&";7596 goto redir;7597 case NFROMTO:7598 p = "<>";7599 redir:7600 s[0] = n->nfile.fd + '0';7601 s[1] = '\0';7602 cmdputs(s);7603 cmdputs(p);7604 if (n->type == NTOFD || n->type == NFROMFD) {7605 s[0] = n->ndup.dupfd + '0';7606 p = s;7607 goto dotail2;7608 } else {7609 n = n->nfile.fname;7610 goto donode;7611 }7612 }7613 }7614 7615 static void7616 cmdlist(union node *np, int sep)7617 {7618 for (; np; np = np->narg.next) {7619 if (!sep)7620 cmdputs(spcstr);7621 cmdtxt(np);7622 if (sep && np->narg.next)7623 cmdputs(spcstr);7624 }7625 }7626 4068 7627 4069 static void … … 7637 4079 "%", "%%", "#", "##" 7638 4080 }; 4081 7639 4082 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); 7640 4083 p = s; … … 7651 4094 else 7652 4095 str = "${"; 7653 if (!(subtype & VSQUOTE) != !(quoted & 1)) { 7654 quoted ^= 1; 7655 c = '"'; 7656 } else 4096 if (!(subtype & VSQUOTE) == !(quoted & 1)) 7657 4097 goto dostr; 4098 quoted ^= 1; 4099 c = '"'; 7658 4100 break; 7659 4101 case CTLENDVAR: … … 7668 4110 str = "\"$(...)\""; 7669 4111 goto dostr; 7670 #if def CONFIG_ASH_MATH_SUPPORT4112 #if ENABLE_ASH_MATH_SUPPORT 7671 4113 case CTLARI: 7672 4114 str = "$(("; … … 7704 4146 } 7705 4147 USTPUTC(c, nextc); 7706 checkstr:4148 checkstr: 7707 4149 if (!str) 7708 4150 continue; 7709 dostr:4151 dostr: 7710 4152 while ((c = *str++)) { 7711 4153 USTPUTC(c, nextc); … … 7719 4161 } 7720 4162 7721 7722 static void 7723 showpipe(struct job *jp, FILE *out) 7724 { 7725 struct procstat *sp; 7726 struct procstat *spend; 7727 7728 spend = jp->ps + jp->nprocs; 7729 for (sp = jp->ps + 1; sp < spend; sp++) 7730 fprintf(out, " | %s", sp->cmd); 7731 outcslow('\n', out); 7732 flushall(); 7733 } 7734 7735 static void 7736 xtcsetpgrp(int fd, pid_t pgrp) 7737 { 7738 if (tcsetpgrp(fd, pgrp)) 7739 sh_error("Cannot set tty process group (%m)"); 4163 /* cmdtxt() and cmdlist() call each other */ 4164 static void cmdtxt(union node *n); 4165 4166 static void 4167 cmdlist(union node *np, int sep) 4168 { 4169 for (; np; np = np->narg.next) { 4170 if (!sep) 4171 cmdputs(" "); 4172 cmdtxt(np); 4173 if (sep && np->narg.next) 4174 cmdputs(" "); 4175 } 4176 } 4177 4178 static void 4179 cmdtxt(union node *n) 4180 { 4181 union node *np; 4182 struct nodelist *lp; 4183 const char *p; 4184 char s[2]; 4185 4186 if (!n) 4187 return; 4188 switch (n->type) { 4189 default: 4190 #if DEBUG 4191 abort(); 4192 #endif 4193 case NPIPE: 4194 lp = n->npipe.cmdlist; 4195 for (;;) { 4196 cmdtxt(lp->n); 4197 lp = lp->next; 4198 if (!lp) 4199 break; 4200 cmdputs(" | "); 4201 } 4202 break; 4203 case NSEMI: 4204 p = "; "; 4205 goto binop; 4206 case NAND: 4207 p = " && "; 4208 goto binop; 4209 case NOR: 4210 p = " || "; 4211 binop: 4212 cmdtxt(n->nbinary.ch1); 4213 cmdputs(p); 4214 n = n->nbinary.ch2; 4215 goto donode; 4216 case NREDIR: 4217 case NBACKGND: 4218 n = n->nredir.n; 4219 goto donode; 4220 case NNOT: 4221 cmdputs("!"); 4222 n = n->nnot.com; 4223 donode: 4224 cmdtxt(n); 4225 break; 4226 case NIF: 4227 cmdputs("if "); 4228 cmdtxt(n->nif.test); 4229 cmdputs("; then "); 4230 n = n->nif.ifpart; 4231 if (n->nif.elsepart) { 4232 cmdtxt(n); 4233 cmdputs("; else "); 4234 n = n->nif.elsepart; 4235 } 4236 p = "; fi"; 4237 goto dotail; 4238 case NSUBSHELL: 4239 cmdputs("("); 4240 n = n->nredir.n; 4241 p = ")"; 4242 goto dotail; 4243 case NWHILE: 4244 p = "while "; 4245 goto until; 4246 case NUNTIL: 4247 p = "until "; 4248 until: 4249 cmdputs(p); 4250 cmdtxt(n->nbinary.ch1); 4251 n = n->nbinary.ch2; 4252 p = "; done"; 4253 dodo: 4254 cmdputs("; do "); 4255 dotail: 4256 cmdtxt(n); 4257 goto dotail2; 4258 case NFOR: 4259 cmdputs("for "); 4260 cmdputs(n->nfor.var); 4261 cmdputs(" in "); 4262 cmdlist(n->nfor.args, 1); 4263 n = n->nfor.body; 4264 p = "; done"; 4265 goto dodo; 4266 case NDEFUN: 4267 cmdputs(n->narg.text); 4268 p = "() { ... }"; 4269 goto dotail2; 4270 case NCMD: 4271 cmdlist(n->ncmd.args, 1); 4272 cmdlist(n->ncmd.redirect, 0); 4273 break; 4274 case NARG: 4275 p = n->narg.text; 4276 dotail2: 4277 cmdputs(p); 4278 break; 4279 case NHERE: 4280 case NXHERE: 4281 p = "<<..."; 4282 goto dotail2; 4283 case NCASE: 4284 cmdputs("case "); 4285 cmdputs(n->ncase.expr->narg.text); 4286 cmdputs(" in "); 4287 for (np = n->ncase.cases; np; np = np->nclist.next) { 4288 cmdtxt(np->nclist.pattern); 4289 cmdputs(") "); 4290 cmdtxt(np->nclist.body); 4291 cmdputs(";; "); 4292 } 4293 p = "esac"; 4294 goto dotail2; 4295 case NTO: 4296 p = ">"; 4297 goto redir; 4298 case NCLOBBER: 4299 p = ">|"; 4300 goto redir; 4301 case NAPPEND: 4302 p = ">>"; 4303 goto redir; 4304 case NTOFD: 4305 p = ">&"; 4306 goto redir; 4307 case NFROM: 4308 p = "<"; 4309 goto redir; 4310 case NFROMFD: 4311 p = "<&"; 4312 goto redir; 4313 case NFROMTO: 4314 p = "<>"; 4315 redir: 4316 s[0] = n->nfile.fd + '0'; 4317 s[1] = '\0'; 4318 cmdputs(s); 4319 cmdputs(p); 4320 if (n->type == NTOFD || n->type == NFROMFD) { 4321 s[0] = n->ndup.dupfd + '0'; 4322 p = s; 4323 goto dotail2; 4324 } 4325 n = n->nfile.fname; 4326 goto donode; 4327 } 4328 } 4329 4330 static char * 4331 commandtext(union node *n) 4332 { 4333 char *name; 4334 4335 STARTSTACKSTR(cmdnextc); 4336 cmdtxt(n); 4337 name = stackblock(); 4338 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", 4339 name, cmdnextc, cmdnextc)); 4340 return ckstrdup(name); 7740 4341 } 7741 4342 #endif /* JOBS */ 7742 4343 4344 /* 4345 * Fork off a subshell. If we are doing job control, give the subshell its 4346 * own process group. Jp is a job structure that the job is to be added to. 4347 * N is the command that will be evaluated by the child. Both jp and n may 4348 * be NULL. The mode parameter can be one of the following: 4349 * FORK_FG - Fork off a foreground process. 4350 * FORK_BG - Fork off a background process. 4351 * FORK_NOJOB - Like FORK_FG, but don't give the process its own 4352 * process group even if job control is on. 4353 * 4354 * When job control is turned off, background processes have their standard 4355 * input redirected to /dev/null (except for the second and later processes 4356 * in a pipeline). 4357 * 4358 * Called with interrupts off. 4359 */ 4360 /* 4361 * Clear traps on a fork. 4362 */ 4363 static void 4364 clear_traps(void) 4365 { 4366 char **tp; 4367 4368 for (tp = trap; tp < &trap[NSIG]; tp++) { 4369 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 4370 INT_OFF; 4371 free(*tp); 4372 *tp = NULL; 4373 if (tp != &trap[0]) 4374 setsignal(tp - trap); 4375 INT_ON; 4376 } 4377 } 4378 } 4379 4380 /* Lives far away from here, needed for forkchild */ 4381 static void closescript(void); 4382 /* Called after fork(), in child */ 4383 static void 4384 forkchild(struct job *jp, union node *n, int mode) 4385 { 4386 int oldlvl; 4387 4388 TRACE(("Child shell %d\n", getpid())); 4389 oldlvl = shlvl; 4390 shlvl++; 4391 4392 closescript(); 4393 clear_traps(); 4394 #if JOBS 4395 /* do job control only in root shell */ 4396 jobctl = 0; 4397 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 4398 pid_t pgrp; 4399 4400 if (jp->nprocs == 0) 4401 pgrp = getpid(); 4402 else 4403 pgrp = jp->ps[0].pid; 4404 /* This can fail because we are doing it in the parent also */ 4405 (void)setpgid(0, pgrp); 4406 if (mode == FORK_FG) 4407 xtcsetpgrp(ttyfd, pgrp); 4408 setsignal(SIGTSTP); 4409 setsignal(SIGTTOU); 4410 } else 4411 #endif 4412 if (mode == FORK_BG) { 4413 ignoresig(SIGINT); 4414 ignoresig(SIGQUIT); 4415 if (jp->nprocs == 0) { 4416 close(0); 4417 if (open(bb_dev_null, O_RDONLY) != 0) 4418 ash_msg_and_raise_error("can't open %s", bb_dev_null); 4419 } 4420 } 4421 if (!oldlvl && iflag) { 4422 setsignal(SIGINT); 4423 setsignal(SIGQUIT); 4424 setsignal(SIGTERM); 4425 } 4426 #if JOBS 4427 /* For "jobs | cat" to work like in bash, we must retain list of jobs 4428 * in child, but we do need to remove ourself */ 4429 if (jp) 4430 freejob(jp); 4431 #else 4432 for (jp = curjob; jp; jp = jp->prev_job) 4433 freejob(jp); 4434 #endif 4435 jobless = 0; 4436 } 4437 4438 /* Called after fork(), in parent */ 4439 static void 4440 forkparent(struct job *jp, union node *n, int mode, pid_t pid) 4441 { 4442 TRACE(("In parent shell: child = %d\n", pid)); 4443 if (!jp) { 4444 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0); 4445 jobless++; 4446 return; 4447 } 4448 #if JOBS 4449 if (mode != FORK_NOJOB && jp->jobctl) { 4450 int pgrp; 4451 4452 if (jp->nprocs == 0) 4453 pgrp = pid; 4454 else 4455 pgrp = jp->ps[0].pid; 4456 /* This can fail because we are doing it in the child also */ 4457 setpgid(pid, pgrp); 4458 } 4459 #endif 4460 if (mode == FORK_BG) { 4461 backgndpid = pid; /* set $! */ 4462 set_curjob(jp, CUR_RUNNING); 4463 } 4464 if (jp) { 4465 struct procstat *ps = &jp->ps[jp->nprocs++]; 4466 ps->pid = pid; 4467 ps->status = -1; 4468 ps->cmd = nullstr; 4469 #if JOBS 4470 if (jobctl && n) 4471 ps->cmd = commandtext(n); 4472 #endif 4473 } 4474 } 4475 7743 4476 static int 7744 getstatus(struct job *job) { 4477 forkshell(struct job *jp, union node *n, int mode) 4478 { 4479 int pid; 4480 4481 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 4482 pid = fork(); 4483 if (pid < 0) { 4484 TRACE(("Fork failed, errno=%d", errno)); 4485 if (jp) 4486 freejob(jp); 4487 ash_msg_and_raise_error("cannot fork"); 4488 } 4489 if (pid == 0) 4490 forkchild(jp, n, mode); 4491 else 4492 forkparent(jp, n, mode, pid); 4493 return pid; 4494 } 4495 4496 /* 4497 * Wait for job to finish. 4498 * 4499 * Under job control we have the problem that while a child process is 4500 * running interrupts generated by the user are sent to the child but not 4501 * to the shell. This means that an infinite loop started by an inter- 4502 * active user may be hard to kill. With job control turned off, an 4503 * interactive user may place an interactive program inside a loop. If 4504 * the interactive program catches interrupts, the user doesn't want 4505 * these interrupts to also abort the loop. The approach we take here 4506 * is to have the shell ignore interrupt signals while waiting for a 4507 * foreground process to terminate, and then send itself an interrupt 4508 * signal if the child process was terminated by an interrupt signal. 4509 * Unfortunately, some programs want to do a bit of cleanup and then 4510 * exit on interrupt; unless these processes terminate themselves by 4511 * sending a signal to themselves (instead of calling exit) they will 4512 * confuse this approach. 4513 * 4514 * Called with interrupts off. 4515 */ 4516 static int 4517 waitforjob(struct job *jp) 4518 { 4519 int st; 4520 4521 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 4522 while (jp->state == JOBRUNNING) { 4523 dowait(DOWAIT_BLOCK, jp); 4524 } 4525 st = getstatus(jp); 4526 #if JOBS 4527 if (jp->jobctl) { 4528 xtcsetpgrp(ttyfd, rootpid); 4529 /* 4530 * This is truly gross. 4531 * If we're doing job control, then we did a TIOCSPGRP which 4532 * caused us (the shell) to no longer be in the controlling 4533 * session -- so we wouldn't have seen any ^C/SIGINT. So, we 4534 * intuit from the subprocess exit status whether a SIGINT 4535 * occurred, and if so interrupt ourselves. Yuck. - mycroft 4536 */ 4537 if (jp->sigint) 4538 raise(SIGINT); 4539 } 4540 if (jp->state == JOBDONE) 4541 #endif 4542 freejob(jp); 4543 return st; 4544 } 4545 4546 /* 4547 * return 1 if there are stopped jobs, otherwise 0 4548 */ 4549 static int 4550 stoppedjobs(void) 4551 { 4552 struct job *jp; 4553 int retval; 4554 4555 retval = 0; 4556 if (job_warning) 4557 goto out; 4558 jp = curjob; 4559 if (jp && jp->state == JOBSTOPPED) { 4560 out2str("You have stopped jobs.\n"); 4561 job_warning = 2; 4562 retval++; 4563 } 4564 out: 4565 return retval; 4566 } 4567 4568 4569 /* ============ redir.c 4570 * 4571 * Code for dealing with input/output redirection. 4572 */ 4573 4574 #define EMPTY -2 /* marks an unused slot in redirtab */ 4575 #ifndef PIPE_BUF 4576 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 4577 #else 4578 # define PIPESIZE PIPE_BUF 4579 #endif 4580 4581 /* 4582 * Open a file in noclobber mode. 4583 * The code was copied from bash. 4584 */ 4585 static int 4586 noclobberopen(const char *fname) 4587 { 4588 int r, fd; 4589 struct stat finfo, finfo2; 4590 4591 /* 4592 * If the file exists and is a regular file, return an error 4593 * immediately. 4594 */ 4595 r = stat(fname, &finfo); 4596 if (r == 0 && S_ISREG(finfo.st_mode)) { 4597 errno = EEXIST; 4598 return -1; 4599 } 4600 4601 /* 4602 * If the file was not present (r != 0), make sure we open it 4603 * exclusively so that if it is created before we open it, our open 4604 * will fail. Make sure that we do not truncate an existing file. 4605 * Note that we don't turn on O_EXCL unless the stat failed -- if the 4606 * file was not a regular file, we leave O_EXCL off. 4607 */ 4608 if (r != 0) 4609 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); 4610 fd = open(fname, O_WRONLY|O_CREAT, 0666); 4611 4612 /* If the open failed, return the file descriptor right away. */ 4613 if (fd < 0) 4614 return fd; 4615 4616 /* 4617 * OK, the open succeeded, but the file may have been changed from a 4618 * non-regular file to a regular file between the stat and the open. 4619 * We are assuming that the O_EXCL open handles the case where FILENAME 4620 * did not exist and is symlinked to an existing file between the stat 4621 * and open. 4622 */ 4623 4624 /* 4625 * If we can open it and fstat the file descriptor, and neither check 4626 * revealed that it was a regular file, and the file has not been 4627 * replaced, return the file descriptor. 4628 */ 4629 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) 4630 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 4631 return fd; 4632 4633 /* The file has been replaced. badness. */ 4634 close(fd); 4635 errno = EEXIST; 4636 return -1; 4637 } 4638 4639 /* 4640 * Handle here documents. Normally we fork off a process to write the 4641 * data to a pipe. If the document is short, we can stuff the data in 4642 * the pipe without forking. 4643 */ 4644 /* openhere needs this forward reference */ 4645 static void expandhere(union node *arg, int fd); 4646 static int 4647 openhere(union node *redir) 4648 { 4649 int pip[2]; 4650 size_t len = 0; 4651 4652 if (pipe(pip) < 0) 4653 ash_msg_and_raise_error("pipe call failed"); 4654 if (redir->type == NHERE) { 4655 len = strlen(redir->nhere.doc->narg.text); 4656 if (len <= PIPESIZE) { 4657 full_write(pip[1], redir->nhere.doc->narg.text, len); 4658 goto out; 4659 } 4660 } 4661 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 4662 close(pip[0]); 4663 signal(SIGINT, SIG_IGN); 4664 signal(SIGQUIT, SIG_IGN); 4665 signal(SIGHUP, SIG_IGN); 4666 #ifdef SIGTSTP 4667 signal(SIGTSTP, SIG_IGN); 4668 #endif 4669 signal(SIGPIPE, SIG_DFL); 4670 if (redir->type == NHERE) 4671 full_write(pip[1], redir->nhere.doc->narg.text, len); 4672 else 4673 expandhere(redir->nhere.doc, pip[1]); 4674 _exit(0); 4675 } 4676 out: 4677 close(pip[1]); 4678 return pip[0]; 4679 } 4680 4681 static int 4682 openredirect(union node *redir) 4683 { 4684 char *fname; 4685 int f; 4686 4687 switch (redir->nfile.type) { 4688 case NFROM: 4689 fname = redir->nfile.expfname; 4690 f = open(fname, O_RDONLY); 4691 if (f < 0) 4692 goto eopen; 4693 break; 4694 case NFROMTO: 4695 fname = redir->nfile.expfname; 4696 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 4697 if (f < 0) 4698 goto ecreate; 4699 break; 4700 case NTO: 4701 /* Take care of noclobber mode. */ 4702 if (Cflag) { 4703 fname = redir->nfile.expfname; 4704 f = noclobberopen(fname); 4705 if (f < 0) 4706 goto ecreate; 4707 break; 4708 } 4709 /* FALLTHROUGH */ 4710 case NCLOBBER: 4711 fname = redir->nfile.expfname; 4712 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 4713 if (f < 0) 4714 goto ecreate; 4715 break; 4716 case NAPPEND: 4717 fname = redir->nfile.expfname; 4718 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 4719 if (f < 0) 4720 goto ecreate; 4721 break; 4722 default: 4723 #if DEBUG 4724 abort(); 4725 #endif 4726 /* Fall through to eliminate warning. */ 4727 case NTOFD: 4728 case NFROMFD: 4729 f = -1; 4730 break; 4731 case NHERE: 4732 case NXHERE: 4733 f = openhere(redir); 4734 break; 4735 } 4736 4737 return f; 4738 ecreate: 4739 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory")); 4740 eopen: 4741 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file")); 4742 } 4743 4744 /* 4745 * Copy a file descriptor to be >= to. Returns -1 4746 * if the source file descriptor is closed, EMPTY if there are no unused 4747 * file descriptors left. 4748 */ 4749 static int 4750 copyfd(int from, int to) 4751 { 4752 int newfd; 4753 4754 newfd = fcntl(from, F_DUPFD, to); 4755 if (newfd < 0) { 4756 if (errno == EMFILE) 4757 return EMPTY; 4758 ash_msg_and_raise_error("%d: %m", from); 4759 } 4760 return newfd; 4761 } 4762 4763 static void 4764 dupredirect(union node *redir, int f) 4765 { 4766 int fd = redir->nfile.fd; 4767 4768 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 4769 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 4770 copyfd(redir->ndup.dupfd, fd); 4771 } 4772 return; 4773 } 4774 4775 if (f != fd) { 4776 copyfd(f, fd); 4777 close(f); 4778 } 4779 } 4780 4781 /* 4782 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 4783 * old file descriptors are stashed away so that the redirection can be 4784 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 4785 * standard output, and the standard error if it becomes a duplicate of 4786 * stdout, is saved in memory. 4787 */ 4788 /* flags passed to redirect */ 4789 #define REDIR_PUSH 01 /* save previous values of file descriptors */ 4790 #define REDIR_SAVEFD2 03 /* set preverrout */ 4791 static void 4792 redirect(union node *redir, int flags) 4793 { 4794 union node *n; 4795 struct redirtab *sv; 4796 int i; 4797 int fd; 4798 int newfd; 4799 int *p; 4800 nullredirs++; 4801 if (!redir) { 4802 return; 4803 } 4804 sv = NULL; 4805 INT_OFF; 4806 if (flags & REDIR_PUSH) { 4807 struct redirtab *q; 4808 q = ckmalloc(sizeof(struct redirtab)); 4809 q->next = redirlist; 4810 redirlist = q; 4811 q->nullredirs = nullredirs - 1; 4812 for (i = 0; i < 10; i++) 4813 q->renamed[i] = EMPTY; 4814 nullredirs = 0; 4815 sv = q; 4816 } 4817 n = redir; 4818 do { 4819 fd = n->nfile.fd; 4820 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) 4821 && n->ndup.dupfd == fd) 4822 continue; /* redirect from/to same file descriptor */ 4823 4824 newfd = openredirect(n); 4825 if (fd == newfd) 4826 continue; 4827 if (sv && *(p = &sv->renamed[fd]) == EMPTY) { 4828 i = fcntl(fd, F_DUPFD, 10); 4829 4830 if (i == -1) { 4831 i = errno; 4832 if (i != EBADF) { 4833 close(newfd); 4834 errno = i; 4835 ash_msg_and_raise_error("%d: %m", fd); 4836 /* NOTREACHED */ 4837 } 4838 } else { 4839 *p = i; 4840 close(fd); 4841 } 4842 } else { 4843 close(fd); 4844 } 4845 dupredirect(n, newfd); 4846 } while ((n = n->nfile.next)); 4847 INT_ON; 4848 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) 4849 preverrout_fd = sv->renamed[2]; 4850 } 4851 4852 /* 4853 * Undo the effects of the last redirection. 4854 */ 4855 static void 4856 popredir(int drop) 4857 { 4858 struct redirtab *rp; 4859 int i; 4860 4861 if (--nullredirs >= 0) 4862 return; 4863 INT_OFF; 4864 rp = redirlist; 4865 for (i = 0; i < 10; i++) { 4866 if (rp->renamed[i] != EMPTY) { 4867 if (!drop) { 4868 close(i); 4869 copyfd(rp->renamed[i], i); 4870 } 4871 close(rp->renamed[i]); 4872 } 4873 } 4874 redirlist = rp->next; 4875 nullredirs = rp->nullredirs; 4876 free(rp); 4877 INT_ON; 4878 } 4879 4880 /* 4881 * Undo all redirections. Called on error or interrupt. 4882 */ 4883 4884 /* 4885 * Discard all saved file descriptors. 4886 */ 4887 static void 4888 clearredir(int drop) 4889 { 4890 for (;;) { 4891 nullredirs = 0; 4892 if (!redirlist) 4893 break; 4894 popredir(drop); 4895 } 4896 } 4897 4898 static int 4899 redirectsafe(union node *redir, int flags) 4900 { 4901 int err; 4902 volatile int saveint; 4903 struct jmploc *volatile savehandler = exception_handler; 4904 struct jmploc jmploc; 4905 4906 SAVE_INT(saveint); 4907 err = setjmp(jmploc.loc) * 2; 4908 if (!err) { 4909 exception_handler = &jmploc; 4910 redirect(redir, flags); 4911 } 4912 exception_handler = savehandler; 4913 if (err && exception != EXERROR) 4914 longjmp(exception_handler->loc, 1); 4915 RESTORE_INT(saveint); 4916 return err; 4917 } 4918 4919 4920 /* ============ Routines to expand arguments to commands 4921 * 4922 * We have to deal with backquotes, shell variables, and file metacharacters. 4923 */ 4924 4925 /* 4926 * expandarg flags 4927 */ 4928 #define EXP_FULL 0x1 /* perform word splitting & file globbing */ 4929 #define EXP_TILDE 0x2 /* do normal tilde expansion */ 4930 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ 4931 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 4932 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 4933 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ 4934 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 4935 #define EXP_WORD 0x80 /* expand word in parameter expansion */ 4936 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ 4937 /* 4938 * _rmescape() flags 4939 */ 4940 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 4941 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 4942 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ 4943 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 4944 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 4945 4946 /* 4947 * Structure specifying which parts of the string should be searched 4948 * for IFS characters. 4949 */ 4950 struct ifsregion { 4951 struct ifsregion *next; /* next region in list */ 4952 int begoff; /* offset of start of region */ 4953 int endoff; /* offset of end of region */ 4954 int nulonly; /* search for nul bytes only */ 4955 }; 4956 4957 struct arglist { 4958 struct strlist *list; 4959 struct strlist **lastp; 4960 }; 4961 4962 /* output of current string */ 4963 static char *expdest; 4964 /* list of back quote expressions */ 4965 static struct nodelist *argbackq; 4966 /* first struct in list of ifs regions */ 4967 static struct ifsregion ifsfirst; 4968 /* last struct in list */ 4969 static struct ifsregion *ifslastp; 4970 /* holds expanded arg list */ 4971 static struct arglist exparg; 4972 4973 /* 4974 * Our own itoa(). 4975 */ 4976 static int 4977 cvtnum(arith_t num) 4978 { 4979 int len; 4980 4981 expdest = makestrspace(32, expdest); 4982 #if ENABLE_ASH_MATH_SUPPORT_64 4983 len = fmtstr(expdest, 32, "%lld", (long long) num); 4984 #else 4985 len = fmtstr(expdest, 32, "%ld", num); 4986 #endif 4987 STADJUST(len, expdest); 4988 return len; 4989 } 4990 4991 static size_t 4992 esclen(const char *start, const char *p) 4993 { 4994 size_t esc = 0; 4995 4996 while (p > start && *--p == CTLESC) { 4997 esc++; 4998 } 4999 return esc; 5000 } 5001 5002 /* 5003 * Remove any CTLESC characters from a string. 5004 */ 5005 static char * 5006 _rmescapes(char *str, int flag) 5007 { 5008 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; 5009 5010 char *p, *q, *r; 5011 unsigned inquotes; 5012 int notescaped; 5013 int globbing; 5014 5015 p = strpbrk(str, qchars); 5016 if (!p) { 5017 return str; 5018 } 5019 q = p; 5020 r = str; 5021 if (flag & RMESCAPE_ALLOC) { 5022 size_t len = p - str; 5023 size_t fulllen = len + strlen(p) + 1; 5024 5025 if (flag & RMESCAPE_GROW) { 5026 r = makestrspace(fulllen, expdest); 5027 } else if (flag & RMESCAPE_HEAP) { 5028 r = ckmalloc(fulllen); 5029 } else { 5030 r = stalloc(fulllen); 5031 } 5032 q = r; 5033 if (len > 0) { 5034 q = memcpy(q, str, len) + len; 5035 } 5036 } 5037 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5038 globbing = flag & RMESCAPE_GLOB; 5039 notescaped = globbing; 5040 while (*p) { 5041 if (*p == CTLQUOTEMARK) { 5042 inquotes = ~inquotes; 5043 p++; 5044 notescaped = globbing; 5045 continue; 5046 } 5047 if (*p == '\\') { 5048 /* naked back slash */ 5049 notescaped = 0; 5050 goto copy; 5051 } 5052 if (*p == CTLESC) { 5053 p++; 5054 if (notescaped && inquotes && *p != '/') { 5055 *q++ = '\\'; 5056 } 5057 } 5058 notescaped = globbing; 5059 copy: 5060 *q++ = *p++; 5061 } 5062 *q = '\0'; 5063 if (flag & RMESCAPE_GROW) { 5064 expdest = r; 5065 STADJUST(q - r + 1, expdest); 5066 } 5067 return r; 5068 } 5069 #define rmescapes(p) _rmescapes((p), 0) 5070 5071 #define pmatch(a, b) !fnmatch((a), (b), 0) 5072 5073 /* 5074 * Prepare a pattern for a expmeta (internal glob(3)) call. 5075 * 5076 * Returns an stalloced string. 5077 */ 5078 static char * 5079 preglob(const char *pattern, int quoted, int flag) 5080 { 5081 flag |= RMESCAPE_GLOB; 5082 if (quoted) { 5083 flag |= RMESCAPE_QUOTED; 5084 } 5085 return _rmescapes((char *)pattern, flag); 5086 } 5087 5088 /* 5089 * Put a string on the stack. 5090 */ 5091 static void 5092 memtodest(const char *p, size_t len, int syntax, int quotes) 5093 { 5094 char *q = expdest; 5095 5096 q = makestrspace(len * 2, q); 5097 5098 while (len--) { 5099 int c = signed_char2int(*p++); 5100 if (!c) 5101 continue; 5102 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5103 USTPUTC(CTLESC, q); 5104 USTPUTC(c, q); 5105 } 5106 5107 expdest = q; 5108 } 5109 5110 static void 5111 strtodest(const char *p, int syntax, int quotes) 5112 { 5113 memtodest(p, strlen(p), syntax, quotes); 5114 } 5115 5116 /* 5117 * Record the fact that we have to scan this region of the 5118 * string for IFS characters. 5119 */ 5120 static void 5121 recordregion(int start, int end, int nulonly) 5122 { 5123 struct ifsregion *ifsp; 5124 5125 if (ifslastp == NULL) { 5126 ifsp = &ifsfirst; 5127 } else { 5128 INT_OFF; 5129 ifsp = ckmalloc(sizeof(*ifsp)); 5130 ifsp->next = NULL; 5131 ifslastp->next = ifsp; 5132 INT_ON; 5133 } 5134 ifslastp = ifsp; 5135 ifslastp->begoff = start; 5136 ifslastp->endoff = end; 5137 ifslastp->nulonly = nulonly; 5138 } 5139 5140 static void 5141 removerecordregions(int endoff) 5142 { 5143 if (ifslastp == NULL) 5144 return; 5145 5146 if (ifsfirst.endoff > endoff) { 5147 while (ifsfirst.next != NULL) { 5148 struct ifsregion *ifsp; 5149 INT_OFF; 5150 ifsp = ifsfirst.next->next; 5151 free(ifsfirst.next); 5152 ifsfirst.next = ifsp; 5153 INT_ON; 5154 } 5155 if (ifsfirst.begoff > endoff) 5156 ifslastp = NULL; 5157 else { 5158 ifslastp = &ifsfirst; 5159 ifsfirst.endoff = endoff; 5160 } 5161 return; 5162 } 5163 5164 ifslastp = &ifsfirst; 5165 while (ifslastp->next && ifslastp->next->begoff < endoff) 5166 ifslastp=ifslastp->next; 5167 while (ifslastp->next != NULL) { 5168 struct ifsregion *ifsp; 5169 INT_OFF; 5170 ifsp = ifslastp->next->next; 5171 free(ifslastp->next); 5172 ifslastp->next = ifsp; 5173 INT_ON; 5174 } 5175 if (ifslastp->endoff > endoff) 5176 ifslastp->endoff = endoff; 5177 } 5178 5179 static char * 5180 exptilde(char *startp, char *p, int flag) 5181 { 5182 char c; 5183 char *name; 5184 struct passwd *pw; 5185 const char *home; 5186 int quotes = flag & (EXP_FULL | EXP_CASE); 5187 int startloc; 5188 5189 name = p + 1; 5190 5191 while ((c = *++p) != '\0') { 5192 switch (c) { 5193 case CTLESC: 5194 return startp; 5195 case CTLQUOTEMARK: 5196 return startp; 5197 case ':': 5198 if (flag & EXP_VARTILDE) 5199 goto done; 5200 break; 5201 case '/': 5202 case CTLENDVAR: 5203 goto done; 5204 } 5205 } 5206 done: 5207 *p = '\0'; 5208 if (*name == '\0') { 5209 home = lookupvar(homestr); 5210 } else { 5211 pw = getpwnam(name); 5212 if (pw == NULL) 5213 goto lose; 5214 home = pw->pw_dir; 5215 } 5216 if (!home || !*home) 5217 goto lose; 5218 *p = c; 5219 startloc = expdest - (char *)stackblock(); 5220 strtodest(home, SQSYNTAX, quotes); 5221 recordregion(startloc, expdest - (char *)stackblock(), 0); 5222 return p; 5223 lose: 5224 *p = c; 5225 return startp; 5226 } 5227 5228 /* 5229 * Execute a command inside back quotes. If it's a builtin command, we 5230 * want to save its output in a block obtained from malloc. Otherwise 5231 * we fork off a subprocess and get the output of the command via a pipe. 5232 * Should be called with interrupts off. 5233 */ 5234 struct backcmd { /* result of evalbackcmd */ 5235 int fd; /* file descriptor to read from */ 5236 char *buf; /* buffer */ 5237 int nleft; /* number of chars in buffer */ 5238 struct job *jp; /* job structure for command */ 5239 }; 5240 5241 /* These forward decls are needed to use "eval" code for backticks handling: */ 5242 static int back_exitstatus; /* exit status of backquoted command */ 5243 #define EV_EXIT 01 /* exit after evaluating tree */ 5244 static void evaltree(union node *, int); 5245 5246 static void 5247 evalbackcmd(union node *n, struct backcmd *result) 5248 { 5249 int saveherefd; 5250 5251 result->fd = -1; 5252 result->buf = NULL; 5253 result->nleft = 0; 5254 result->jp = NULL; 5255 if (n == NULL) { 5256 goto out; 5257 } 5258 5259 saveherefd = herefd; 5260 herefd = -1; 5261 5262 { 5263 int pip[2]; 5264 struct job *jp; 5265 5266 if (pipe(pip) < 0) 5267 ash_msg_and_raise_error("pipe call failed"); 5268 jp = makejob(n, 1); 5269 if (forkshell(jp, n, FORK_NOJOB) == 0) { 5270 FORCE_INT_ON; 5271 close(pip[0]); 5272 if (pip[1] != 1) { 5273 close(1); 5274 copyfd(pip[1], 1); 5275 close(pip[1]); 5276 } 5277 eflag = 0; 5278 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 5279 /* NOTREACHED */ 5280 } 5281 close(pip[1]); 5282 result->fd = pip[0]; 5283 result->jp = jp; 5284 } 5285 herefd = saveherefd; 5286 out: 5287 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 5288 result->fd, result->buf, result->nleft, result->jp)); 5289 } 5290 5291 /* 5292 * Expand stuff in backwards quotes. 5293 */ 5294 static void 5295 expbackq(union node *cmd, int quoted, int quotes) 5296 { 5297 struct backcmd in; 5298 int i; 5299 char buf[128]; 5300 char *p; 5301 char *dest; 5302 int startloc; 5303 int syntax = quoted? DQSYNTAX : BASESYNTAX; 5304 struct stackmark smark; 5305 5306 INT_OFF; 5307 setstackmark(&smark); 5308 dest = expdest; 5309 startloc = dest - (char *)stackblock(); 5310 grabstackstr(dest); 5311 evalbackcmd(cmd, &in); 5312 popstackmark(&smark); 5313 5314 p = in.buf; 5315 i = in.nleft; 5316 if (i == 0) 5317 goto read; 5318 for (;;) { 5319 memtodest(p, i, syntax, quotes); 5320 read: 5321 if (in.fd < 0) 5322 break; 5323 i = safe_read(in.fd, buf, sizeof(buf)); 5324 TRACE(("expbackq: read returns %d\n", i)); 5325 if (i <= 0) 5326 break; 5327 p = buf; 5328 } 5329 5330 if (in.buf) 5331 free(in.buf); 5332 if (in.fd >= 0) { 5333 close(in.fd); 5334 back_exitstatus = waitforjob(in.jp); 5335 } 5336 INT_ON; 5337 5338 /* Eat all trailing newlines */ 5339 dest = expdest; 5340 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 5341 STUNPUTC(dest); 5342 expdest = dest; 5343 5344 if (quoted == 0) 5345 recordregion(startloc, dest - (char *)stackblock(), 0); 5346 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 5347 (dest - (char *)stackblock()) - startloc, 5348 (dest - (char *)stackblock()) - startloc, 5349 stackblock() + startloc)); 5350 } 5351 5352 #if ENABLE_ASH_MATH_SUPPORT 5353 /* 5354 * Expand arithmetic expression. Backup to start of expression, 5355 * evaluate, place result in (backed up) result, adjust string position. 5356 */ 5357 static void 5358 expari(int quotes) 5359 { 5360 char *p, *start; 5361 int begoff; 5362 int flag; 5363 int len; 5364 5365 /* ifsfree(); */ 5366 5367 /* 5368 * This routine is slightly over-complicated for 5369 * efficiency. Next we scan backwards looking for the 5370 * start of arithmetic. 5371 */ 5372 start = stackblock(); 5373 p = expdest - 1; 5374 *p = '\0'; 5375 p--; 5376 do { 5377 int esc; 5378 5379 while (*p != CTLARI) { 5380 p--; 5381 #if DEBUG 5382 if (p < start) { 5383 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)"); 5384 } 5385 #endif 5386 } 5387 5388 esc = esclen(start, p); 5389 if (!(esc % 2)) { 5390 break; 5391 } 5392 5393 p -= esc + 1; 5394 } while (1); 5395 5396 begoff = p - start; 5397 5398 removerecordregions(begoff); 5399 5400 flag = p[1]; 5401 5402 expdest = p; 5403 5404 if (quotes) 5405 rmescapes(p + 2); 5406 5407 len = cvtnum(dash_arith(p + 2)); 5408 5409 if (flag != '"') 5410 recordregion(begoff, begoff + len, 0); 5411 } 5412 #endif 5413 5414 /* argstr needs it */ 5415 static char *evalvar(char *p, int flag); 5416 5417 /* 5418 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 5419 * characters to allow for further processing. Otherwise treat 5420 * $@ like $* since no splitting will be performed. 5421 */ 5422 static void 5423 argstr(char *p, int flag) 5424 { 5425 static const char spclchars[] ALIGN1 = { 5426 '=', 5427 ':', 5428 CTLQUOTEMARK, 5429 CTLENDVAR, 5430 CTLESC, 5431 CTLVAR, 5432 CTLBACKQ, 5433 CTLBACKQ | CTLQUOTE, 5434 #if ENABLE_ASH_MATH_SUPPORT 5435 CTLENDARI, 5436 #endif 5437 0 5438 }; 5439 const char *reject = spclchars; 5440 int c; 5441 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 5442 int breakall = flag & EXP_WORD; 5443 int inquotes; 5444 size_t length; 5445 int startloc; 5446 5447 if (!(flag & EXP_VARTILDE)) { 5448 reject += 2; 5449 } else if (flag & EXP_VARTILDE2) { 5450 reject++; 5451 } 5452 inquotes = 0; 5453 length = 0; 5454 if (flag & EXP_TILDE) { 5455 char *q; 5456 5457 flag &= ~EXP_TILDE; 5458 tilde: 5459 q = p; 5460 if (*q == CTLESC && (flag & EXP_QWORD)) 5461 q++; 5462 if (*q == '~') 5463 p = exptilde(p, q, flag); 5464 } 5465 start: 5466 startloc = expdest - (char *)stackblock(); 5467 for (;;) { 5468 length += strcspn(p + length, reject); 5469 c = p[length]; 5470 if (c && (!(c & 0x80) 5471 #if ENABLE_ASH_MATH_SUPPORT 5472 || c == CTLENDARI 5473 #endif 5474 )) { 5475 /* c == '=' || c == ':' || c == CTLENDARI */ 5476 length++; 5477 } 5478 if (length > 0) { 5479 int newloc; 5480 expdest = stack_nputstr(p, length, expdest); 5481 newloc = expdest - (char *)stackblock(); 5482 if (breakall && !inquotes && newloc > startloc) { 5483 recordregion(startloc, newloc, 0); 5484 } 5485 startloc = newloc; 5486 } 5487 p += length + 1; 5488 length = 0; 5489 5490 switch (c) { 5491 case '\0': 5492 goto breakloop; 5493 case '=': 5494 if (flag & EXP_VARTILDE2) { 5495 p--; 5496 continue; 5497 } 5498 flag |= EXP_VARTILDE2; 5499 reject++; 5500 /* fall through */ 5501 case ':': 5502 /* 5503 * sort of a hack - expand tildes in variable 5504 * assignments (after the first '=' and after ':'s). 5505 */ 5506 if (*--p == '~') { 5507 goto tilde; 5508 } 5509 continue; 5510 } 5511 5512 switch (c) { 5513 case CTLENDVAR: /* ??? */ 5514 goto breakloop; 5515 case CTLQUOTEMARK: 5516 /* "$@" syntax adherence hack */ 5517 if ( 5518 !inquotes && 5519 !memcmp(p, dolatstr, 4) && 5520 (p[4] == CTLQUOTEMARK || ( 5521 p[4] == CTLENDVAR && 5522 p[5] == CTLQUOTEMARK 5523 )) 5524 ) { 5525 p = evalvar(p + 1, flag) + 1; 5526 goto start; 5527 } 5528 inquotes = !inquotes; 5529 addquote: 5530 if (quotes) { 5531 p--; 5532 length++; 5533 startloc++; 5534 } 5535 break; 5536 case CTLESC: 5537 startloc++; 5538 length++; 5539 goto addquote; 5540 case CTLVAR: 5541 p = evalvar(p, flag); 5542 goto start; 5543 case CTLBACKQ: 5544 c = 0; 5545 case CTLBACKQ|CTLQUOTE: 5546 expbackq(argbackq->n, c, quotes); 5547 argbackq = argbackq->next; 5548 goto start; 5549 #if ENABLE_ASH_MATH_SUPPORT 5550 case CTLENDARI: 5551 p--; 5552 expari(quotes); 5553 goto start; 5554 #endif 5555 } 5556 } 5557 breakloop: 5558 ; 5559 } 5560 5561 static char * 5562 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5563 int zero) 5564 { 5565 char *loc; 5566 char *loc2; 5567 char c; 5568 5569 loc = startp; 5570 loc2 = rmesc; 5571 do { 5572 int match; 5573 const char *s = loc2; 5574 c = *loc2; 5575 if (zero) { 5576 *loc2 = '\0'; 5577 s = rmesc; 5578 } 5579 match = pmatch(str, s); 5580 *loc2 = c; 5581 if (match) 5582 return loc; 5583 if (quotes && *loc == CTLESC) 5584 loc++; 5585 loc++; 5586 loc2++; 5587 } while (c); 5588 return 0; 5589 } 5590 5591 static char * 5592 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5593 int zero) 5594 { 5595 int esc = 0; 5596 char *loc; 5597 char *loc2; 5598 5599 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 5600 int match; 5601 char c = *loc2; 5602 const char *s = loc2; 5603 if (zero) { 5604 *loc2 = '\0'; 5605 s = rmesc; 5606 } 5607 match = pmatch(str, s); 5608 *loc2 = c; 5609 if (match) 5610 return loc; 5611 loc--; 5612 if (quotes) { 5613 if (--esc < 0) { 5614 esc = esclen(startp, loc); 5615 } 5616 if (esc % 2) { 5617 esc--; 5618 loc--; 5619 } 5620 } 5621 } 5622 return 0; 5623 } 5624 5625 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN; 5626 static void 5627 varunset(const char *end, const char *var, const char *umsg, int varflags) 5628 { 5629 const char *msg; 5630 const char *tail; 5631 5632 tail = nullstr; 5633 msg = "parameter not set"; 5634 if (umsg) { 5635 if (*end == CTLENDVAR) { 5636 if (varflags & VSNUL) 5637 tail = " or null"; 5638 } else 5639 msg = umsg; 5640 } 5641 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5642 } 5643 5644 static const char * 5645 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5646 { 5647 char *startp; 5648 char *loc; 5649 int saveherefd = herefd; 5650 struct nodelist *saveargbackq = argbackq; 5651 int amount; 5652 char *rmesc, *rmescend; 5653 int zero; 5654 char *(*scan)(char *, char *, char *, char *, int , int); 5655 5656 herefd = -1; 5657 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5658 STPUTC('\0', expdest); 5659 herefd = saveherefd; 5660 argbackq = saveargbackq; 5661 startp = stackblock() + startloc; 5662 5663 switch (subtype) { 5664 case VSASSIGN: 5665 setvar(str, startp, 0); 5666 amount = startp - expdest; 5667 STADJUST(amount, expdest); 5668 return startp; 5669 5670 case VSQUESTION: 5671 varunset(p, str, startp, varflags); 5672 /* NOTREACHED */ 5673 } 5674 5675 subtype -= VSTRIMRIGHT; 5676 #if DEBUG 5677 if (subtype < 0 || subtype > 3) 5678 abort(); 5679 #endif 5680 5681 rmesc = startp; 5682 rmescend = stackblock() + strloc; 5683 if (quotes) { 5684 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5685 if (rmesc != startp) { 5686 rmescend = expdest; 5687 startp = stackblock() + startloc; 5688 } 5689 } 5690 rmescend--; 5691 str = stackblock() + strloc; 5692 preglob(str, varflags & VSQUOTE, 0); 5693 5694 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 5695 zero = subtype >> 1; 5696 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ 5697 scan = (subtype & 1) ^ zero ? scanleft : scanright; 5698 5699 loc = scan(startp, rmesc, rmescend, str, quotes, zero); 5700 if (loc) { 5701 if (zero) { 5702 memmove(startp, loc, str - loc); 5703 loc = startp + (str - loc) - 1; 5704 } 5705 *loc = '\0'; 5706 amount = loc - expdest; 5707 STADJUST(amount, expdest); 5708 } 5709 return loc; 5710 } 5711 5712 /* 5713 * Add the value of a specialized variable to the stack string. 5714 */ 5715 static ssize_t 5716 varvalue(char *name, int varflags, int flags) 5717 { 5718 int num; 5719 char *p; 5720 int i; 5721 int sep = 0; 5722 int sepq = 0; 5723 ssize_t len = 0; 5724 char **ap; 5725 int syntax; 5726 int quoted = varflags & VSQUOTE; 5727 int subtype = varflags & VSTYPE; 5728 int quotes = flags & (EXP_FULL | EXP_CASE); 5729 5730 if (quoted && (flags & EXP_FULL)) 5731 sep = 1 << CHAR_BIT; 5732 5733 syntax = quoted ? DQSYNTAX : BASESYNTAX; 5734 switch (*name) { 5735 case '$': 5736 num = rootpid; 5737 goto numvar; 5738 case '?': 5739 num = exitstatus; 5740 goto numvar; 5741 case '#': 5742 num = shellparam.nparam; 5743 goto numvar; 5744 case '!': 5745 num = backgndpid; 5746 if (num == 0) 5747 return -1; 5748 numvar: 5749 len = cvtnum(num); 5750 break; 5751 case '-': 5752 p = makestrspace(NOPTS, expdest); 5753 for (i = NOPTS - 1; i >= 0; i--) { 5754 if (optlist[i]) { 5755 USTPUTC(optletters(i), p); 5756 len++; 5757 } 5758 } 5759 expdest = p; 5760 break; 5761 case '@': 5762 if (sep) 5763 goto param; 5764 /* fall through */ 5765 case '*': 5766 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' '; 5767 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 5768 sepq = 1; 5769 param: 5770 ap = shellparam.p; 5771 if (!ap) 5772 return -1; 5773 while ((p = *ap++)) { 5774 size_t partlen; 5775 5776 partlen = strlen(p); 5777 len += partlen; 5778 5779 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5780 memtodest(p, partlen, syntax, quotes); 5781 5782 if (*ap && sep) { 5783 char *q; 5784 5785 len++; 5786 if (subtype == VSPLUS || subtype == VSLENGTH) { 5787 continue; 5788 } 5789 q = expdest; 5790 if (sepq) 5791 STPUTC(CTLESC, q); 5792 STPUTC(sep, q); 5793 expdest = q; 5794 } 5795 } 5796 return len; 5797 case '0': 5798 case '1': 5799 case '2': 5800 case '3': 5801 case '4': 5802 case '5': 5803 case '6': 5804 case '7': 5805 case '8': 5806 case '9': 5807 num = atoi(name); 5808 if (num < 0 || num > shellparam.nparam) 5809 return -1; 5810 p = num ? shellparam.p[num - 1] : arg0; 5811 goto value; 5812 default: 5813 p = lookupvar(name); 5814 value: 5815 if (!p) 5816 return -1; 5817 5818 len = strlen(p); 5819 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5820 memtodest(p, len, syntax, quotes); 5821 return len; 5822 } 5823 5824 if (subtype == VSPLUS || subtype == VSLENGTH) 5825 STADJUST(-len, expdest); 5826 return len; 5827 } 5828 5829 /* 5830 * Expand a variable, and return a pointer to the next character in the 5831 * input string. 5832 */ 5833 static char * 5834 evalvar(char *p, int flag) 5835 { 5836 int subtype; 5837 int varflags; 5838 char *var; 5839 int patloc; 5840 int c; 5841 int startloc; 5842 ssize_t varlen; 5843 int easy; 5844 int quotes; 5845 int quoted; 5846 5847 quotes = flag & (EXP_FULL | EXP_CASE); 5848 varflags = *p++; 5849 subtype = varflags & VSTYPE; 5850 quoted = varflags & VSQUOTE; 5851 var = p; 5852 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5853 startloc = expdest - (char *)stackblock(); 5854 p = strchr(p, '=') + 1; 5855 5856 again: 5857 varlen = varvalue(var, varflags, flag); 5858 if (varflags & VSNUL) 5859 varlen--; 5860 5861 if (subtype == VSPLUS) { 5862 varlen = -1 - varlen; 5863 goto vsplus; 5864 } 5865 5866 if (subtype == VSMINUS) { 5867 vsplus: 5868 if (varlen < 0) { 5869 argstr( 5870 p, flag | EXP_TILDE | 5871 (quoted ? EXP_QWORD : EXP_WORD) 5872 ); 5873 goto end; 5874 } 5875 if (easy) 5876 goto record; 5877 goto end; 5878 } 5879 5880 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5881 if (varlen < 0) { 5882 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { 5883 varflags &= ~VSNUL; 5884 /* 5885 * Remove any recorded regions beyond 5886 * start of variable 5887 */ 5888 removerecordregions(startloc); 5889 goto again; 5890 } 5891 goto end; 5892 } 5893 if (easy) 5894 goto record; 5895 goto end; 5896 } 5897 5898 if (varlen < 0 && uflag) 5899 varunset(p, var, 0, 0); 5900 5901 if (subtype == VSLENGTH) { 5902 cvtnum(varlen > 0 ? varlen : 0); 5903 goto record; 5904 } 5905 5906 if (subtype == VSNORMAL) { 5907 if (!easy) 5908 goto end; 5909 record: 5910 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5911 goto end; 5912 } 5913 5914 #if DEBUG 5915 switch (subtype) { 5916 case VSTRIMLEFT: 5917 case VSTRIMLEFTMAX: 5918 case VSTRIMRIGHT: 5919 case VSTRIMRIGHTMAX: 5920 break; 5921 default: 5922 abort(); 5923 } 5924 #endif 5925 5926 if (varlen >= 0) { 5927 /* 5928 * Terminate the string and start recording the pattern 5929 * right after it 5930 */ 5931 STPUTC('\0', expdest); 5932 patloc = expdest - (char *)stackblock(); 5933 if (subevalvar(p, NULL, patloc, subtype, 5934 startloc, varflags, quotes) == 0) { 5935 int amount = expdest - ( 5936 (char *)stackblock() + patloc - 1 5937 ); 5938 STADJUST(-amount, expdest); 5939 } 5940 /* Remove any recorded regions beyond start of variable */ 5941 removerecordregions(startloc); 5942 goto record; 5943 } 5944 5945 end: 5946 if (subtype != VSNORMAL) { /* skip to end of alternative */ 5947 int nesting = 1; 5948 for (;;) { 5949 c = *p++; 5950 if (c == CTLESC) 5951 p++; 5952 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 5953 if (varlen >= 0) 5954 argbackq = argbackq->next; 5955 } else if (c == CTLVAR) { 5956 if ((*p++ & VSTYPE) != VSNORMAL) 5957 nesting++; 5958 } else if (c == CTLENDVAR) { 5959 if (--nesting == 0) 5960 break; 5961 } 5962 } 5963 } 5964 return p; 5965 } 5966 5967 /* 5968 * Break the argument string into pieces based upon IFS and add the 5969 * strings to the argument list. The regions of the string to be 5970 * searched for IFS characters have been stored by recordregion. 5971 */ 5972 static void 5973 ifsbreakup(char *string, struct arglist *arglist) 5974 { 5975 struct ifsregion *ifsp; 5976 struct strlist *sp; 5977 char *start; 5978 char *p; 5979 char *q; 5980 const char *ifs, *realifs; 5981 int ifsspc; 5982 int nulonly; 5983 5984 start = string; 5985 if (ifslastp != NULL) { 5986 ifsspc = 0; 5987 nulonly = 0; 5988 realifs = ifsset() ? ifsval() : defifs; 5989 ifsp = &ifsfirst; 5990 do { 5991 p = string + ifsp->begoff; 5992 nulonly = ifsp->nulonly; 5993 ifs = nulonly ? nullstr : realifs; 5994 ifsspc = 0; 5995 while (p < string + ifsp->endoff) { 5996 q = p; 5997 if (*p == CTLESC) 5998 p++; 5999 if (!strchr(ifs, *p)) { 6000 p++; 6001 continue; 6002 } 6003 if (!nulonly) 6004 ifsspc = (strchr(defifs, *p) != NULL); 6005 /* Ignore IFS whitespace at start */ 6006 if (q == start && ifsspc) { 6007 p++; 6008 start = p; 6009 continue; 6010 } 6011 *q = '\0'; 6012 sp = stalloc(sizeof(*sp)); 6013 sp->text = start; 6014 *arglist->lastp = sp; 6015 arglist->lastp = &sp->next; 6016 p++; 6017 if (!nulonly) { 6018 for (;;) { 6019 if (p >= string + ifsp->endoff) { 6020 break; 6021 } 6022 q = p; 6023 if (*p == CTLESC) 6024 p++; 6025 if (strchr(ifs, *p) == NULL ) { 6026 p = q; 6027 break; 6028 } else if (strchr(defifs, *p) == NULL) { 6029 if (ifsspc) { 6030 p++; 6031 ifsspc = 0; 6032 } else { 6033 p = q; 6034 break; 6035 } 6036 } else 6037 p++; 6038 } 6039 } 6040 start = p; 6041 } /* while */ 6042 ifsp = ifsp->next; 6043 } while (ifsp != NULL); 6044 if (nulonly) 6045 goto add; 6046 } 6047 6048 if (!*start) 6049 return; 6050 6051 add: 6052 sp = stalloc(sizeof(*sp)); 6053 sp->text = start; 6054 *arglist->lastp = sp; 6055 arglist->lastp = &sp->next; 6056 } 6057 6058 static void 6059 ifsfree(void) 6060 { 6061 struct ifsregion *p; 6062 6063 INT_OFF; 6064 p = ifsfirst.next; 6065 do { 6066 struct ifsregion *ifsp; 6067 ifsp = p->next; 6068 free(p); 6069 p = ifsp; 6070 } while (p); 6071 ifslastp = NULL; 6072 ifsfirst.next = NULL; 6073 INT_ON; 6074 } 6075 6076 /* 6077 * Add a file name to the list. 6078 */ 6079 static void 6080 addfname(const char *name) 6081 { 6082 struct strlist *sp; 6083 6084 sp = stalloc(sizeof(*sp)); 6085 sp->text = ststrdup(name); 6086 *exparg.lastp = sp; 6087 exparg.lastp = &sp->next; 6088 } 6089 6090 static char *expdir; 6091 6092 /* 6093 * Do metacharacter (i.e. *, ?, [...]) expansion. 6094 */ 6095 static void 6096 expmeta(char *enddir, char *name) 6097 { 6098 char *p; 6099 const char *cp; 6100 char *start; 6101 char *endname; 6102 int metaflag; 6103 struct stat statb; 6104 DIR *dirp; 6105 struct dirent *dp; 6106 int atend; 6107 int matchdot; 6108 6109 metaflag = 0; 6110 start = name; 6111 for (p = name; *p; p++) { 6112 if (*p == '*' || *p == '?') 6113 metaflag = 1; 6114 else if (*p == '[') { 6115 char *q = p + 1; 6116 if (*q == '!') 6117 q++; 6118 for (;;) { 6119 if (*q == '\\') 6120 q++; 6121 if (*q == '/' || *q == '\0') 6122 break; 6123 if (*++q == ']') { 6124 metaflag = 1; 6125 break; 6126 } 6127 } 6128 } else if (*p == '\\') 6129 p++; 6130 else if (*p == '/') { 6131 if (metaflag) 6132 goto out; 6133 start = p + 1; 6134 } 6135 } 6136 out: 6137 if (metaflag == 0) { /* we've reached the end of the file name */ 6138 if (enddir != expdir) 6139 metaflag++; 6140 p = name; 6141 do { 6142 if (*p == '\\') 6143 p++; 6144 *enddir++ = *p; 6145 } while (*p++); 6146 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 6147 addfname(expdir); 6148 return; 6149 } 6150 endname = p; 6151 if (name < start) { 6152 p = name; 6153 do { 6154 if (*p == '\\') 6155 p++; 6156 *enddir++ = *p++; 6157 } while (p < start); 6158 } 6159 if (enddir == expdir) { 6160 cp = "."; 6161 } else if (enddir == expdir + 1 && *expdir == '/') { 6162 cp = "/"; 6163 } else { 6164 cp = expdir; 6165 enddir[-1] = '\0'; 6166 } 6167 dirp = opendir(cp); 6168 if (dirp == NULL) 6169 return; 6170 if (enddir != expdir) 6171 enddir[-1] = '/'; 6172 if (*endname == 0) { 6173 atend = 1; 6174 } else { 6175 atend = 0; 6176 *endname++ = '\0'; 6177 } 6178 matchdot = 0; 6179 p = start; 6180 if (*p == '\\') 6181 p++; 6182 if (*p == '.') 6183 matchdot++; 6184 while (! intpending && (dp = readdir(dirp)) != NULL) { 6185 if (dp->d_name[0] == '.' && ! matchdot) 6186 continue; 6187 if (pmatch(start, dp->d_name)) { 6188 if (atend) { 6189 strcpy(enddir, dp->d_name); 6190 addfname(expdir); 6191 } else { 6192 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) 6193 continue; 6194 p[-1] = '/'; 6195 expmeta(p, endname); 6196 } 6197 } 6198 } 6199 closedir(dirp); 6200 if (! atend) 6201 endname[-1] = '/'; 6202 } 6203 6204 static struct strlist * 6205 msort(struct strlist *list, int len) 6206 { 6207 struct strlist *p, *q = NULL; 6208 struct strlist **lpp; 6209 int half; 6210 int n; 6211 6212 if (len <= 1) 6213 return list; 6214 half = len >> 1; 6215 p = list; 6216 for (n = half; --n >= 0; ) { 6217 q = p; 6218 p = p->next; 6219 } 6220 q->next = NULL; /* terminate first half of list */ 6221 q = msort(list, half); /* sort first half of list */ 6222 p = msort(p, len - half); /* sort second half */ 6223 lpp = &list; 6224 for (;;) { 6225 #if ENABLE_LOCALE_SUPPORT 6226 if (strcoll(p->text, q->text) < 0) 6227 #else 6228 if (strcmp(p->text, q->text) < 0) 6229 #endif 6230 { 6231 *lpp = p; 6232 lpp = &p->next; 6233 p = *lpp; 6234 if (p == NULL) { 6235 *lpp = q; 6236 break; 6237 } 6238 } else { 6239 *lpp = q; 6240 lpp = &q->next; 6241 q = *lpp; 6242 if (q == NULL) { 6243 *lpp = p; 6244 break; 6245 } 6246 } 6247 } 6248 return list; 6249 } 6250 6251 /* 6252 * Sort the results of file name expansion. It calculates the number of 6253 * strings to sort and then calls msort (short for merge sort) to do the 6254 * work. 6255 */ 6256 static struct strlist * 6257 expsort(struct strlist *str) 6258 { 6259 int len; 6260 struct strlist *sp; 6261 6262 len = 0; 6263 for (sp = str; sp; sp = sp->next) 6264 len++; 6265 return msort(str, len); 6266 } 6267 6268 static void 6269 expandmeta(struct strlist *str, int flag) 6270 { 6271 static const char metachars[] ALIGN1 = { 6272 '*', '?', '[', 0 6273 }; 6274 /* TODO - EXP_REDIR */ 6275 6276 while (str) { 6277 struct strlist **savelastp; 6278 struct strlist *sp; 6279 char *p; 6280 6281 if (fflag) 6282 goto nometa; 6283 if (!strpbrk(str->text, metachars)) 6284 goto nometa; 6285 savelastp = exparg.lastp; 6286 6287 INT_OFF; 6288 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 6289 { 6290 int i = strlen(str->text); 6291 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 6292 } 6293 6294 expmeta(expdir, p); 6295 free(expdir); 6296 if (p != str->text) 6297 free(p); 6298 INT_ON; 6299 if (exparg.lastp == savelastp) { 6300 /* 6301 * no matches 6302 */ 6303 nometa: 6304 *exparg.lastp = str; 6305 rmescapes(str->text); 6306 exparg.lastp = &str->next; 6307 } else { 6308 *exparg.lastp = NULL; 6309 *savelastp = sp = expsort(*savelastp); 6310 while (sp->next != NULL) 6311 sp = sp->next; 6312 exparg.lastp = &sp->next; 6313 } 6314 str = str->next; 6315 } 6316 } 6317 6318 /* 6319 * Perform variable substitution and command substitution on an argument, 6320 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 6321 * perform splitting and file name expansion. When arglist is NULL, perform 6322 * here document expansion. 6323 */ 6324 static void 6325 expandarg(union node *arg, struct arglist *arglist, int flag) 6326 { 6327 struct strlist *sp; 6328 char *p; 6329 6330 argbackq = arg->narg.backquote; 6331 STARTSTACKSTR(expdest); 6332 ifsfirst.next = NULL; 6333 ifslastp = NULL; 6334 argstr(arg->narg.text, flag); 6335 p = _STPUTC('\0', expdest); 6336 expdest = p - 1; 6337 if (arglist == NULL) { 6338 return; /* here document expanded */ 6339 } 6340 p = grabstackstr(p); 6341 exparg.lastp = &exparg.list; 6342 /* 6343 * TODO - EXP_REDIR 6344 */ 6345 if (flag & EXP_FULL) { 6346 ifsbreakup(p, &exparg); 6347 *exparg.lastp = NULL; 6348 exparg.lastp = &exparg.list; 6349 expandmeta(exparg.list, flag); 6350 } else { 6351 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 6352 rmescapes(p); 6353 sp = stalloc(sizeof(*sp)); 6354 sp->text = p; 6355 *exparg.lastp = sp; 6356 exparg.lastp = &sp->next; 6357 } 6358 if (ifsfirst.next) 6359 ifsfree(); 6360 *exparg.lastp = NULL; 6361 if (exparg.list) { 6362 *arglist->lastp = exparg.list; 6363 arglist->lastp = exparg.lastp; 6364 } 6365 } 6366 6367 /* 6368 * Expand shell variables and backquotes inside a here document. 6369 */ 6370 static void 6371 expandhere(union node *arg, int fd) 6372 { 6373 herefd = fd; 6374 expandarg(arg, (struct arglist *)NULL, 0); 6375 full_write(fd, stackblock(), expdest - (char *)stackblock()); 6376 } 6377 6378 /* 6379 * Returns true if the pattern matches the string. 6380 */ 6381 static int 6382 patmatch(char *pattern, const char *string) 6383 { 6384 return pmatch(preglob(pattern, 0, 0), string); 6385 } 6386 6387 /* 6388 * See if a pattern matches in a case statement. 6389 */ 6390 static int 6391 casematch(union node *pattern, char *val) 6392 { 6393 struct stackmark smark; 6394 int result; 6395 6396 setstackmark(&smark); 6397 argbackq = pattern->narg.backquote; 6398 STARTSTACKSTR(expdest); 6399 ifslastp = NULL; 6400 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 6401 STACKSTRNUL(expdest); 6402 result = patmatch(stackblock(), val); 6403 popstackmark(&smark); 6404 return result; 6405 } 6406 6407 6408 /* ============ find_command */ 6409 6410 struct builtincmd { 6411 const char *name; 6412 int (*builtin)(int, char **); 6413 /* unsigned flags; */ 6414 }; 6415 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1) 6416 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2) 6417 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4) 6418 6419 struct cmdentry { 6420 int cmdtype; 6421 union param { 6422 int index; 6423 const struct builtincmd *cmd; 6424 struct funcnode *func; 6425 } u; 6426 }; 6427 /* values of cmdtype */ 6428 #define CMDUNKNOWN -1 /* no entry in table for command */ 6429 #define CMDNORMAL 0 /* command is an executable program */ 6430 #define CMDFUNCTION 1 /* command is a shell function */ 6431 #define CMDBUILTIN 2 /* command is a shell builtin */ 6432 6433 /* action to find_command() */ 6434 #define DO_ERR 0x01 /* prints errors */ 6435 #define DO_ABS 0x02 /* checks absolute paths */ 6436 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 6437 #define DO_ALTPATH 0x08 /* using alternate path */ 6438 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 6439 6440 static void find_command(char *, struct cmdentry *, int, const char *); 6441 6442 6443 /* ============ Hashing commands */ 6444 6445 /* 6446 * When commands are first encountered, they are entered in a hash table. 6447 * This ensures that a full path search will not have to be done for them 6448 * on each invocation. 6449 * 6450 * We should investigate converting to a linear search, even though that 6451 * would make the command name "hash" a misnomer. 6452 */ 6453 6454 #define CMDTABLESIZE 31 /* should be prime */ 6455 #define ARB 1 /* actual size determined at run time */ 6456 6457 struct tblentry { 6458 struct tblentry *next; /* next entry in hash chain */ 6459 union param param; /* definition of builtin function */ 6460 short cmdtype; /* index identifying command */ 6461 char rehash; /* if set, cd done since entry created */ 6462 char cmdname[ARB]; /* name of command */ 6463 }; 6464 6465 static struct tblentry *cmdtable[CMDTABLESIZE]; 6466 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 6467 6468 static void 6469 tryexec(char *cmd, char **argv, char **envp) 6470 { 6471 int repeated = 0; 6472 6473 #if ENABLE_FEATURE_SH_STANDALONE 6474 if (strchr(cmd, '/') == NULL) { 6475 const struct bb_applet *a; 6476 6477 a = find_applet_by_name(cmd); 6478 if (a) { 6479 if (a->noexec) { 6480 current_applet = a; 6481 run_current_applet_and_exit(argv); 6482 } 6483 /* re-exec ourselves with the new arguments */ 6484 execve(bb_busybox_exec_path, argv, envp); 6485 /* If they called chroot or otherwise made the binary no longer 6486 * executable, fall through */ 6487 } 6488 } 6489 #endif 6490 6491 repeat: 6492 #ifdef SYSV 6493 do { 6494 execve(cmd, argv, envp); 6495 } while (errno == EINTR); 6496 #else 6497 execve(cmd, argv, envp); 6498 #endif 6499 if (repeated++) { 6500 free(argv); 6501 } else if (errno == ENOEXEC) { 6502 char **ap; 6503 char **new; 6504 6505 for (ap = argv; *ap; ap++) 6506 ; 6507 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); 6508 ap[1] = cmd; 6509 ap[0] = cmd = (char *)DEFAULT_SHELL; 6510 ap += 2; 6511 argv++; 6512 while ((*ap++ = *argv++)) 6513 ; 6514 argv = new; 6515 goto repeat; 6516 } 6517 } 6518 6519 /* 6520 * Exec a program. Never returns. If you change this routine, you may 6521 * have to change the find_command routine as well. 6522 */ 6523 #define environment() listvars(VEXPORT, VUNSET, 0) 6524 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 6525 static void 6526 shellexec(char **argv, const char *path, int idx) 6527 { 6528 char *cmdname; 6529 int e; 6530 char **envp; 6531 int exerrno; 6532 6533 clearredir(1); 6534 envp = environment(); 6535 if (strchr(argv[0], '/') 6536 #if ENABLE_FEATURE_SH_STANDALONE 6537 || find_applet_by_name(argv[0]) 6538 #endif 6539 ) { 6540 tryexec(argv[0], argv, envp); 6541 e = errno; 6542 } else { 6543 e = ENOENT; 6544 while ((cmdname = padvance(&path, argv[0])) != NULL) { 6545 if (--idx < 0 && pathopt == NULL) { 6546 tryexec(cmdname, argv, envp); 6547 if (errno != ENOENT && errno != ENOTDIR) 6548 e = errno; 6549 } 6550 stunalloc(cmdname); 6551 } 6552 } 6553 6554 /* Map to POSIX errors */ 6555 switch (e) { 6556 case EACCES: 6557 exerrno = 126; 6558 break; 6559 case ENOENT: 6560 exerrno = 127; 6561 break; 6562 default: 6563 exerrno = 2; 6564 break; 6565 } 6566 exitstatus = exerrno; 6567 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", 6568 argv[0], e, suppressint )); 6569 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); 6570 /* NOTREACHED */ 6571 } 6572 6573 static void 6574 printentry(struct tblentry *cmdp) 6575 { 6576 int idx; 6577 const char *path; 6578 char *name; 6579 6580 idx = cmdp->param.index; 6581 path = pathval(); 6582 do { 6583 name = padvance(&path, cmdp->cmdname); 6584 stunalloc(name); 6585 } while (--idx >= 0); 6586 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 6587 } 6588 6589 /* 6590 * Clear out command entries. The argument specifies the first entry in 6591 * PATH which has changed. 6592 */ 6593 static void 6594 clearcmdentry(int firstchange) 6595 { 6596 struct tblentry **tblp; 6597 struct tblentry **pp; 6598 struct tblentry *cmdp; 6599 6600 INT_OFF; 6601 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { 6602 pp = tblp; 6603 while ((cmdp = *pp) != NULL) { 6604 if ((cmdp->cmdtype == CMDNORMAL && 6605 cmdp->param.index >= firstchange) 6606 || (cmdp->cmdtype == CMDBUILTIN && 6607 builtinloc >= firstchange) 6608 ) { 6609 *pp = cmdp->next; 6610 free(cmdp); 6611 } else { 6612 pp = &cmdp->next; 6613 } 6614 } 6615 } 6616 INT_ON; 6617 } 6618 6619 /* 6620 * Locate a command in the command hash table. If "add" is nonzero, 6621 * add the command to the table if it is not already present. The 6622 * variable "lastcmdentry" is set to point to the address of the link 6623 * pointing to the entry, so that delete_cmd_entry can delete the 6624 * entry. 6625 * 6626 * Interrupts must be off if called with add != 0. 6627 */ 6628 static struct tblentry **lastcmdentry; 6629 6630 static struct tblentry * 6631 cmdlookup(const char *name, int add) 6632 { 6633 unsigned int hashval; 6634 const char *p; 6635 struct tblentry *cmdp; 6636 struct tblentry **pp; 6637 6638 p = name; 6639 hashval = (unsigned char)*p << 4; 6640 while (*p) 6641 hashval += (unsigned char)*p++; 6642 hashval &= 0x7FFF; 6643 pp = &cmdtable[hashval % CMDTABLESIZE]; 6644 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6645 if (strcmp(cmdp->cmdname, name) == 0) 6646 break; 6647 pp = &cmdp->next; 6648 } 6649 if (add && cmdp == NULL) { 6650 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB 6651 + strlen(name) + 1); 6652 cmdp->next = NULL; 6653 cmdp->cmdtype = CMDUNKNOWN; 6654 strcpy(cmdp->cmdname, name); 6655 } 6656 lastcmdentry = pp; 6657 return cmdp; 6658 } 6659 6660 /* 6661 * Delete the command entry returned on the last lookup. 6662 */ 6663 static void 6664 delete_cmd_entry(void) 6665 { 6666 struct tblentry *cmdp; 6667 6668 INT_OFF; 6669 cmdp = *lastcmdentry; 6670 *lastcmdentry = cmdp->next; 6671 if (cmdp->cmdtype == CMDFUNCTION) 6672 freefunc(cmdp->param.func); 6673 free(cmdp); 6674 INT_ON; 6675 } 6676 6677 /* 6678 * Add a new command entry, replacing any existing command entry for 6679 * the same name - except special builtins. 6680 */ 6681 static void 6682 addcmdentry(char *name, struct cmdentry *entry) 6683 { 6684 struct tblentry *cmdp; 6685 6686 cmdp = cmdlookup(name, 1); 6687 if (cmdp->cmdtype == CMDFUNCTION) { 6688 freefunc(cmdp->param.func); 6689 } 6690 cmdp->cmdtype = entry->cmdtype; 6691 cmdp->param = entry->u; 6692 cmdp->rehash = 0; 6693 } 6694 6695 static int 6696 hashcmd(int argc, char **argv) 6697 { 6698 struct tblentry **pp; 6699 struct tblentry *cmdp; 6700 int c; 6701 struct cmdentry entry; 6702 char *name; 6703 6704 while ((c = nextopt("r")) != '\0') { 6705 clearcmdentry(0); 6706 return 0; 6707 } 6708 if (*argptr == NULL) { 6709 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6710 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6711 if (cmdp->cmdtype == CMDNORMAL) 6712 printentry(cmdp); 6713 } 6714 } 6715 return 0; 6716 } 6717 c = 0; 6718 while ((name = *argptr) != NULL) { 6719 cmdp = cmdlookup(name, 0); 6720 if (cmdp != NULL 6721 && (cmdp->cmdtype == CMDNORMAL 6722 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 6723 delete_cmd_entry(); 6724 find_command(name, &entry, DO_ERR, pathval()); 6725 if (entry.cmdtype == CMDUNKNOWN) 6726 c = 1; 6727 argptr++; 6728 } 6729 return c; 6730 } 6731 6732 /* 6733 * Called when a cd is done. Marks all commands so the next time they 6734 * are executed they will be rehashed. 6735 */ 6736 static void 6737 hashcd(void) 6738 { 6739 struct tblentry **pp; 6740 struct tblentry *cmdp; 6741 6742 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6743 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6744 if (cmdp->cmdtype == CMDNORMAL || ( 6745 cmdp->cmdtype == CMDBUILTIN && 6746 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) && 6747 builtinloc > 0 6748 )) 6749 cmdp->rehash = 1; 6750 } 6751 } 6752 } 6753 6754 /* 6755 * Fix command hash table when PATH changed. 6756 * Called before PATH is changed. The argument is the new value of PATH; 6757 * pathval() still returns the old value at this point. 6758 * Called with interrupts off. 6759 */ 6760 static void 6761 changepath(const char *newval) 6762 { 6763 const char *old, *new; 6764 int idx; 6765 int firstchange; 6766 int idx_bltin; 6767 6768 old = pathval(); 6769 new = newval; 6770 firstchange = 9999; /* assume no change */ 6771 idx = 0; 6772 idx_bltin = -1; 6773 for (;;) { 6774 if (*old != *new) { 6775 firstchange = idx; 6776 if ((*old == '\0' && *new == ':') 6777 || (*old == ':' && *new == '\0')) 6778 firstchange++; 6779 old = new; /* ignore subsequent differences */ 6780 } 6781 if (*new == '\0') 6782 break; 6783 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 6784 idx_bltin = idx; 6785 if (*new == ':') { 6786 idx++; 6787 } 6788 new++, old++; 6789 } 6790 if (builtinloc < 0 && idx_bltin >= 0) 6791 builtinloc = idx_bltin; /* zap builtins */ 6792 if (builtinloc >= 0 && idx_bltin < 0) 6793 firstchange = 0; 6794 clearcmdentry(firstchange); 6795 builtinloc = idx_bltin; 6796 } 6797 6798 #define TEOF 0 6799 #define TNL 1 6800 #define TREDIR 2 6801 #define TWORD 3 6802 #define TSEMI 4 6803 #define TBACKGND 5 6804 #define TAND 6 6805 #define TOR 7 6806 #define TPIPE 8 6807 #define TLP 9 6808 #define TRP 10 6809 #define TENDCASE 11 6810 #define TENDBQUOTE 12 6811 #define TNOT 13 6812 #define TCASE 14 6813 #define TDO 15 6814 #define TDONE 16 6815 #define TELIF 17 6816 #define TELSE 18 6817 #define TESAC 19 6818 #define TFI 20 6819 #define TFOR 21 6820 #define TIF 22 6821 #define TIN 23 6822 #define TTHEN 24 6823 #define TUNTIL 25 6824 #define TWHILE 26 6825 #define TBEGIN 27 6826 #define TEND 28 6827 6828 /* first char is indicating which tokens mark the end of a list */ 6829 static const char *const tokname_array[] = { 6830 "\1end of file", 6831 "\0newline", 6832 "\0redirection", 6833 "\0word", 6834 "\0;", 6835 "\0&", 6836 "\0&&", 6837 "\0||", 6838 "\0|", 6839 "\0(", 6840 "\1)", 6841 "\1;;", 6842 "\1`", 6843 #define KWDOFFSET 13 6844 /* the following are keywords */ 6845 "\0!", 6846 "\0case", 6847 "\1do", 6848 "\1done", 6849 "\1elif", 6850 "\1else", 6851 "\1esac", 6852 "\1fi", 6853 "\0for", 6854 "\0if", 6855 "\0in", 6856 "\1then", 6857 "\0until", 6858 "\0while", 6859 "\0{", 6860 "\1}", 6861 }; 6862 6863 static const char * 6864 tokname(int tok) 6865 { 6866 static char buf[16]; 6867 6868 //try this: 6869 //if (tok < TSEMI) return tokname_array[tok] + 1; 6870 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1); 6871 //return buf; 6872 6873 if (tok >= TSEMI) 6874 buf[0] = '"'; 6875 sprintf(buf + (tok >= TSEMI), "%s%c", 6876 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0)); 6877 return buf; 6878 } 6879 6880 /* Wrapper around strcmp for qsort/bsearch/... */ 6881 static int 6882 pstrcmp(const void *a, const void *b) 6883 { 6884 return strcmp((char*) a, (*(char**) b) + 1); 6885 } 6886 6887 static const char *const * 6888 findkwd(const char *s) 6889 { 6890 return bsearch(s, tokname_array + KWDOFFSET, 6891 ARRAY_SIZE(tokname_array) - KWDOFFSET, 6892 sizeof(tokname_array[0]), pstrcmp); 6893 } 6894 6895 /* 6896 * Locate and print what a word is... 6897 */ 6898 static int 6899 describe_command(char *command, int describe_command_verbose) 6900 { 6901 struct cmdentry entry; 6902 struct tblentry *cmdp; 6903 #if ENABLE_ASH_ALIAS 6904 const struct alias *ap; 6905 #endif 6906 const char *path = pathval(); 6907 6908 if (describe_command_verbose) { 6909 out1str(command); 6910 } 6911 6912 /* First look at the keywords */ 6913 if (findkwd(command)) { 6914 out1str(describe_command_verbose ? " is a shell keyword" : command); 6915 goto out; 6916 } 6917 6918 #if ENABLE_ASH_ALIAS 6919 /* Then look at the aliases */ 6920 ap = lookupalias(command, 0); 6921 if (ap != NULL) { 6922 if (!describe_command_verbose) { 6923 out1str("alias "); 6924 printalias(ap); 6925 return 0; 6926 } 6927 out1fmt(" is an alias for %s", ap->val); 6928 goto out; 6929 } 6930 #endif 6931 /* Then check if it is a tracked alias */ 6932 cmdp = cmdlookup(command, 0); 6933 if (cmdp != NULL) { 6934 entry.cmdtype = cmdp->cmdtype; 6935 entry.u = cmdp->param; 6936 } else { 6937 /* Finally use brute force */ 6938 find_command(command, &entry, DO_ABS, path); 6939 } 6940 6941 switch (entry.cmdtype) { 6942 case CMDNORMAL: { 6943 int j = entry.u.index; 6944 char *p; 6945 if (j == -1) { 6946 p = command; 6947 } else { 6948 do { 6949 p = padvance(&path, command); 6950 stunalloc(p); 6951 } while (--j >= 0); 6952 } 6953 if (describe_command_verbose) { 6954 out1fmt(" is%s %s", 6955 (cmdp ? " a tracked alias for" : nullstr), p 6956 ); 6957 } else { 6958 out1str(p); 6959 } 6960 break; 6961 } 6962 6963 case CMDFUNCTION: 6964 if (describe_command_verbose) { 6965 out1str(" is a shell function"); 6966 } else { 6967 out1str(command); 6968 } 6969 break; 6970 6971 case CMDBUILTIN: 6972 if (describe_command_verbose) { 6973 out1fmt(" is a %sshell builtin", 6974 IS_BUILTIN_SPECIAL(entry.u.cmd) ? 6975 "special " : nullstr 6976 ); 6977 } else { 6978 out1str(command); 6979 } 6980 break; 6981 6982 default: 6983 if (describe_command_verbose) { 6984 out1str(": not found\n"); 6985 } 6986 return 127; 6987 } 6988 out: 6989 outstr("\n", stdout); 6990 return 0; 6991 } 6992 6993 static int 6994 typecmd(int argc, char **argv) 6995 { 6996 int i = 1; 6997 int err = 0; 6998 int verbose = 1; 6999 7000 /* type -p ... ? (we don't bother checking for 'p') */ 7001 if (argv[1] && argv[1][0] == '-') { 7002 i++; 7003 verbose = 0; 7004 } 7005 while (i < argc) { 7006 err |= describe_command(argv[i++], verbose); 7007 } 7008 return err; 7009 } 7010 7011 #if ENABLE_ASH_CMDCMD 7012 static int 7013 commandcmd(int argc, char **argv) 7014 { 7015 int c; 7016 enum { 7017 VERIFY_BRIEF = 1, 7018 VERIFY_VERBOSE = 2, 7019 } verify = 0; 7020 7021 while ((c = nextopt("pvV")) != '\0') 7022 if (c == 'V') 7023 verify |= VERIFY_VERBOSE; 7024 else if (c == 'v') 7025 verify |= VERIFY_BRIEF; 7026 #if DEBUG 7027 else if (c != 'p') 7028 abort(); 7029 #endif 7030 if (verify) 7031 return describe_command(*argptr, verify - VERIFY_BRIEF); 7032 7033 return 0; 7034 } 7035 #endif 7036 7037 7038 /* ============ eval.c */ 7039 7040 static int funcblocksize; /* size of structures in function */ 7041 static int funcstringsize; /* size of strings in node */ 7042 static void *funcblock; /* block to allocate function from */ 7043 static char *funcstring; /* block to allocate strings from */ 7044 7045 /* flags in argument to evaltree */ 7046 #define EV_EXIT 01 /* exit after evaluating tree */ 7047 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 7048 #define EV_BACKCMD 04 /* command executing within back quotes */ 7049 7050 static const short nodesize[26] = { 7051 SHELL_ALIGN(sizeof(struct ncmd)), 7052 SHELL_ALIGN(sizeof(struct npipe)), 7053 SHELL_ALIGN(sizeof(struct nredir)), 7054 SHELL_ALIGN(sizeof(struct nredir)), 7055 SHELL_ALIGN(sizeof(struct nredir)), 7056 SHELL_ALIGN(sizeof(struct nbinary)), 7057 SHELL_ALIGN(sizeof(struct nbinary)), 7058 SHELL_ALIGN(sizeof(struct nbinary)), 7059 SHELL_ALIGN(sizeof(struct nif)), 7060 SHELL_ALIGN(sizeof(struct nbinary)), 7061 SHELL_ALIGN(sizeof(struct nbinary)), 7062 SHELL_ALIGN(sizeof(struct nfor)), 7063 SHELL_ALIGN(sizeof(struct ncase)), 7064 SHELL_ALIGN(sizeof(struct nclist)), 7065 SHELL_ALIGN(sizeof(struct narg)), 7066 SHELL_ALIGN(sizeof(struct narg)), 7067 SHELL_ALIGN(sizeof(struct nfile)), 7068 SHELL_ALIGN(sizeof(struct nfile)), 7069 SHELL_ALIGN(sizeof(struct nfile)), 7070 SHELL_ALIGN(sizeof(struct nfile)), 7071 SHELL_ALIGN(sizeof(struct nfile)), 7072 SHELL_ALIGN(sizeof(struct ndup)), 7073 SHELL_ALIGN(sizeof(struct ndup)), 7074 SHELL_ALIGN(sizeof(struct nhere)), 7075 SHELL_ALIGN(sizeof(struct nhere)), 7076 SHELL_ALIGN(sizeof(struct nnot)), 7077 }; 7078 7079 static void calcsize(union node *n); 7080 7081 static void 7082 sizenodelist(struct nodelist *lp) 7083 { 7084 while (lp) { 7085 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 7086 calcsize(lp->n); 7087 lp = lp->next; 7088 } 7089 } 7090 7091 static void 7092 calcsize(union node *n) 7093 { 7094 if (n == NULL) 7095 return; 7096 funcblocksize += nodesize[n->type]; 7097 switch (n->type) { 7098 case NCMD: 7099 calcsize(n->ncmd.redirect); 7100 calcsize(n->ncmd.args); 7101 calcsize(n->ncmd.assign); 7102 break; 7103 case NPIPE: 7104 sizenodelist(n->npipe.cmdlist); 7105 break; 7106 case NREDIR: 7107 case NBACKGND: 7108 case NSUBSHELL: 7109 calcsize(n->nredir.redirect); 7110 calcsize(n->nredir.n); 7111 break; 7112 case NAND: 7113 case NOR: 7114 case NSEMI: 7115 case NWHILE: 7116 case NUNTIL: 7117 calcsize(n->nbinary.ch2); 7118 calcsize(n->nbinary.ch1); 7119 break; 7120 case NIF: 7121 calcsize(n->nif.elsepart); 7122 calcsize(n->nif.ifpart); 7123 calcsize(n->nif.test); 7124 break; 7125 case NFOR: 7126 funcstringsize += strlen(n->nfor.var) + 1; 7127 calcsize(n->nfor.body); 7128 calcsize(n->nfor.args); 7129 break; 7130 case NCASE: 7131 calcsize(n->ncase.cases); 7132 calcsize(n->ncase.expr); 7133 break; 7134 case NCLIST: 7135 calcsize(n->nclist.body); 7136 calcsize(n->nclist.pattern); 7137 calcsize(n->nclist.next); 7138 break; 7139 case NDEFUN: 7140 case NARG: 7141 sizenodelist(n->narg.backquote); 7142 funcstringsize += strlen(n->narg.text) + 1; 7143 calcsize(n->narg.next); 7144 break; 7145 case NTO: 7146 case NCLOBBER: 7147 case NFROM: 7148 case NFROMTO: 7149 case NAPPEND: 7150 calcsize(n->nfile.fname); 7151 calcsize(n->nfile.next); 7152 break; 7153 case NTOFD: 7154 case NFROMFD: 7155 calcsize(n->ndup.vname); 7156 calcsize(n->ndup.next); 7157 break; 7158 case NHERE: 7159 case NXHERE: 7160 calcsize(n->nhere.doc); 7161 calcsize(n->nhere.next); 7162 break; 7163 case NNOT: 7164 calcsize(n->nnot.com); 7165 break; 7166 }; 7167 } 7168 7169 static char * 7170 nodeckstrdup(char *s) 7171 { 7172 char *rtn = funcstring; 7173 7174 strcpy(funcstring, s); 7175 funcstring += strlen(s) + 1; 7176 return rtn; 7177 } 7178 7179 static union node *copynode(union node *); 7180 7181 static struct nodelist * 7182 copynodelist(struct nodelist *lp) 7183 { 7184 struct nodelist *start; 7185 struct nodelist **lpp; 7186 7187 lpp = &start; 7188 while (lp) { 7189 *lpp = funcblock; 7190 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 7191 (*lpp)->n = copynode(lp->n); 7192 lp = lp->next; 7193 lpp = &(*lpp)->next; 7194 } 7195 *lpp = NULL; 7196 return start; 7197 } 7198 7199 static union node * 7200 copynode(union node *n) 7201 { 7202 union node *new; 7203 7204 if (n == NULL) 7205 return NULL; 7206 new = funcblock; 7207 funcblock = (char *) funcblock + nodesize[n->type]; 7208 7209 switch (n->type) { 7210 case NCMD: 7211 new->ncmd.redirect = copynode(n->ncmd.redirect); 7212 new->ncmd.args = copynode(n->ncmd.args); 7213 new->ncmd.assign = copynode(n->ncmd.assign); 7214 break; 7215 case NPIPE: 7216 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 7217 new->npipe.backgnd = n->npipe.backgnd; 7218 break; 7219 case NREDIR: 7220 case NBACKGND: 7221 case NSUBSHELL: 7222 new->nredir.redirect = copynode(n->nredir.redirect); 7223 new->nredir.n = copynode(n->nredir.n); 7224 break; 7225 case NAND: 7226 case NOR: 7227 case NSEMI: 7228 case NWHILE: 7229 case NUNTIL: 7230 new->nbinary.ch2 = copynode(n->nbinary.ch2); 7231 new->nbinary.ch1 = copynode(n->nbinary.ch1); 7232 break; 7233 case NIF: 7234 new->nif.elsepart = copynode(n->nif.elsepart); 7235 new->nif.ifpart = copynode(n->nif.ifpart); 7236 new->nif.test = copynode(n->nif.test); 7237 break; 7238 case NFOR: 7239 new->nfor.var = nodeckstrdup(n->nfor.var); 7240 new->nfor.body = copynode(n->nfor.body); 7241 new->nfor.args = copynode(n->nfor.args); 7242 break; 7243 case NCASE: 7244 new->ncase.cases = copynode(n->ncase.cases); 7245 new->ncase.expr = copynode(n->ncase.expr); 7246 break; 7247 case NCLIST: 7248 new->nclist.body = copynode(n->nclist.body); 7249 new->nclist.pattern = copynode(n->nclist.pattern); 7250 new->nclist.next = copynode(n->nclist.next); 7251 break; 7252 case NDEFUN: 7253 case NARG: 7254 new->narg.backquote = copynodelist(n->narg.backquote); 7255 new->narg.text = nodeckstrdup(n->narg.text); 7256 new->narg.next = copynode(n->narg.next); 7257 break; 7258 case NTO: 7259 case NCLOBBER: 7260 case NFROM: 7261 case NFROMTO: 7262 case NAPPEND: 7263 new->nfile.fname = copynode(n->nfile.fname); 7264 new->nfile.fd = n->nfile.fd; 7265 new->nfile.next = copynode(n->nfile.next); 7266 break; 7267 case NTOFD: 7268 case NFROMFD: 7269 new->ndup.vname = copynode(n->ndup.vname); 7270 new->ndup.dupfd = n->ndup.dupfd; 7271 new->ndup.fd = n->ndup.fd; 7272 new->ndup.next = copynode(n->ndup.next); 7273 break; 7274 case NHERE: 7275 case NXHERE: 7276 new->nhere.doc = copynode(n->nhere.doc); 7277 new->nhere.fd = n->nhere.fd; 7278 new->nhere.next = copynode(n->nhere.next); 7279 break; 7280 case NNOT: 7281 new->nnot.com = copynode(n->nnot.com); 7282 break; 7283 }; 7284 new->type = n->type; 7285 return new; 7286 } 7287 7288 /* 7289 * Make a copy of a parse tree. 7290 */ 7291 static struct funcnode * 7292 copyfunc(union node *n) 7293 { 7294 struct funcnode *f; 7295 size_t blocksize; 7296 7297 funcblocksize = offsetof(struct funcnode, n); 7298 funcstringsize = 0; 7299 calcsize(n); 7300 blocksize = funcblocksize; 7301 f = ckmalloc(blocksize + funcstringsize); 7302 funcblock = (char *) f + offsetof(struct funcnode, n); 7303 funcstring = (char *) f + blocksize; 7304 copynode(n); 7305 f->count = 0; 7306 return f; 7307 } 7308 7309 /* 7310 * Define a shell function. 7311 */ 7312 static void 7313 defun(char *name, union node *func) 7314 { 7315 struct cmdentry entry; 7316 7317 INT_OFF; 7318 entry.cmdtype = CMDFUNCTION; 7319 entry.u.func = copyfunc(func); 7320 addcmdentry(name, &entry); 7321 INT_ON; 7322 } 7323 7324 static int evalskip; /* set if we are skipping commands */ 7325 /* reasons for skipping commands (see comment on breakcmd routine) */ 7326 #define SKIPBREAK (1 << 0) 7327 #define SKIPCONT (1 << 1) 7328 #define SKIPFUNC (1 << 2) 7329 #define SKIPFILE (1 << 3) 7330 #define SKIPEVAL (1 << 4) 7331 static int skipcount; /* number of levels to skip */ 7332 static int funcnest; /* depth of function calls */ 7333 7334 /* forward decl way out to parsing code - dotrap needs it */ 7335 static int evalstring(char *s, int mask); 7336 7337 /* 7338 * Called to execute a trap. Perhaps we should avoid entering new trap 7339 * handlers while we are executing a trap handler. 7340 */ 7341 static int 7342 dotrap(void) 7343 { 7344 char *p; 7345 char *q; 7346 int i; 7347 int savestatus; 7348 int skip = 0; 7349 7350 savestatus = exitstatus; 7351 pendingsig = 0; 7352 xbarrier(); 7353 7354 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 7355 if (!*q) 7356 continue; 7357 *q = '\0'; 7358 7359 p = trap[i + 1]; 7360 if (!p) 7361 continue; 7362 skip = evalstring(p, SKIPEVAL); 7363 exitstatus = savestatus; 7364 if (skip) 7365 break; 7366 } 7367 7368 return skip; 7369 } 7370 7371 /* forward declarations - evaluation is fairly recursive business... */ 7372 static void evalloop(union node *, int); 7373 static void evalfor(union node *, int); 7374 static void evalcase(union node *, int); 7375 static void evalsubshell(union node *, int); 7376 static void expredir(union node *); 7377 static void evalpipe(union node *, int); 7378 static void evalcommand(union node *, int); 7379 static int evalbltin(const struct builtincmd *, int, char **); 7380 static void prehash(union node *); 7381 7382 /* 7383 * Evaluate a parse tree. The value is left in the global variable 7384 * exitstatus. 7385 */ 7386 static void 7387 evaltree(union node *n, int flags) 7388 { 7389 int checkexit = 0; 7390 void (*evalfn)(union node *, int); 7391 unsigned isor; 7745 7392 int status; 7746 int retval; 7747 7748 status = job->ps[job->nprocs - 1].status; 7749 retval = WEXITSTATUS(status); 7750 if (!WIFEXITED(status)) { 7393 if (n == NULL) { 7394 TRACE(("evaltree(NULL) called\n")); 7395 goto out; 7396 } 7397 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 7398 getpid(), n, n->type, flags)); 7399 switch (n->type) { 7400 default: 7401 #if DEBUG 7402 out1fmt("Node type = %d\n", n->type); 7403 fflush(stdout); 7404 break; 7405 #endif 7406 case NNOT: 7407 evaltree(n->nnot.com, EV_TESTED); 7408 status = !exitstatus; 7409 goto setstatus; 7410 case NREDIR: 7411 expredir(n->nredir.redirect); 7412 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 7413 if (!status) { 7414 evaltree(n->nredir.n, flags & EV_TESTED); 7415 status = exitstatus; 7416 } 7417 popredir(0); 7418 goto setstatus; 7419 case NCMD: 7420 evalfn = evalcommand; 7421 checkexit: 7422 if (eflag && !(flags & EV_TESTED)) 7423 checkexit = ~0; 7424 goto calleval; 7425 case NFOR: 7426 evalfn = evalfor; 7427 goto calleval; 7428 case NWHILE: 7429 case NUNTIL: 7430 evalfn = evalloop; 7431 goto calleval; 7432 case NSUBSHELL: 7433 case NBACKGND: 7434 evalfn = evalsubshell; 7435 goto calleval; 7436 case NPIPE: 7437 evalfn = evalpipe; 7438 goto checkexit; 7439 case NCASE: 7440 evalfn = evalcase; 7441 goto calleval; 7442 case NAND: 7443 case NOR: 7444 case NSEMI: 7445 #if NAND + 1 != NOR 7446 #error NAND + 1 != NOR 7447 #endif 7448 #if NOR + 1 != NSEMI 7449 #error NOR + 1 != NSEMI 7450 #endif 7451 isor = n->type - NAND; 7452 evaltree( 7453 n->nbinary.ch1, 7454 (flags | ((isor >> 1) - 1)) & EV_TESTED 7455 ); 7456 if (!exitstatus == isor) 7457 break; 7458 if (!evalskip) { 7459 n = n->nbinary.ch2; 7460 evaln: 7461 evalfn = evaltree; 7462 calleval: 7463 evalfn(n, flags); 7464 break; 7465 } 7466 break; 7467 case NIF: 7468 evaltree(n->nif.test, EV_TESTED); 7469 if (evalskip) 7470 break; 7471 if (exitstatus == 0) { 7472 n = n->nif.ifpart; 7473 goto evaln; 7474 } else if (n->nif.elsepart) { 7475 n = n->nif.elsepart; 7476 goto evaln; 7477 } 7478 goto success; 7479 case NDEFUN: 7480 defun(n->narg.text, n->narg.next); 7481 success: 7482 status = 0; 7483 setstatus: 7484 exitstatus = status; 7485 break; 7486 } 7487 out: 7488 if ((checkexit & exitstatus)) 7489 evalskip |= SKIPEVAL; 7490 else if (pendingsig && dotrap()) 7491 goto exexit; 7492 7493 if (flags & EV_EXIT) { 7494 exexit: 7495 raise_exception(EXEXIT); 7496 } 7497 } 7498 7499 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 7500 static 7501 #endif 7502 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 7503 7504 static int loopnest; /* current loop nesting level */ 7505 7506 static void 7507 evalloop(union node *n, int flags) 7508 { 7509 int status; 7510 7511 loopnest++; 7512 status = 0; 7513 flags &= EV_TESTED; 7514 for (;;) { 7515 int i; 7516 7517 evaltree(n->nbinary.ch1, EV_TESTED); 7518 if (evalskip) { 7519 skipping: 7520 if (evalskip == SKIPCONT && --skipcount <= 0) { 7521 evalskip = 0; 7522 continue; 7523 } 7524 if (evalskip == SKIPBREAK && --skipcount <= 0) 7525 evalskip = 0; 7526 break; 7527 } 7528 i = exitstatus; 7529 if (n->type != NWHILE) 7530 i = !i; 7531 if (i != 0) 7532 break; 7533 evaltree(n->nbinary.ch2, flags); 7534 status = exitstatus; 7535 if (evalskip) 7536 goto skipping; 7537 } 7538 loopnest--; 7539 exitstatus = status; 7540 } 7541 7542 static void 7543 evalfor(union node *n, int flags) 7544 { 7545 struct arglist arglist; 7546 union node *argp; 7547 struct strlist *sp; 7548 struct stackmark smark; 7549 7550 setstackmark(&smark); 7551 arglist.lastp = &arglist.list; 7552 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 7553 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 7554 /* XXX */ 7555 if (evalskip) 7556 goto out; 7557 } 7558 *arglist.lastp = NULL; 7559 7560 exitstatus = 0; 7561 loopnest++; 7562 flags &= EV_TESTED; 7563 for (sp = arglist.list; sp; sp = sp->next) { 7564 setvar(n->nfor.var, sp->text, 0); 7565 evaltree(n->nfor.body, flags); 7566 if (evalskip) { 7567 if (evalskip == SKIPCONT && --skipcount <= 0) { 7568 evalskip = 0; 7569 continue; 7570 } 7571 if (evalskip == SKIPBREAK && --skipcount <= 0) 7572 evalskip = 0; 7573 break; 7574 } 7575 } 7576 loopnest--; 7577 out: 7578 popstackmark(&smark); 7579 } 7580 7581 static void 7582 evalcase(union node *n, int flags) 7583 { 7584 union node *cp; 7585 union node *patp; 7586 struct arglist arglist; 7587 struct stackmark smark; 7588 7589 setstackmark(&smark); 7590 arglist.lastp = &arglist.list; 7591 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 7592 exitstatus = 0; 7593 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 7594 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 7595 if (casematch(patp, arglist.list->text)) { 7596 if (evalskip == 0) { 7597 evaltree(cp->nclist.body, flags); 7598 } 7599 goto out; 7600 } 7601 } 7602 } 7603 out: 7604 popstackmark(&smark); 7605 } 7606 7607 /* 7608 * Kick off a subshell to evaluate a tree. 7609 */ 7610 static void 7611 evalsubshell(union node *n, int flags) 7612 { 7613 struct job *jp; 7614 int backgnd = (n->type == NBACKGND); 7615 int status; 7616 7617 expredir(n->nredir.redirect); 7618 if (!backgnd && flags & EV_EXIT && !trap[0]) 7619 goto nofork; 7620 INT_OFF; 7621 jp = makejob(n, 1); 7622 if (forkshell(jp, n, backgnd) == 0) { 7623 INT_ON; 7624 flags |= EV_EXIT; 7625 if (backgnd) 7626 flags &=~ EV_TESTED; 7627 nofork: 7628 redirect(n->nredir.redirect, 0); 7629 evaltreenr(n->nredir.n, flags); 7630 /* never returns */ 7631 } 7632 status = 0; 7633 if (! backgnd) 7634 status = waitforjob(jp); 7635 exitstatus = status; 7636 INT_ON; 7637 } 7638 7639 /* 7640 * Compute the names of the files in a redirection list. 7641 */ 7642 static void fixredir(union node *, const char *, int); 7643 static void 7644 expredir(union node *n) 7645 { 7646 union node *redir; 7647 7648 for (redir = n; redir; redir = redir->nfile.next) { 7649 struct arglist fn; 7650 7651 memset(&fn, 0, sizeof(fn)); 7652 fn.lastp = &fn.list; 7653 switch (redir->type) { 7654 case NFROMTO: 7655 case NFROM: 7656 case NTO: 7657 case NCLOBBER: 7658 case NAPPEND: 7659 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 7660 redir->nfile.expfname = fn.list->text; 7661 break; 7662 case NFROMFD: 7663 case NTOFD: 7664 if (redir->ndup.vname) { 7665 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 7666 if (fn.list == NULL) 7667 ash_msg_and_raise_error("redir error"); 7668 fixredir(redir, fn.list->text, 1); 7669 } 7670 break; 7671 } 7672 } 7673 } 7674 7675 /* 7676 * Evaluate a pipeline. All the processes in the pipeline are children 7677 * of the process creating the pipeline. (This differs from some versions 7678 * of the shell, which make the last process in a pipeline the parent 7679 * of all the rest.) 7680 */ 7681 static void 7682 evalpipe(union node *n, int flags) 7683 { 7684 struct job *jp; 7685 struct nodelist *lp; 7686 int pipelen; 7687 int prevfd; 7688 int pip[2]; 7689 7690 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 7691 pipelen = 0; 7692 for (lp = n->npipe.cmdlist; lp; lp = lp->next) 7693 pipelen++; 7694 flags |= EV_EXIT; 7695 INT_OFF; 7696 jp = makejob(n, pipelen); 7697 prevfd = -1; 7698 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 7699 prehash(lp->n); 7700 pip[1] = -1; 7701 if (lp->next) { 7702 if (pipe(pip) < 0) { 7703 close(prevfd); 7704 ash_msg_and_raise_error("pipe call failed"); 7705 } 7706 } 7707 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 7708 INT_ON; 7709 if (pip[1] >= 0) { 7710 close(pip[0]); 7711 } 7712 if (prevfd > 0) { 7713 dup2(prevfd, 0); 7714 close(prevfd); 7715 } 7716 if (pip[1] > 1) { 7717 dup2(pip[1], 1); 7718 close(pip[1]); 7719 } 7720 evaltreenr(lp->n, flags); 7721 /* never returns */ 7722 } 7723 if (prevfd >= 0) 7724 close(prevfd); 7725 prevfd = pip[0]; 7726 close(pip[1]); 7727 } 7728 if (n->npipe.backgnd == 0) { 7729 exitstatus = waitforjob(jp); 7730 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 7731 } 7732 INT_ON; 7733 } 7734 7735 /* 7736 * Controls whether the shell is interactive or not. 7737 */ 7738 static void 7739 setinteractive(int on) 7740 { 7741 static int is_interactive; 7742 7743 if (++on == is_interactive) 7744 return; 7745 is_interactive = on; 7746 setsignal(SIGINT); 7747 setsignal(SIGQUIT); 7748 setsignal(SIGTERM); 7749 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 7750 if (is_interactive > 1) { 7751 /* Looks like they want an interactive shell */ 7752 static smallint did_banner; 7753 7754 if (!did_banner) { 7755 out1fmt( 7756 "\n\n" 7757 "%s built-in shell (ash)\n" 7758 "Enter 'help' for a list of built-in commands." 7759 "\n\n", 7760 bb_banner); 7761 did_banner = 1; 7762 } 7763 } 7764 #endif 7765 } 7766 7767 #if ENABLE_FEATURE_EDITING_VI 7768 #define setvimode(on) do { \ 7769 if (on) line_input_state->flags |= VI_MODE; \ 7770 else line_input_state->flags &= ~VI_MODE; \ 7771 } while (0) 7772 #else 7773 #define setvimode(on) viflag = 0 /* forcibly keep the option off */ 7774 #endif 7775 7776 static void 7777 optschanged(void) 7778 { 7779 #if DEBUG 7780 opentrace(); 7781 #endif 7782 setinteractive(iflag); 7783 setjobctl(mflag); 7784 setvimode(viflag); 7785 } 7786 7787 static struct localvar *localvars; 7788 7789 /* 7790 * Called after a function returns. 7791 * Interrupts must be off. 7792 */ 7793 static void 7794 poplocalvars(void) 7795 { 7796 struct localvar *lvp; 7797 struct var *vp; 7798 7799 while ((lvp = localvars) != NULL) { 7800 localvars = lvp->next; 7801 vp = lvp->vp; 7802 TRACE(("poplocalvar %s", vp ? vp->text : "-")); 7803 if (vp == NULL) { /* $- saved */ 7804 memcpy(optlist, lvp->text, sizeof(optlist)); 7805 free((char*)lvp->text); 7806 optschanged(); 7807 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 7808 unsetvar(vp->text); 7809 } else { 7810 if (vp->func) 7811 (*vp->func)(strchrnul(lvp->text, '=') + 1); 7812 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 7813 free((char*)vp->text); 7814 vp->flags = lvp->flags; 7815 vp->text = lvp->text; 7816 } 7817 free(lvp); 7818 } 7819 } 7820 7821 static int 7822 evalfun(struct funcnode *func, int argc, char **argv, int flags) 7823 { 7824 volatile struct shparam saveparam; 7825 struct localvar *volatile savelocalvars; 7826 struct jmploc *volatile savehandler; 7827 struct jmploc jmploc; 7828 int e; 7829 7830 saveparam = shellparam; 7831 savelocalvars = localvars; 7832 e = setjmp(jmploc.loc); 7833 if (e) { 7834 goto funcdone; 7835 } 7836 INT_OFF; 7837 savehandler = exception_handler; 7838 exception_handler = &jmploc; 7839 localvars = NULL; 7840 shellparam.malloc = 0; 7841 func->count++; 7842 funcnest++; 7843 INT_ON; 7844 shellparam.nparam = argc - 1; 7845 shellparam.p = argv + 1; 7846 #if ENABLE_ASH_GETOPTS 7847 shellparam.optind = 1; 7848 shellparam.optoff = -1; 7849 #endif 7850 evaltree(&func->n, flags & EV_TESTED); 7851 funcdone: 7852 INT_OFF; 7853 funcnest--; 7854 freefunc(func); 7855 poplocalvars(); 7856 localvars = savelocalvars; 7857 freeparam(&shellparam); 7858 shellparam = saveparam; 7859 exception_handler = savehandler; 7860 INT_ON; 7861 evalskip &= ~SKIPFUNC; 7862 return e; 7863 } 7864 7865 #if ENABLE_ASH_CMDCMD 7866 static char ** 7867 parse_command_args(char **argv, const char **path) 7868 { 7869 char *cp, c; 7870 7871 for (;;) { 7872 cp = *++argv; 7873 if (!cp) 7874 return 0; 7875 if (*cp++ != '-') 7876 break; 7877 c = *cp++; 7878 if (!c) 7879 break; 7880 if (c == '-' && !*cp) { 7881 argv++; 7882 break; 7883 } 7884 do { 7885 switch (c) { 7886 case 'p': 7887 *path = bb_default_path; 7888 break; 7889 default: 7890 /* run 'typecmd' for other options */ 7891 return 0; 7892 } 7893 c = *cp++; 7894 } while (c); 7895 } 7896 return argv; 7897 } 7898 #endif 7899 7900 /* 7901 * Make a variable a local variable. When a variable is made local, it's 7902 * value and flags are saved in a localvar structure. The saved values 7903 * will be restored when the shell function returns. We handle the name 7904 * "-" as a special case. 7905 */ 7906 static void 7907 mklocal(char *name) 7908 { 7909 struct localvar *lvp; 7910 struct var **vpp; 7911 struct var *vp; 7912 7913 INT_OFF; 7914 lvp = ckmalloc(sizeof(struct localvar)); 7915 if (LONE_DASH(name)) { 7916 char *p; 7917 p = ckmalloc(sizeof(optlist)); 7918 lvp->text = memcpy(p, optlist, sizeof(optlist)); 7919 vp = NULL; 7920 } else { 7921 char *eq; 7922 7923 vpp = hashvar(name); 7924 vp = *findvar(vpp, name); 7925 eq = strchr(name, '='); 7926 if (vp == NULL) { 7927 if (eq) 7928 setvareq(name, VSTRFIXED); 7929 else 7930 setvar(name, NULL, VSTRFIXED); 7931 vp = *vpp; /* the new variable */ 7932 lvp->flags = VUNSET; 7933 } else { 7934 lvp->text = vp->text; 7935 lvp->flags = vp->flags; 7936 vp->flags |= VSTRFIXED|VTEXTFIXED; 7937 if (eq) 7938 setvareq(name, 0); 7939 } 7940 } 7941 lvp->vp = vp; 7942 lvp->next = localvars; 7943 localvars = lvp; 7944 INT_ON; 7945 } 7946 7947 /* 7948 * The "local" command. 7949 */ 7950 static int 7951 localcmd(int argc, char **argv) 7952 { 7953 char *name; 7954 7955 argv = argptr; 7956 while ((name = *argv++) != NULL) { 7957 mklocal(name); 7958 } 7959 return 0; 7960 } 7961 7962 static int 7963 falsecmd(int argc, char **argv) 7964 { 7965 return 1; 7966 } 7967 7968 static int 7969 truecmd(int argc, char **argv) 7970 { 7971 return 0; 7972 } 7973 7974 static int 7975 execcmd(int argc, char **argv) 7976 { 7977 if (argc > 1) { 7978 iflag = 0; /* exit on error */ 7979 mflag = 0; 7980 optschanged(); 7981 shellexec(argv + 1, pathval(), 0); 7982 } 7983 return 0; 7984 } 7985 7986 /* 7987 * The return command. 7988 */ 7989 static int 7990 returncmd(int argc, char **argv) 7991 { 7992 /* 7993 * If called outside a function, do what ksh does; 7994 * skip the rest of the file. 7995 */ 7996 evalskip = funcnest ? SKIPFUNC : SKIPFILE; 7997 return argv[1] ? number(argv[1]) : exitstatus; 7998 } 7999 8000 /* Forward declarations for builtintab[] */ 8001 static int breakcmd(int, char **); 8002 static int dotcmd(int, char **); 8003 static int evalcmd(int, char **); 8004 #if ENABLE_ASH_BUILTIN_ECHO 8005 static int echocmd(int, char **); 8006 #endif 8007 #if ENABLE_ASH_BUILTIN_TEST 8008 static int testcmd(int, char **); 8009 #endif 8010 static int exitcmd(int, char **); 8011 static int exportcmd(int, char **); 8012 #if ENABLE_ASH_GETOPTS 8013 static int getoptscmd(int, char **); 8014 #endif 8015 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8016 static int helpcmd(int argc, char **argv); 8017 #endif 8018 #if ENABLE_ASH_MATH_SUPPORT 8019 static int letcmd(int, char **); 8020 #endif 8021 static int readcmd(int, char **); 8022 static int setcmd(int, char **); 8023 static int shiftcmd(int, char **); 8024 static int timescmd(int, char **); 8025 static int trapcmd(int, char **); 8026 static int umaskcmd(int, char **); 8027 static int unsetcmd(int, char **); 8028 static int ulimitcmd(int, char **); 8029 8030 #define BUILTIN_NOSPEC "0" 8031 #define BUILTIN_SPECIAL "1" 8032 #define BUILTIN_REGULAR "2" 8033 #define BUILTIN_SPEC_REG "3" 8034 #define BUILTIN_ASSIGN "4" 8035 #define BUILTIN_SPEC_ASSG "5" 8036 #define BUILTIN_REG_ASSG "6" 8037 #define BUILTIN_SPEC_REG_ASSG "7" 8038 8039 /* make sure to keep these in proper order since it is searched via bsearch() */ 8040 static const struct builtincmd builtintab[] = { 8041 { BUILTIN_SPEC_REG ".", dotcmd }, 8042 { BUILTIN_SPEC_REG ":", truecmd }, 8043 #if ENABLE_ASH_BUILTIN_TEST 8044 { BUILTIN_REGULAR "[", testcmd }, 8045 { BUILTIN_REGULAR "[[", testcmd }, 8046 #endif 8047 #if ENABLE_ASH_ALIAS 8048 { BUILTIN_REG_ASSG "alias", aliascmd }, 8049 #endif 7751 8050 #if JOBS 7752 retval = WSTOPSIG(status); 7753 if (!WIFSTOPPED(status)) 7754 #endif 7755 { 7756 /* XXX: limits number of signals */ 7757 retval = WTERMSIG(status); 8051 { BUILTIN_REGULAR "bg", fg_bgcmd }, 8052 #endif 8053 { BUILTIN_SPEC_REG "break", breakcmd }, 8054 { BUILTIN_REGULAR "cd", cdcmd }, 8055 { BUILTIN_NOSPEC "chdir", cdcmd }, 8056 #if ENABLE_ASH_CMDCMD 8057 { BUILTIN_REGULAR "command", commandcmd }, 8058 #endif 8059 { BUILTIN_SPEC_REG "continue", breakcmd }, 8060 #if ENABLE_ASH_BUILTIN_ECHO 8061 { BUILTIN_REGULAR "echo", echocmd }, 8062 #endif 8063 { BUILTIN_SPEC_REG "eval", evalcmd }, 8064 { BUILTIN_SPEC_REG "exec", execcmd }, 8065 { BUILTIN_SPEC_REG "exit", exitcmd }, 8066 { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, 8067 { BUILTIN_REGULAR "false", falsecmd }, 7758 8068 #if JOBS 7759 if (retval == SIGINT) 7760 job->sigint = 1; 7761 #endif 7762 } 7763 retval += 128; 7764 } 7765 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", 7766 jobno(job), job->nprocs, status, retval)); 7767 return retval; 7768 } 7769 7770 #ifdef CONFIG_ASH_MAIL 7771 /* mail.c */ 7772 7773 /* 7774 * Routines to check for mail. (Perhaps make part of main.c?) 7775 */ 8069 { BUILTIN_REGULAR "fg", fg_bgcmd }, 8070 #endif 8071 #if ENABLE_ASH_GETOPTS 8072 { BUILTIN_REGULAR "getopts", getoptscmd }, 8073 #endif 8074 { BUILTIN_NOSPEC "hash", hashcmd }, 8075 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8076 { BUILTIN_NOSPEC "help", helpcmd }, 8077 #endif 8078 #if JOBS 8079 { BUILTIN_REGULAR "jobs", jobscmd }, 8080 { BUILTIN_REGULAR "kill", killcmd }, 8081 #endif 8082 #if ENABLE_ASH_MATH_SUPPORT 8083 { BUILTIN_NOSPEC "let", letcmd }, 8084 #endif 8085 { BUILTIN_ASSIGN "local", localcmd }, 8086 { BUILTIN_NOSPEC "pwd", pwdcmd }, 8087 { BUILTIN_REGULAR "read", readcmd }, 8088 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 8089 { BUILTIN_SPEC_REG "return", returncmd }, 8090 { BUILTIN_SPEC_REG "set", setcmd }, 8091 { BUILTIN_SPEC_REG "shift", shiftcmd }, 8092 { BUILTIN_SPEC_REG "source", dotcmd }, 8093 #if ENABLE_ASH_BUILTIN_TEST 8094 { BUILTIN_REGULAR "test", testcmd }, 8095 #endif 8096 { BUILTIN_SPEC_REG "times", timescmd }, 8097 { BUILTIN_SPEC_REG "trap", trapcmd }, 8098 { BUILTIN_REGULAR "true", truecmd }, 8099 { BUILTIN_NOSPEC "type", typecmd }, 8100 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 8101 { BUILTIN_REGULAR "umask", umaskcmd }, 8102 #if ENABLE_ASH_ALIAS 8103 { BUILTIN_REGULAR "unalias", unaliascmd }, 8104 #endif 8105 { BUILTIN_SPEC_REG "unset", unsetcmd }, 8106 { BUILTIN_REGULAR "wait", waitcmd }, 8107 }; 8108 8109 8110 #define COMMANDCMD (builtintab + 5 + \ 8111 2 * ENABLE_ASH_BUILTIN_TEST + \ 8112 ENABLE_ASH_ALIAS + \ 8113 ENABLE_ASH_JOB_CONTROL) 8114 #define EXECCMD (builtintab + 7 + \ 8115 2 * ENABLE_ASH_BUILTIN_TEST + \ 8116 ENABLE_ASH_ALIAS + \ 8117 ENABLE_ASH_JOB_CONTROL + \ 8118 ENABLE_ASH_CMDCMD + \ 8119 ENABLE_ASH_BUILTIN_ECHO) 8120 8121 /* 8122 * Search the table of builtin commands. 8123 */ 8124 static struct builtincmd * 8125 find_builtin(const char *name) 8126 { 8127 struct builtincmd *bp; 8128 8129 bp = bsearch( 8130 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]), 8131 pstrcmp 8132 ); 8133 return bp; 8134 } 8135 8136 /* 8137 * Execute a simple command. 8138 */ 8139 static int back_exitstatus; /* exit status of backquoted command */ 8140 static int 8141 isassignment(const char *p) 8142 { 8143 const char *q = endofname(p); 8144 if (p == q) 8145 return 0; 8146 return *q == '='; 8147 } 8148 static int 8149 bltincmd(int argc, char **argv) 8150 { 8151 /* Preserve exitstatus of a previous possible redirection 8152 * as POSIX mandates */ 8153 return back_exitstatus; 8154 } 8155 static void 8156 evalcommand(union node *cmd, int flags) 8157 { 8158 static const struct builtincmd bltin = { 8159 "\0\0", bltincmd 8160 }; 8161 struct stackmark smark; 8162 union node *argp; 8163 struct arglist arglist; 8164 struct arglist varlist; 8165 char **argv; 8166 int argc; 8167 const struct strlist *sp; 8168 struct cmdentry cmdentry; 8169 struct job *jp; 8170 char *lastarg; 8171 const char *path; 8172 int spclbltin; 8173 int cmd_is_exec; 8174 int status; 8175 char **nargv; 8176 struct builtincmd *bcmd; 8177 int pseudovarflag = 0; 8178 8179 /* First expand the arguments. */ 8180 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 8181 setstackmark(&smark); 8182 back_exitstatus = 0; 8183 8184 cmdentry.cmdtype = CMDBUILTIN; 8185 cmdentry.u.cmd = &bltin; 8186 varlist.lastp = &varlist.list; 8187 *varlist.lastp = NULL; 8188 arglist.lastp = &arglist.list; 8189 *arglist.lastp = NULL; 8190 8191 argc = 0; 8192 if (cmd->ncmd.args) { 8193 bcmd = find_builtin(cmd->ncmd.args->narg.text); 8194 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 8195 } 8196 8197 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 8198 struct strlist **spp; 8199 8200 spp = arglist.lastp; 8201 if (pseudovarflag && isassignment(argp->narg.text)) 8202 expandarg(argp, &arglist, EXP_VARTILDE); 8203 else 8204 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 8205 8206 for (sp = *spp; sp; sp = sp->next) 8207 argc++; 8208 } 8209 8210 argv = nargv = stalloc(sizeof(char *) * (argc + 1)); 8211 for (sp = arglist.list; sp; sp = sp->next) { 8212 TRACE(("evalcommand arg: %s\n", sp->text)); 8213 *nargv++ = sp->text; 8214 } 8215 *nargv = NULL; 8216 8217 lastarg = NULL; 8218 if (iflag && funcnest == 0 && argc > 0) 8219 lastarg = nargv[-1]; 8220 8221 preverrout_fd = 2; 8222 expredir(cmd->ncmd.redirect); 8223 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 8224 8225 path = vpath.text; 8226 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 8227 struct strlist **spp; 8228 char *p; 8229 8230 spp = varlist.lastp; 8231 expandarg(argp, &varlist, EXP_VARTILDE); 8232 8233 /* 8234 * Modify the command lookup path, if a PATH= assignment 8235 * is present 8236 */ 8237 p = (*spp)->text; 8238 if (varequal(p, path)) 8239 path = p; 8240 } 8241 8242 /* Print the command if xflag is set. */ 8243 if (xflag) { 8244 int n; 8245 const char *p = " %s"; 8246 8247 p++; 8248 dprintf(preverrout_fd, p, expandstr(ps4val())); 8249 8250 sp = varlist.list; 8251 for (n = 0; n < 2; n++) { 8252 while (sp) { 8253 dprintf(preverrout_fd, p, sp->text); 8254 sp = sp->next; 8255 if (*p == '%') { 8256 p--; 8257 } 8258 } 8259 sp = arglist.list; 8260 } 8261 full_write(preverrout_fd, "\n", 1); 8262 } 8263 8264 cmd_is_exec = 0; 8265 spclbltin = -1; 8266 8267 /* Now locate the command. */ 8268 if (argc) { 8269 const char *oldpath; 8270 int cmd_flag = DO_ERR; 8271 8272 path += 5; 8273 oldpath = path; 8274 for (;;) { 8275 find_command(argv[0], &cmdentry, cmd_flag, path); 8276 if (cmdentry.cmdtype == CMDUNKNOWN) { 8277 status = 127; 8278 flush_stderr(); 8279 goto bail; 8280 } 8281 8282 /* implement bltin and command here */ 8283 if (cmdentry.cmdtype != CMDBUILTIN) 8284 break; 8285 if (spclbltin < 0) 8286 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 8287 if (cmdentry.u.cmd == EXECCMD) 8288 cmd_is_exec++; 8289 #if ENABLE_ASH_CMDCMD 8290 if (cmdentry.u.cmd == COMMANDCMD) { 8291 path = oldpath; 8292 nargv = parse_command_args(argv, &path); 8293 if (!nargv) 8294 break; 8295 argc -= nargv - argv; 8296 argv = nargv; 8297 cmd_flag |= DO_NOFUNC; 8298 } else 8299 #endif 8300 break; 8301 } 8302 } 8303 8304 if (status) { 8305 /* We have a redirection error. */ 8306 if (spclbltin > 0) 8307 raise_exception(EXERROR); 8308 bail: 8309 exitstatus = status; 8310 goto out; 8311 } 8312 8313 /* Execute the command. */ 8314 switch (cmdentry.cmdtype) { 8315 default: 8316 /* Fork off a child process if necessary. */ 8317 if (!(flags & EV_EXIT) || trap[0]) { 8318 INT_OFF; 8319 jp = makejob(cmd, 1); 8320 if (forkshell(jp, cmd, FORK_FG) != 0) { 8321 exitstatus = waitforjob(jp); 8322 INT_ON; 8323 break; 8324 } 8325 FORCE_INT_ON; 8326 } 8327 listsetvar(varlist.list, VEXPORT|VSTACK); 8328 shellexec(argv, path, cmdentry.u.index); 8329 /* NOTREACHED */ 8330 8331 case CMDBUILTIN: 8332 cmdenviron = varlist.list; 8333 if (cmdenviron) { 8334 struct strlist *list = cmdenviron; 8335 int i = VNOSET; 8336 if (spclbltin > 0 || argc == 0) { 8337 i = 0; 8338 if (cmd_is_exec && argc > 1) 8339 i = VEXPORT; 8340 } 8341 listsetvar(list, i); 8342 } 8343 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 8344 int exit_status; 8345 int i, j; 8346 8347 i = exception; 8348 if (i == EXEXIT) 8349 goto raise; 8350 8351 exit_status = 2; 8352 j = 0; 8353 if (i == EXINT) 8354 j = SIGINT; 8355 if (i == EXSIG) 8356 j = pendingsig; 8357 if (j) 8358 exit_status = j + 128; 8359 exitstatus = exit_status; 8360 8361 if (i == EXINT || spclbltin > 0) { 8362 raise: 8363 longjmp(exception_handler->loc, 1); 8364 } 8365 FORCE_INT_ON; 8366 } 8367 break; 8368 8369 case CMDFUNCTION: 8370 listsetvar(varlist.list, 0); 8371 if (evalfun(cmdentry.u.func, argc, argv, flags)) 8372 goto raise; 8373 break; 8374 } 8375 8376 out: 8377 popredir(cmd_is_exec); 8378 if (lastarg) 8379 /* dsl: I think this is intended to be used to support 8380 * '_' in 'vi' command mode during line editing... 8381 * However I implemented that within libedit itself. 8382 */ 8383 setvar("_", lastarg, 0); 8384 popstackmark(&smark); 8385 } 8386 8387 static int 8388 evalbltin(const struct builtincmd *cmd, int argc, char **argv) 8389 { 8390 char *volatile savecmdname; 8391 struct jmploc *volatile savehandler; 8392 struct jmploc jmploc; 8393 int i; 8394 8395 savecmdname = commandname; 8396 i = setjmp(jmploc.loc); 8397 if (i) 8398 goto cmddone; 8399 savehandler = exception_handler; 8400 exception_handler = &jmploc; 8401 commandname = argv[0]; 8402 argptr = argv + 1; 8403 optptr = NULL; /* initialize nextopt */ 8404 exitstatus = (*cmd->builtin)(argc, argv); 8405 flush_stdout_stderr(); 8406 cmddone: 8407 exitstatus |= ferror(stdout); 8408 clearerr(stdout); 8409 commandname = savecmdname; 8410 exsig = 0; 8411 exception_handler = savehandler; 8412 8413 return i; 8414 } 8415 8416 static int 8417 goodname(const char *p) 8418 { 8419 return !*endofname(p); 8420 } 8421 8422 8423 /* 8424 * Search for a command. This is called before we fork so that the 8425 * location of the command will be available in the parent as well as 8426 * the child. The check for "goodname" is an overly conservative 8427 * check that the name will not be subject to expansion. 8428 */ 8429 static void 8430 prehash(union node *n) 8431 { 8432 struct cmdentry entry; 8433 8434 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text)) 8435 find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); 8436 } 8437 8438 8439 /* ============ Builtin commands 8440 * 8441 * Builtin commands whose functions are closely tied to evaluation 8442 * are implemented here. 8443 */ 8444 8445 /* 8446 * Handle break and continue commands. Break, continue, and return are 8447 * all handled by setting the evalskip flag. The evaluation routines 8448 * above all check this flag, and if it is set they start skipping 8449 * commands rather than executing them. The variable skipcount is 8450 * the number of loops to break/continue, or the number of function 8451 * levels to return. (The latter is always 1.) It should probably 8452 * be an error to break out of more loops than exist, but it isn't 8453 * in the standard shell so we don't make it one here. 8454 */ 8455 static int 8456 breakcmd(int argc, char **argv) 8457 { 8458 int n = argc > 1 ? number(argv[1]) : 1; 8459 8460 if (n <= 0) 8461 ash_msg_and_raise_error(illnum, argv[1]); 8462 if (n > loopnest) 8463 n = loopnest; 8464 if (n > 0) { 8465 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK; 8466 skipcount = n; 8467 } 8468 return 0; 8469 } 8470 8471 8472 /* ============ input.c 8473 * 8474 * This implements the input routines used by the parser. 8475 */ 8476 8477 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 8478 8479 enum { 8480 INPUT_PUSH_FILE = 1, 8481 INPUT_NOFILE_OK = 2, 8482 }; 8483 8484 /* 8485 * NEOF is returned by parsecmd when it encounters an end of file. It 8486 * must be distinct from NULL, so we use the address of a variable that 8487 * happens to be handy. 8488 */ 8489 static int plinno = 1; /* input line number */ 8490 /* number of characters left in input buffer */ 8491 static int parsenleft; /* copy of parsefile->nleft */ 8492 static int parselleft; /* copy of parsefile->lleft */ 8493 /* next character in input buffer */ 8494 static char *parsenextc; /* copy of parsefile->nextc */ 8495 8496 static int checkkwd; 8497 /* values of checkkwd variable */ 8498 #define CHKALIAS 0x1 8499 #define CHKKWD 0x2 8500 #define CHKNL 0x4 8501 8502 static void 8503 popstring(void) 8504 { 8505 struct strpush *sp = parsefile->strpush; 8506 8507 INT_OFF; 8508 #if ENABLE_ASH_ALIAS 8509 if (sp->ap) { 8510 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 8511 checkkwd |= CHKALIAS; 8512 } 8513 if (sp->string != sp->ap->val) { 8514 free(sp->string); 8515 } 8516 sp->ap->flag &= ~ALIASINUSE; 8517 if (sp->ap->flag & ALIASDEAD) { 8518 unalias(sp->ap->name); 8519 } 8520 } 8521 #endif 8522 parsenextc = sp->prevstring; 8523 parsenleft = sp->prevnleft; 8524 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 8525 parsefile->strpush = sp->prev; 8526 if (sp != &(parsefile->basestrpush)) 8527 free(sp); 8528 INT_ON; 8529 } 8530 8531 static int 8532 preadfd(void) 8533 { 8534 int nr; 8535 char *buf = parsefile->buf; 8536 parsenextc = buf; 8537 8538 retry: 8539 #if ENABLE_FEATURE_EDITING 8540 if (!iflag || parsefile->fd) 8541 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8542 else { 8543 #if ENABLE_FEATURE_TAB_COMPLETION 8544 line_input_state->path_lookup = pathval(); 8545 #endif 8546 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state); 8547 if (nr == 0) { 8548 /* Ctrl+C pressed */ 8549 if (trap[SIGINT]) { 8550 buf[0] = '\n'; 8551 buf[1] = '\0'; 8552 raise(SIGINT); 8553 return 1; 8554 } 8555 goto retry; 8556 } 8557 if (nr < 0 && errno == 0) { 8558 /* Ctrl+D presend */ 8559 nr = 0; 8560 } 8561 } 8562 #else 8563 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8564 #endif 8565 8566 if (nr < 0) { 8567 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 8568 int flags = fcntl(0, F_GETFL); 8569 if (flags >= 0 && flags & O_NONBLOCK) { 8570 flags &=~ O_NONBLOCK; 8571 if (fcntl(0, F_SETFL, flags) >= 0) { 8572 out2str("sh: turning off NDELAY mode\n"); 8573 goto retry; 8574 } 8575 } 8576 } 8577 } 8578 return nr; 8579 } 8580 8581 /* 8582 * Refill the input buffer and return the next input character: 8583 * 8584 * 1) If a string was pushed back on the input, pop it; 8585 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 8586 * from a string so we can't refill the buffer, return EOF. 8587 * 3) If the is more stuff in this buffer, use it else call read to fill it. 8588 * 4) Process input up to the next newline, deleting nul characters. 8589 */ 8590 static int 8591 preadbuffer(void) 8592 { 8593 char *q; 8594 int more; 8595 char savec; 8596 8597 while (parsefile->strpush) { 8598 #if ENABLE_ASH_ALIAS 8599 if (parsenleft == -1 && parsefile->strpush->ap && 8600 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 8601 return PEOA; 8602 } 8603 #endif 8604 popstring(); 8605 if (--parsenleft >= 0) 8606 return signed_char2int(*parsenextc++); 8607 } 8608 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 8609 return PEOF; 8610 flush_stdout_stderr(); 8611 8612 more = parselleft; 8613 if (more <= 0) { 8614 again: 8615 more = preadfd(); 8616 if (more <= 0) { 8617 parselleft = parsenleft = EOF_NLEFT; 8618 return PEOF; 8619 } 8620 } 8621 8622 q = parsenextc; 8623 8624 /* delete nul characters */ 8625 for (;;) { 8626 int c; 8627 8628 more--; 8629 c = *q; 8630 8631 if (!c) 8632 memmove(q, q + 1, more); 8633 else { 8634 q++; 8635 if (c == '\n') { 8636 parsenleft = q - parsenextc - 1; 8637 break; 8638 } 8639 } 8640 8641 if (more <= 0) { 8642 parsenleft = q - parsenextc - 1; 8643 if (parsenleft < 0) 8644 goto again; 8645 break; 8646 } 8647 } 8648 parselleft = more; 8649 8650 savec = *q; 8651 *q = '\0'; 8652 8653 if (vflag) { 8654 out2str(parsenextc); 8655 } 8656 8657 *q = savec; 8658 8659 return signed_char2int(*parsenextc++); 8660 } 8661 8662 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer()) 8663 static int 8664 pgetc(void) 8665 { 8666 return pgetc_as_macro(); 8667 } 8668 8669 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 8670 #define pgetc_macro() pgetc() 8671 #else 8672 #define pgetc_macro() pgetc_as_macro() 8673 #endif 8674 8675 /* 8676 * Same as pgetc(), but ignores PEOA. 8677 */ 8678 #if ENABLE_ASH_ALIAS 8679 static int 8680 pgetc2(void) 8681 { 8682 int c; 8683 8684 do { 8685 c = pgetc_macro(); 8686 } while (c == PEOA); 8687 return c; 8688 } 8689 #else 8690 static int 8691 pgetc2(void) 8692 { 8693 return pgetc_macro(); 8694 } 8695 #endif 8696 8697 /* 8698 * Read a line from the script. 8699 */ 8700 static char * 8701 pfgets(char *line, int len) 8702 { 8703 char *p = line; 8704 int nleft = len; 8705 int c; 8706 8707 while (--nleft > 0) { 8708 c = pgetc2(); 8709 if (c == PEOF) { 8710 if (p == line) 8711 return NULL; 8712 break; 8713 } 8714 *p++ = c; 8715 if (c == '\n') 8716 break; 8717 } 8718 *p = '\0'; 8719 return line; 8720 } 8721 8722 /* 8723 * Undo the last call to pgetc. Only one character may be pushed back. 8724 * PEOF may be pushed back. 8725 */ 8726 static void 8727 pungetc(void) 8728 { 8729 parsenleft++; 8730 parsenextc--; 8731 } 8732 8733 /* 8734 * Push a string back onto the input at this current parsefile level. 8735 * We handle aliases this way. 8736 */ 8737 static void 8738 pushstring(char *s, void *ap) 8739 { 8740 struct strpush *sp; 8741 size_t len; 8742 8743 len = strlen(s); 8744 INT_OFF; 8745 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 8746 if (parsefile->strpush) { 8747 sp = ckmalloc(sizeof(struct strpush)); 8748 sp->prev = parsefile->strpush; 8749 parsefile->strpush = sp; 8750 } else 8751 sp = parsefile->strpush = &(parsefile->basestrpush); 8752 sp->prevstring = parsenextc; 8753 sp->prevnleft = parsenleft; 8754 #if ENABLE_ASH_ALIAS 8755 sp->ap = (struct alias *)ap; 8756 if (ap) { 8757 ((struct alias *)ap)->flag |= ALIASINUSE; 8758 sp->string = s; 8759 } 8760 #endif 8761 parsenextc = s; 8762 parsenleft = len; 8763 INT_ON; 8764 } 8765 8766 /* 8767 * To handle the "." command, a stack of input files is used. Pushfile 8768 * adds a new entry to the stack and popfile restores the previous level. 8769 */ 8770 static void 8771 pushfile(void) 8772 { 8773 struct parsefile *pf; 8774 8775 parsefile->nleft = parsenleft; 8776 parsefile->lleft = parselleft; 8777 parsefile->nextc = parsenextc; 8778 parsefile->linno = plinno; 8779 pf = ckmalloc(sizeof(*pf)); 8780 pf->prev = parsefile; 8781 pf->fd = -1; 8782 pf->strpush = NULL; 8783 pf->basestrpush.prev = NULL; 8784 parsefile = pf; 8785 } 8786 8787 static void 8788 popfile(void) 8789 { 8790 struct parsefile *pf = parsefile; 8791 8792 INT_OFF; 8793 if (pf->fd >= 0) 8794 close(pf->fd); 8795 if (pf->buf) 8796 free(pf->buf); 8797 while (pf->strpush) 8798 popstring(); 8799 parsefile = pf->prev; 8800 free(pf); 8801 parsenleft = parsefile->nleft; 8802 parselleft = parsefile->lleft; 8803 parsenextc = parsefile->nextc; 8804 plinno = parsefile->linno; 8805 INT_ON; 8806 } 8807 8808 /* 8809 * Return to top level. 8810 */ 8811 static void 8812 popallfiles(void) 8813 { 8814 while (parsefile != &basepf) 8815 popfile(); 8816 } 8817 8818 /* 8819 * Close the file(s) that the shell is reading commands from. Called 8820 * after a fork is done. 8821 */ 8822 static void 8823 closescript(void) 8824 { 8825 popallfiles(); 8826 if (parsefile->fd > 0) { 8827 close(parsefile->fd); 8828 parsefile->fd = 0; 8829 } 8830 } 8831 8832 /* 8833 * Like setinputfile, but takes an open file descriptor. Call this with 8834 * interrupts off. 8835 */ 8836 static void 8837 setinputfd(int fd, int push) 8838 { 8839 fcntl(fd, F_SETFD, FD_CLOEXEC); 8840 if (push) { 8841 pushfile(); 8842 parsefile->buf = 0; 8843 } 8844 parsefile->fd = fd; 8845 if (parsefile->buf == NULL) 8846 parsefile->buf = ckmalloc(IBUFSIZ); 8847 parselleft = parsenleft = 0; 8848 plinno = 1; 8849 } 8850 8851 /* 8852 * Set the input to take input from a file. If push is set, push the 8853 * old input onto the stack first. 8854 */ 8855 static int 8856 setinputfile(const char *fname, int flags) 8857 { 8858 int fd; 8859 int fd2; 8860 8861 INT_OFF; 8862 fd = open(fname, O_RDONLY); 8863 if (fd < 0) { 8864 if (flags & INPUT_NOFILE_OK) 8865 goto out; 8866 ash_msg_and_raise_error("can't open %s", fname); 8867 } 8868 if (fd < 10) { 8869 fd2 = copyfd(fd, 10); 8870 close(fd); 8871 if (fd2 < 0) 8872 ash_msg_and_raise_error("out of file descriptors"); 8873 fd = fd2; 8874 } 8875 setinputfd(fd, flags & INPUT_PUSH_FILE); 8876 out: 8877 INT_ON; 8878 return fd; 8879 } 8880 8881 /* 8882 * Like setinputfile, but takes input from a string. 8883 */ 8884 static void 8885 setinputstring(char *string) 8886 { 8887 INT_OFF; 8888 pushfile(); 8889 parsenextc = string; 8890 parsenleft = strlen(string); 8891 parsefile->buf = NULL; 8892 plinno = 1; 8893 INT_ON; 8894 } 8895 8896 8897 /* ============ mail.c 8898 * 8899 * Routines to check for mail. 8900 */ 8901 8902 #if ENABLE_ASH_MAIL 7776 8903 7777 8904 #define MAXMBOXES 10 … … 7782 8909 static int mail_var_path_changed; 7783 8910 7784 7785 7786 8911 /* 7787 8912 * Print appropriate message(s) if mail has arrived. … … 7790 8915 * so we just update the values. 7791 8916 */ 7792 7793 8917 static void 7794 8918 chkmail(void) … … 7809 8933 if (*p == '\0') 7810 8934 continue; 7811 for (q = p ; *q; q++);7812 #if defDEBUG8935 for (q = p; *q; q++); 8936 #if DEBUG 7813 8937 if (q[-1] != '/') 7814 8938 abort(); … … 7831 8955 } 7832 8956 7833 7834 8957 static void 7835 8958 changemail(const char *val) … … 7838 8961 } 7839 8962 7840 #endif /* CONFIG_ASH_MAIL */ 7841 7842 /* main.c */ 7843 7844 7845 #if PROFILE 7846 static short profile_buf[16384]; 7847 extern int etext(); 7848 #endif 7849 7850 static int isloginsh; 7851 7852 static void read_profile(const char *); 7853 7854 /* 7855 * Main routine. We initialize things, parse the arguments, execute 7856 * profiles if we're a login shell, and then call cmdloop to execute 7857 * commands. The setjmp call sets up the location to jump to when an 7858 * exception occurs. When an exception occurs the variable "state" 7859 * is used to figure out how far we had gotten. 7860 */ 7861 7862 int 7863 ash_main(int argc, char **argv) 7864 { 7865 char *shinit; 7866 volatile int state; 7867 struct jmploc jmploc; 7868 struct stackmark smark; 7869 7870 #ifdef __GLIBC__ 7871 dash_errno = __errno_location(); 7872 #endif 7873 7874 #if PROFILE 7875 monitor(4, etext, profile_buf, sizeof profile_buf, 50); 7876 #endif 7877 state = 0; 7878 if (setjmp(jmploc.loc)) { 7879 int e; 7880 int s; 7881 7882 reset(); 7883 7884 e = exception; 7885 if (e == EXERROR) 7886 exitstatus = 2; 7887 s = state; 7888 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 7889 exitshell(); 7890 7891 if (e == EXINT) { 7892 outcslow('\n', stderr); 7893 } 7894 popstackmark(&smark); 7895 FORCEINTON; /* enable interrupts */ 7896 if (s == 1) 7897 goto state1; 7898 else if (s == 2) 7899 goto state2; 7900 else if (s == 3) 7901 goto state3; 7902 else 7903 goto state4; 7904 } 7905 handler = &jmploc; 7906 #ifdef DEBUG 7907 opentrace(); 7908 trputs("Shell args: "); trargs(argv); 7909 #endif 7910 rootpid = getpid(); 7911 7912 #ifdef CONFIG_ASH_RANDOM_SUPPORT 7913 rseed = rootpid + ((time_t)time((time_t *)0)); 7914 #endif 7915 init(); 7916 setstackmark(&smark); 7917 procargs(argc, argv); 7918 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7919 if ( iflag ) { 7920 const char *hp = lookupvar("HISTFILE"); 7921 7922 if(hp == NULL ) { 7923 hp = lookupvar("HOME"); 7924 if(hp != NULL) { 7925 char *defhp = concat_path_file(hp, ".ash_history"); 7926 setvar("HISTFILE", defhp, 0); 7927 free(defhp); 7928 } 7929 } 7930 } 7931 #endif 7932 if (argv[0] && argv[0][0] == '-') 7933 isloginsh = 1; 7934 if (isloginsh) { 7935 state = 1; 7936 read_profile("/etc/profile"); 7937 state1: 7938 state = 2; 7939 read_profile(".profile"); 7940 } 7941 state2: 7942 state = 3; 7943 if ( 7944 #ifndef linux 7945 getuid() == geteuid() && getgid() == getegid() && 7946 #endif 7947 iflag 7948 ) { 7949 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 7950 read_profile(shinit); 7951 } 7952 } 7953 state3: 7954 state = 4; 7955 if (minusc) 7956 evalstring(minusc, 0); 7957 7958 if (sflag || minusc == NULL) { 7959 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7960 if ( iflag ) { 7961 const char *hp = lookupvar("HISTFILE"); 7962 7963 if(hp != NULL ) 7964 load_history ( hp ); 7965 } 7966 #endif 7967 state4: /* XXX ??? - why isn't this before the "if" statement */ 7968 cmdloop(1); 7969 } 7970 #if PROFILE 7971 monitor(0); 7972 #endif 7973 #if GPROF 7974 { 7975 extern void _mcleanup(void); 7976 _mcleanup(); 7977 } 7978 #endif 7979 exitshell(); 7980 /* NOTREACHED */ 7981 } 7982 7983 7984 /* 7985 * Read and execute commands. "Top" is nonzero for the top level command 7986 * loop; it turns on prompting if the shell is interactive. 7987 */ 7988 7989 static int 7990 cmdloop(int top) 7991 { 7992 union node *n; 7993 struct stackmark smark; 7994 int inter; 7995 int numeof = 0; 7996 7997 TRACE(("cmdloop(%d) called\n", top)); 7998 for (;;) { 7999 int skip; 8000 8001 setstackmark(&smark); 8002 #if JOBS 8003 if (jobctl) 8004 showjobs(stderr, SHOW_CHANGED); 8005 #endif 8006 inter = 0; 8007 if (iflag && top) { 8008 inter++; 8009 #ifdef CONFIG_ASH_MAIL 8010 chkmail(); 8011 #endif 8012 } 8013 n = parsecmd(inter); 8014 /* showtree(n); DEBUG */ 8015 if (n == NEOF) { 8016 if (!top || numeof >= 50) 8017 break; 8018 if (!stoppedjobs()) { 8019 if (!Iflag) 8020 break; 8021 out2str("\nUse \"exit\" to leave shell.\n"); 8022 } 8023 numeof++; 8024 } else if (nflag == 0) { 8025 job_warning = (job_warning == 2) ? 1 : 0; 8026 numeof = 0; 8027 evaltree(n, 0); 8028 } 8029 popstackmark(&smark); 8030 skip = evalskip; 8031 8032 if (skip) { 8033 evalskip = 0; 8034 return skip & SKIPEVAL; 8035 } 8036 } 8037 8038 return 0; 8039 } 8040 8041 8042 /* 8043 * Read /etc/profile or .profile. Return on error. 8044 */ 8045 8046 static void 8047 read_profile(const char *name) 8048 { 8049 int skip; 8050 8051 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) 8052 return; 8053 8054 skip = cmdloop(0); 8055 popfile(); 8056 8057 if (skip) 8058 exitshell(); 8059 } 8060 8061 8062 /* 8063 * Read a file containing shell functions. 8064 */ 8065 8066 static void 8067 readcmdfile(char *name) 8068 { 8069 setinputfile(name, INPUT_PUSH_FILE); 8070 cmdloop(0); 8071 popfile(); 8072 } 8073 8074 8075 /* 8076 * Take commands from a file. To be compatible we should do a path 8077 * search for the file, which is necessary to find sub-commands. 8078 */ 8079 8080 static inline char * 8081 find_dot_file(char *name) 8082 { 8083 char *fullname; 8084 const char *path = pathval(); 8085 struct stat statb; 8086 8087 /* don't try this for absolute or relative paths */ 8088 if (strchr(name, '/')) 8089 return name; 8090 8091 while ((fullname = padvance(&path, name)) != NULL) { 8092 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 8093 /* 8094 * Don't bother freeing here, since it will 8095 * be freed by the caller. 8096 */ 8097 return fullname; 8098 } 8099 stunalloc(fullname); 8100 } 8101 8102 /* not found in the PATH */ 8103 sh_error(not_found_msg, name); 8104 /* NOTREACHED */ 8105 } 8106 8107 static int dotcmd(int argc, char **argv) 8108 { 8109 struct strlist *sp; 8110 volatile struct shparam saveparam; 8111 int status = 0; 8112 8113 for (sp = cmdenviron; sp; sp = sp->next) 8114 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 8115 8116 if (argc >= 2) { /* That's what SVR2 does */ 8117 char *fullname; 8118 8119 fullname = find_dot_file(argv[1]); 8120 8121 if (argc > 2) { 8122 saveparam = shellparam; 8123 shellparam.malloc = 0; 8124 shellparam.nparam = argc - 2; 8125 shellparam.p = argv + 2; 8126 }; 8127 8128 setinputfile(fullname, INPUT_PUSH_FILE); 8129 commandname = fullname; 8130 cmdloop(0); 8131 popfile(); 8132 8133 if (argc > 2) { 8134 freeparam(&shellparam); 8135 shellparam = saveparam; 8136 }; 8137 status = exitstatus; 8138 } 8139 return status; 8140 } 8141 8142 8143 static int 8144 exitcmd(int argc, char **argv) 8145 { 8146 if (stoppedjobs()) 8147 return 0; 8148 if (argc > 1) 8149 exitstatus = number(argv[1]); 8150 exraise(EXEXIT); 8151 /* NOTREACHED */ 8152 } 8153 8154 #ifdef CONFIG_ASH_BUILTIN_ECHO 8155 static int 8156 echocmd(int argc, char **argv) 8157 { 8158 return bb_echo(argc, argv); 8159 } 8160 #endif 8161 8162 #ifdef CONFIG_ASH_BUILTIN_TEST 8163 static int 8164 testcmd(int argc, char **argv) 8165 { 8166 return bb_test(argc, argv); 8167 } 8168 #endif 8169 8170 /* memalloc.c */ 8171 8172 /* 8173 * Same for malloc, realloc, but returns an error when out of space. 8174 */ 8175 8176 static pointer 8177 ckrealloc(pointer p, size_t nbytes) 8178 { 8179 p = realloc(p, nbytes); 8180 if (p == NULL) 8181 sh_error(bb_msg_memory_exhausted); 8182 return p; 8183 } 8184 8185 static pointer 8186 ckmalloc(size_t nbytes) 8187 { 8188 return ckrealloc(NULL, nbytes); 8189 } 8190 8191 /* 8192 * Make a copy of a string in safe storage. 8193 */ 8194 8195 static char * 8196 savestr(const char *s) 8197 { 8198 char *p = strdup(s); 8199 if (!p) 8200 sh_error(bb_msg_memory_exhausted); 8201 return p; 8202 } 8203 8204 8205 /* 8206 * Parse trees for commands are allocated in lifo order, so we use a stack 8207 * to make this more efficient, and also to avoid all sorts of exception 8208 * handling code to handle interrupts in the middle of a parse. 8209 * 8210 * The size 504 was chosen because the Ultrix malloc handles that size 8211 * well. 8212 */ 8213 8214 8215 static pointer 8216 stalloc(size_t nbytes) 8217 { 8218 char *p; 8219 size_t aligned; 8220 8221 aligned = SHELL_ALIGN(nbytes); 8222 if (aligned > stacknleft) { 8223 size_t len; 8224 size_t blocksize; 8225 struct stack_block *sp; 8226 8227 blocksize = aligned; 8228 if (blocksize < MINSIZE) 8229 blocksize = MINSIZE; 8230 len = sizeof(struct stack_block) - MINSIZE + blocksize; 8231 if (len < blocksize) 8232 sh_error(bb_msg_memory_exhausted); 8233 INTOFF; 8234 sp = ckmalloc(len); 8235 sp->prev = stackp; 8236 stacknxt = sp->space; 8237 stacknleft = blocksize; 8238 sstrend = stacknxt + blocksize; 8239 stackp = sp; 8240 INTON; 8241 } 8242 p = stacknxt; 8243 stacknxt += aligned; 8244 stacknleft -= aligned; 8245 return p; 8246 } 8247 8248 8249 void 8250 stunalloc(pointer p) 8251 { 8252 #ifdef DEBUG 8253 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { 8254 write(2, "stunalloc\n", 10); 8255 abort(); 8256 } 8257 #endif 8258 stacknleft += stacknxt - (char *)p; 8259 stacknxt = p; 8260 } 8261 8262 8263 void 8264 setstackmark(struct stackmark *mark) 8265 { 8266 mark->stackp = stackp; 8267 mark->stacknxt = stacknxt; 8268 mark->stacknleft = stacknleft; 8269 mark->marknext = markp; 8270 markp = mark; 8271 } 8272 8273 8274 void 8275 popstackmark(struct stackmark *mark) 8276 { 8277 struct stack_block *sp; 8278 8279 INTOFF; 8280 markp = mark->marknext; 8281 while (stackp != mark->stackp) { 8282 sp = stackp; 8283 stackp = sp->prev; 8284 ckfree(sp); 8285 } 8286 stacknxt = mark->stacknxt; 8287 stacknleft = mark->stacknleft; 8288 sstrend = mark->stacknxt + mark->stacknleft; 8289 INTON; 8290 } 8291 8292 8293 /* 8294 * When the parser reads in a string, it wants to stick the string on the 8295 * stack and only adjust the stack pointer when it knows how big the 8296 * string is. Stackblock (defined in stack.h) returns a pointer to a block 8297 * of space on top of the stack and stackblocklen returns the length of 8298 * this block. Growstackblock will grow this space by at least one byte, 8299 * possibly moving it (like realloc). Grabstackblock actually allocates the 8300 * part of the block that has been used. 8301 */ 8302 8303 void 8304 growstackblock(void) 8305 { 8306 size_t newlen; 8307 8308 newlen = stacknleft * 2; 8309 if (newlen < stacknleft) 8310 sh_error(bb_msg_memory_exhausted); 8311 if (newlen < 128) 8312 newlen += 128; 8313 8314 if (stacknxt == stackp->space && stackp != &stackbase) { 8315 struct stack_block *oldstackp; 8316 struct stackmark *xmark; 8317 struct stack_block *sp; 8318 struct stack_block *prevstackp; 8319 size_t grosslen; 8320 8321 INTOFF; 8322 oldstackp = stackp; 8323 sp = stackp; 8324 prevstackp = sp->prev; 8325 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 8326 sp = ckrealloc((pointer)sp, grosslen); 8327 sp->prev = prevstackp; 8328 stackp = sp; 8329 stacknxt = sp->space; 8330 stacknleft = newlen; 8331 sstrend = sp->space + newlen; 8332 8333 /* 8334 * Stack marks pointing to the start of the old block 8335 * must be relocated to point to the new block 8336 */ 8337 xmark = markp; 8338 while (xmark != NULL && xmark->stackp == oldstackp) { 8339 xmark->stackp = stackp; 8340 xmark->stacknxt = stacknxt; 8341 xmark->stacknleft = stacknleft; 8342 xmark = xmark->marknext; 8343 } 8344 INTON; 8345 } else { 8346 char *oldspace = stacknxt; 8347 int oldlen = stacknleft; 8348 char *p = stalloc(newlen); 8349 8350 /* free the space we just allocated */ 8351 stacknxt = memcpy(p, oldspace, oldlen); 8352 stacknleft += newlen; 8353 } 8354 } 8355 8356 static inline void 8357 grabstackblock(size_t len) 8358 { 8359 len = SHELL_ALIGN(len); 8360 stacknxt += len; 8361 stacknleft -= len; 8362 } 8363 8364 /* 8365 * The following routines are somewhat easier to use than the above. 8366 * The user declares a variable of type STACKSTR, which may be declared 8367 * to be a register. The macro STARTSTACKSTR initializes things. Then 8368 * the user uses the macro STPUTC to add characters to the string. In 8369 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 8370 * grown as necessary. When the user is done, she can just leave the 8371 * string there and refer to it using stackblock(). Or she can allocate 8372 * the space for it using grabstackstr(). If it is necessary to allow 8373 * someone else to use the stack temporarily and then continue to grow 8374 * the string, the user should use grabstack to allocate the space, and 8375 * then call ungrabstr(p) to return to the previous mode of operation. 8376 * 8377 * USTPUTC is like STPUTC except that it doesn't check for overflow. 8378 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 8379 * is space for at least one character. 8380 */ 8381 8382 void * 8383 growstackstr(void) 8384 { 8385 size_t len = stackblocksize(); 8386 if (herefd >= 0 && len >= 1024) { 8387 bb_full_write(herefd, stackblock(), len); 8388 return stackblock(); 8389 } 8390 growstackblock(); 8391 return stackblock() + len; 8392 } 8393 8394 /* 8395 * Called from CHECKSTRSPACE. 8396 */ 8397 8398 char * 8399 makestrspace(size_t newlen, char *p) 8400 { 8401 size_t len = p - stacknxt; 8402 size_t size = stackblocksize(); 8403 8404 for (;;) { 8405 size_t nleft; 8406 8407 size = stackblocksize(); 8408 nleft = size - len; 8409 if (nleft >= newlen) 8410 break; 8411 growstackblock(); 8412 } 8413 return stackblock() + len; 8414 } 8415 8416 char * 8417 stnputs(const char *s, size_t n, char *p) 8418 { 8419 p = makestrspace(n, p); 8420 p = mempcpy(p, s, n); 8421 return p; 8422 } 8423 8424 char * 8425 stputs(const char *s, char *p) 8426 { 8427 return stnputs(s, strlen(s), p); 8428 } 8429 8430 /* mystring.c */ 8431 8432 /* 8433 * String functions. 8434 * 8435 * number(s) Convert a string of digits to an integer. 8436 * is_number(s) Return true if s is a string of digits. 8437 */ 8438 8439 /* 8440 * prefix -- see if pfx is a prefix of string. 8441 */ 8442 8443 char * 8444 prefix(const char *string, const char *pfx) 8445 { 8446 while (*pfx) { 8447 if (*pfx++ != *string++) 8448 return 0; 8449 } 8450 return (char *) string; 8451 } 8452 8453 8454 /* 8455 * Convert a string of digits to an integer, printing an error message on 8456 * failure. 8457 */ 8458 8459 int 8460 number(const char *s) 8461 { 8462 8463 if (! is_number(s)) 8464 sh_error(illnum, s); 8465 return atoi(s); 8466 } 8467 8468 8469 /* 8470 * Check for a valid number. This should be elsewhere. 8471 */ 8472 8473 int 8474 is_number(const char *p) 8475 { 8476 do { 8477 if (! is_digit(*p)) 8478 return 0; 8479 } while (*++p != '\0'); 8480 return 1; 8481 } 8482 8483 8484 /* 8485 * Produce a possibly single quoted string suitable as input to the shell. 8486 * The return string is allocated on the stack. 8487 */ 8488 8489 char * 8490 single_quote(const char *s) { 8491 char *p; 8492 8493 STARTSTACKSTR(p); 8494 8495 do { 8496 char *q; 8497 size_t len; 8498 8499 len = strchrnul(s, '\'') - s; 8500 8501 q = p = makestrspace(len + 3, p); 8502 8503 *q++ = '\''; 8504 q = mempcpy(q, s, len); 8505 *q++ = '\''; 8506 s += len; 8507 8508 STADJUST(q - p, p); 8509 8510 len = strspn(s, "'"); 8511 if (!len) 8512 break; 8513 8514 q = p = makestrspace(len + 3, p); 8515 8516 *q++ = '"'; 8517 q = mempcpy(q, s, len); 8518 *q++ = '"'; 8519 s += len; 8520 8521 STADJUST(q - p, p); 8522 } while (*s); 8523 8524 USTPUTC(0, p); 8525 8526 return stackblock(); 8527 } 8528 8529 /* 8530 * Like strdup but works with the ash stack. 8531 */ 8532 8533 char * 8534 sstrdup(const char *p) 8535 { 8536 size_t len = strlen(p) + 1; 8537 return memcpy(stalloc(len), p, len); 8538 } 8539 8540 8541 static void 8542 calcsize(union node *n) 8543 { 8544 if (n == NULL) 8545 return; 8546 funcblocksize += nodesize[n->type]; 8547 switch (n->type) { 8548 case NCMD: 8549 calcsize(n->ncmd.redirect); 8550 calcsize(n->ncmd.args); 8551 calcsize(n->ncmd.assign); 8552 break; 8553 case NPIPE: 8554 sizenodelist(n->npipe.cmdlist); 8555 break; 8556 case NREDIR: 8557 case NBACKGND: 8558 case NSUBSHELL: 8559 calcsize(n->nredir.redirect); 8560 calcsize(n->nredir.n); 8561 break; 8562 case NAND: 8563 case NOR: 8564 case NSEMI: 8565 case NWHILE: 8566 case NUNTIL: 8567 calcsize(n->nbinary.ch2); 8568 calcsize(n->nbinary.ch1); 8569 break; 8570 case NIF: 8571 calcsize(n->nif.elsepart); 8572 calcsize(n->nif.ifpart); 8573 calcsize(n->nif.test); 8574 break; 8575 case NFOR: 8576 funcstringsize += strlen(n->nfor.var) + 1; 8577 calcsize(n->nfor.body); 8578 calcsize(n->nfor.args); 8579 break; 8580 case NCASE: 8581 calcsize(n->ncase.cases); 8582 calcsize(n->ncase.expr); 8583 break; 8584 case NCLIST: 8585 calcsize(n->nclist.body); 8586 calcsize(n->nclist.pattern); 8587 calcsize(n->nclist.next); 8588 break; 8589 case NDEFUN: 8590 case NARG: 8591 sizenodelist(n->narg.backquote); 8592 funcstringsize += strlen(n->narg.text) + 1; 8593 calcsize(n->narg.next); 8594 break; 8595 case NTO: 8596 case NCLOBBER: 8597 case NFROM: 8598 case NFROMTO: 8599 case NAPPEND: 8600 calcsize(n->nfile.fname); 8601 calcsize(n->nfile.next); 8602 break; 8603 case NTOFD: 8604 case NFROMFD: 8605 calcsize(n->ndup.vname); 8606 calcsize(n->ndup.next); 8607 break; 8608 case NHERE: 8609 case NXHERE: 8610 calcsize(n->nhere.doc); 8611 calcsize(n->nhere.next); 8612 break; 8613 case NNOT: 8614 calcsize(n->nnot.com); 8615 break; 8616 }; 8617 } 8618 8619 8620 static void 8621 sizenodelist(struct nodelist *lp) 8622 { 8623 while (lp) { 8624 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8625 calcsize(lp->n); 8626 lp = lp->next; 8627 } 8628 } 8629 8630 8631 static union node * 8632 copynode(union node *n) 8633 { 8634 union node *new; 8635 8636 if (n == NULL) 8637 return NULL; 8638 new = funcblock; 8639 funcblock = (char *) funcblock + nodesize[n->type]; 8640 switch (n->type) { 8641 case NCMD: 8642 new->ncmd.redirect = copynode(n->ncmd.redirect); 8643 new->ncmd.args = copynode(n->ncmd.args); 8644 new->ncmd.assign = copynode(n->ncmd.assign); 8645 break; 8646 case NPIPE: 8647 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8648 new->npipe.backgnd = n->npipe.backgnd; 8649 break; 8650 case NREDIR: 8651 case NBACKGND: 8652 case NSUBSHELL: 8653 new->nredir.redirect = copynode(n->nredir.redirect); 8654 new->nredir.n = copynode(n->nredir.n); 8655 break; 8656 case NAND: 8657 case NOR: 8658 case NSEMI: 8659 case NWHILE: 8660 case NUNTIL: 8661 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8662 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8663 break; 8664 case NIF: 8665 new->nif.elsepart = copynode(n->nif.elsepart); 8666 new->nif.ifpart = copynode(n->nif.ifpart); 8667 new->nif.test = copynode(n->nif.test); 8668 break; 8669 case NFOR: 8670 new->nfor.var = nodesavestr(n->nfor.var); 8671 new->nfor.body = copynode(n->nfor.body); 8672 new->nfor.args = copynode(n->nfor.args); 8673 break; 8674 case NCASE: 8675 new->ncase.cases = copynode(n->ncase.cases); 8676 new->ncase.expr = copynode(n->ncase.expr); 8677 break; 8678 case NCLIST: 8679 new->nclist.body = copynode(n->nclist.body); 8680 new->nclist.pattern = copynode(n->nclist.pattern); 8681 new->nclist.next = copynode(n->nclist.next); 8682 break; 8683 case NDEFUN: 8684 case NARG: 8685 new->narg.backquote = copynodelist(n->narg.backquote); 8686 new->narg.text = nodesavestr(n->narg.text); 8687 new->narg.next = copynode(n->narg.next); 8688 break; 8689 case NTO: 8690 case NCLOBBER: 8691 case NFROM: 8692 case NFROMTO: 8693 case NAPPEND: 8694 new->nfile.fname = copynode(n->nfile.fname); 8695 new->nfile.fd = n->nfile.fd; 8696 new->nfile.next = copynode(n->nfile.next); 8697 break; 8698 case NTOFD: 8699 case NFROMFD: 8700 new->ndup.vname = copynode(n->ndup.vname); 8701 new->ndup.dupfd = n->ndup.dupfd; 8702 new->ndup.fd = n->ndup.fd; 8703 new->ndup.next = copynode(n->ndup.next); 8704 break; 8705 case NHERE: 8706 case NXHERE: 8707 new->nhere.doc = copynode(n->nhere.doc); 8708 new->nhere.fd = n->nhere.fd; 8709 new->nhere.next = copynode(n->nhere.next); 8710 break; 8711 case NNOT: 8712 new->nnot.com = copynode(n->nnot.com); 8713 break; 8714 }; 8715 new->type = n->type; 8716 return new; 8717 } 8718 8719 8720 static struct nodelist * 8721 copynodelist(struct nodelist *lp) 8722 { 8723 struct nodelist *start; 8724 struct nodelist **lpp; 8725 8726 lpp = &start; 8727 while (lp) { 8728 *lpp = funcblock; 8729 funcblock = (char *) funcblock + 8730 SHELL_ALIGN(sizeof(struct nodelist)); 8731 (*lpp)->n = copynode(lp->n); 8732 lp = lp->next; 8733 lpp = &(*lpp)->next; 8734 } 8735 *lpp = NULL; 8736 return start; 8737 } 8738 8739 8740 static char * 8741 nodesavestr(char *s) 8742 { 8743 char *rtn = funcstring; 8744 8745 funcstring = stpcpy(funcstring, s) + 1; 8746 return rtn; 8747 } 8748 8749 8750 /* 8751 * Free a parse tree. 8752 */ 8753 8754 static void 8755 freefunc(struct funcnode *f) 8756 { 8757 if (f && --f->count < 0) 8758 ckfree(f); 8759 } 8760 8761 8762 static void options(int); 8763 static void setoption(int, int); 8764 8765 8766 /* 8767 * Process the shell command line arguments. 8768 */ 8769 8770 void 8771 procargs(int argc, char **argv) 8772 { 8773 int i; 8774 const char *xminusc; 8775 char **xargv; 8776 8777 xargv = argv; 8778 arg0 = xargv[0]; 8779 if (argc > 0) 8780 xargv++; 8781 for (i = 0; i < NOPTS; i++) 8782 optlist[i] = 2; 8783 argptr = xargv; 8784 options(1); 8785 xargv = argptr; 8786 xminusc = minusc; 8787 if (*xargv == NULL) { 8788 if (xminusc) 8789 sh_error(bb_msg_requires_arg, "-c"); 8790 sflag = 1; 8791 } 8792 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 8793 iflag = 1; 8794 if (mflag == 2) 8795 mflag = iflag; 8796 for (i = 0; i < NOPTS; i++) 8797 if (optlist[i] == 2) 8798 optlist[i] = 0; 8799 #if DEBUG == 2 8800 debug = 1; 8801 #endif 8802 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 8803 if (xminusc) { 8804 minusc = *xargv++; 8805 if (*xargv) 8806 goto setarg0; 8807 } else if (!sflag) { 8808 setinputfile(*xargv, 0); 8809 setarg0: 8810 arg0 = *xargv++; 8811 commandname = arg0; 8812 } 8813 8814 shellparam.p = xargv; 8815 #ifdef CONFIG_ASH_GETOPTS 8963 #endif /* ASH_MAIL */ 8964 8965 8966 /* ============ ??? */ 8967 8968 /* 8969 * Set the shell parameters. 8970 */ 8971 static void 8972 setparam(char **argv) 8973 { 8974 char **newparam; 8975 char **ap; 8976 int nparam; 8977 8978 for (nparam = 0; argv[nparam]; nparam++); 8979 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); 8980 while (*argv) { 8981 *ap++ = ckstrdup(*argv++); 8982 } 8983 *ap = NULL; 8984 freeparam(&shellparam); 8985 shellparam.malloc = 1; 8986 shellparam.nparam = nparam; 8987 shellparam.p = newparam; 8988 #if ENABLE_ASH_GETOPTS 8816 8989 shellparam.optind = 1; 8817 8990 shellparam.optoff = -1; 8818 8991 #endif 8819 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 8820 while (*xargv) { 8821 shellparam.nparam++; 8822 xargv++; 8823 } 8824 optschanged(); 8825 } 8826 8827 8828 void 8829 optschanged(void) 8830 { 8831 #ifdef DEBUG 8832 opentrace(); 8833 #endif 8834 setinteractive(iflag); 8835 setjobctl(mflag); 8836 setvimode(viflag); 8837 } 8838 8839 static inline void 8992 } 8993 8994 /* 8995 * Process shell options. The global variable argptr contains a pointer 8996 * to the argument list; we advance it past the options. 8997 */ 8998 static void 8840 8999 minus_o(char *name, int val) 8841 9000 { 8842 9001 int i; 8843 9002 8844 if (name == NULL) { 8845 out1str("Current option settings\n"); 8846 for (i = 0; i < NOPTS; i++) 8847 out1fmt("%-16s%s\n", optnames(i), 8848 optlist[i] ? "on" : "off"); 8849 } else { 8850 for (i = 0; i < NOPTS; i++) 8851 if (equal(name, optnames(i))) { 9003 if (name) { 9004 for (i = 0; i < NOPTS; i++) { 9005 if (strcmp(name, optnames(i)) == 0) { 8852 9006 optlist[i] = val; 8853 9007 return; 8854 9008 } 8855 sh_error("Illegal option -o %s", name); 8856 } 8857 } 8858 8859 /* 8860 * Process shell options. The global variable argptr contains a pointer 8861 * to the argument list; we advance it past the options. 8862 */ 8863 9009 } 9010 ash_msg_and_raise_error("illegal option -o %s", name); 9011 } 9012 out1str("Current option settings\n"); 9013 for (i = 0; i < NOPTS; i++) 9014 out1fmt("%-16s%s\n", optnames(i), 9015 optlist[i] ? "on" : "off"); 9016 } 9017 static void 9018 setoption(int flag, int val) 9019 { 9020 int i; 9021 9022 for (i = 0; i < NOPTS; i++) { 9023 if (optletters(i) == flag) { 9024 optlist[i] = val; 9025 return; 9026 } 9027 } 9028 ash_msg_and_raise_error("illegal option -%c", flag); 9029 /* NOTREACHED */ 9030 } 8864 9031 static void 8865 9032 options(int cmdline) … … 8872 9039 minusc = NULL; 8873 9040 while ((p = *argptr) != NULL) { 9041 c = *p++; 9042 if (c != '-' && c != '+') 9043 break; 8874 9044 argptr++; 8875 if ((c = *p++) == '-') { 9045 val = 0; /* val = 0 if c == '+' */ 9046 if (c == '-') { 8876 9047 val = 1; 8877 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {9048 if (p[0] == '\0' || LONE_DASH(p)) { 8878 9049 if (!cmdline) { 8879 9050 /* "-" means turn off -x and -v */ … … 8886 9057 break; /* "-" or "--" terminates options */ 8887 9058 } 8888 } else if (c == '+') { 8889 val = 0; 8890 } else { 8891 argptr--; 8892 break; 8893 } 9059 } 9060 /* first char was + or - */ 8894 9061 while ((c = *p++) != '\0') { 9062 /* bash 3.2 indeed handles -c CMD and +c CMD the same */ 8895 9063 if (c == 'c' && cmdline) { 8896 minusc = p; /* command is after shell args */9064 minusc = p; /* command is after shell args */ 8897 9065 } else if (c == 'o') { 8898 9066 minus_o(*argptr, val); 8899 9067 if (*argptr) 8900 9068 argptr++; 8901 } else if (cmdline && (c == '-')) { // long options 9069 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */ 9070 isloginsh = 1; 9071 /* bash does not accept +-login, we also won't */ 9072 } else if (cmdline && val && (c == '-')) { /* long options */ 8902 9073 if (strcmp(p, "login") == 0) 8903 9074 isloginsh = 1; … … 8910 9081 } 8911 9082 8912 8913 static void8914 setoption(int flag, int val)8915 {8916 int i;8917 8918 for (i = 0; i < NOPTS; i++)8919 if (optletters(i) == flag) {8920 optlist[i] = val;8921 return;8922 }8923 sh_error("Illegal option -%c", flag);8924 /* NOTREACHED */8925 }8926 8927 8928 8929 /*8930 * Set the shell parameters.8931 */8932 8933 void8934 setparam(char **argv)8935 {8936 char **newparam;8937 char **ap;8938 int nparam;8939 8940 for (nparam = 0 ; argv[nparam] ; nparam++);8941 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);8942 while (*argv) {8943 *ap++ = savestr(*argv++);8944 }8945 *ap = NULL;8946 freeparam(&shellparam);8947 shellparam.malloc = 1;8948 shellparam.nparam = nparam;8949 shellparam.p = newparam;8950 #ifdef CONFIG_ASH_GETOPTS8951 shellparam.optind = 1;8952 shellparam.optoff = -1;8953 #endif8954 }8955 8956 8957 /*8958 * Free the list of positional parameters.8959 */8960 8961 void8962 freeparam(volatile struct shparam *param)8963 {8964 char **ap;8965 8966 if (param->malloc) {8967 for (ap = param->p ; *ap ; ap++)8968 ckfree(*ap);8969 ckfree(param->p);8970 }8971 }8972 8973 8974 8975 9083 /* 8976 9084 * The shift builtin command. 8977 9085 */ 8978 8979 int 9086 static int 8980 9087 shiftcmd(int argc, char **argv) 8981 9088 { … … 8987 9094 n = number(argv[1]); 8988 9095 if (n > shellparam.nparam) 8989 sh_error("can't shift that many");8990 INT OFF;9096 ash_msg_and_raise_error("can't shift that many"); 9097 INT_OFF; 8991 9098 shellparam.nparam -= n; 8992 for (ap1 = shellparam.p ; --n >= 0; ap1++) {9099 for (ap1 = shellparam.p; --n >= 0; ap1++) { 8993 9100 if (shellparam.malloc) 8994 ckfree(*ap1);9101 free(*ap1); 8995 9102 } 8996 9103 ap2 = shellparam.p; 8997 9104 while ((*ap2++ = *ap1++) != NULL); 8998 #if def CONFIG_ASH_GETOPTS9105 #if ENABLE_ASH_GETOPTS 8999 9106 shellparam.optind = 1; 9000 9107 shellparam.optoff = -1; 9001 9108 #endif 9002 INT ON;9109 INT_ON; 9003 9110 return 0; 9004 9111 } 9005 9112 9006 9113 /* 9114 * POSIX requires that 'set' (but not export or readonly) output the 9115 * variables in lexicographic order - by the locale's collating order (sigh). 9116 * Maybe we could keep them in an ordered balanced binary tree 9117 * instead of hashed lists. 9118 * For now just roll 'em through qsort for printing... 9119 */ 9120 static int 9121 showvars(const char *sep_prefix, int on, int off) 9122 { 9123 const char *sep; 9124 char **ep, **epend; 9125 9126 ep = listvars(on, off, &epend); 9127 qsort(ep, epend - ep, sizeof(char *), vpcmp); 9128 9129 sep = *sep_prefix ? " " : sep_prefix; 9130 9131 for (; ep < epend; ep++) { 9132 const char *p; 9133 const char *q; 9134 9135 p = strchrnul(*ep, '='); 9136 q = nullstr; 9137 if (*p) 9138 q = single_quote(++p); 9139 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); 9140 } 9141 return 0; 9142 } 9007 9143 9008 9144 /* 9009 9145 * The set command builtin. 9010 9146 */ 9011 9012 int 9147 static int 9013 9148 setcmd(int argc, char **argv) 9014 9149 { 9015 9150 if (argc == 1) 9016 9151 return showvars(nullstr, 0, VUNSET); 9017 INT OFF;9152 INT_OFF; 9018 9153 options(0); 9019 9154 optschanged(); … … 9021 9156 setparam(argptr); 9022 9157 } 9023 INT ON;9158 INT_ON; 9024 9159 return 0; 9025 9160 } 9026 9161 9027 9028 #ifdef CONFIG_ASH_GETOPTS 9029 static void 9030 getoptsreset(const char *value) 9031 { 9032 shellparam.optind = number(value); 9033 shellparam.optoff = -1; 9034 } 9035 #endif 9036 9037 #ifdef CONFIG_LOCALE_SUPPORT 9038 static void change_lc_all(const char *value) 9039 { 9040 if (value != 0 && *value != 0) 9041 setlocale(LC_ALL, value); 9042 } 9043 9044 static void change_lc_ctype(const char *value) 9045 { 9046 if (value != 0 && *value != 0) 9047 setlocale(LC_CTYPE, value); 9048 } 9049 9050 #endif 9051 9052 #ifdef CONFIG_ASH_RANDOM_SUPPORT 9162 #if ENABLE_ASH_RANDOM_SUPPORT 9053 9163 /* Roughly copied from bash.. */ 9054 static void change_random(const char *value) 9055 { 9056 if(value == NULL) { 9164 static void 9165 change_random(const char *value) 9166 { 9167 if (value == NULL) { 9057 9168 /* "get", generate */ 9058 9169 char buf[16]; … … 9070 9181 #endif 9071 9182 9072 9073 #ifdef CONFIG_ASH_GETOPTS 9183 #if ENABLE_ASH_GETOPTS 9074 9184 static int 9075 9185 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) … … 9082 9192 char **optnext; 9083 9193 9084 if (*param_optind < 1)9194 if (*param_optind < 1) 9085 9195 return 1; 9086 9196 optnext = optfirst + *param_optind - 1; … … 9094 9204 p = *optnext; 9095 9205 if (p == NULL || *p != '-' || *++p == '\0') { 9096 atend:9206 atend: 9097 9207 p = NULL; 9098 9208 done = 1; … … 9100 9210 } 9101 9211 optnext++; 9102 if ( p[0] == '-' && p[1] == '\0') /* check for "--" */9212 if (LONE_DASH(p)) /* check for "--" */ 9103 9213 goto atend; 9104 9214 } … … 9113 9223 } else { 9114 9224 fprintf(stderr, "Illegal option -%c\n", c); 9115 (void)unsetvar("OPTARG");9225 unsetvar("OPTARG"); 9116 9226 } 9117 9227 c = '?'; … … 9131 9241 } else { 9132 9242 fprintf(stderr, "No arg for -%c option\n", c); 9133 (void)unsetvar("OPTARG");9243 unsetvar("OPTARG"); 9134 9244 c = '?'; 9135 9245 } … … 9143 9253 } else 9144 9254 err |= setvarsafe("OPTARG", nullstr, 0); 9145 9146 out: 9255 out: 9147 9256 *optoff = p ? p - *(optnext - 1) : -1; 9148 9257 *param_optind = optnext - optfirst + 1; … … 9155 9264 *param_optind = 1; 9156 9265 *optoff = -1; 9157 flush all();9158 exraise(EXERROR);9266 flush_stdout_stderr(); 9267 raise_exception(EXERROR); 9159 9268 } 9160 9269 return done; … … 9167 9276 * then it's the first time getopts has been called. 9168 9277 */ 9169 9170 int 9278 static int 9171 9279 getoptscmd(int argc, char **argv) 9172 9280 { … … 9174 9282 9175 9283 if (argc < 3) 9176 sh_error("Usage: getopts optstring var [arg]");9177 elseif (argc == 3) {9284 ash_msg_and_raise_error("usage: getopts optstring var [arg]"); 9285 if (argc == 3) { 9178 9286 optbase = shellparam.p; 9179 9287 if (shellparam.optind > shellparam.nparam + 1) { … … 9181 9289 shellparam.optoff = -1; 9182 9290 } 9183 } 9184 else { 9291 } else { 9185 9292 optbase = &argv[3]; 9186 9293 if (shellparam.optind > argc - 2) { … … 9191 9298 9192 9299 return getopts(argv[1], argv[2], optbase, &shellparam.optind, 9193 &shellparam.optoff); 9194 } 9195 #endif /* CONFIG_ASH_GETOPTS */ 9196 9197 /* 9198 * XXX - should get rid of. have all builtins use getopt(3). the 9199 * library getopt must have the BSD extension static variable "optreset" 9200 * otherwise it can't be used within the shell safely. 9201 * 9202 * Standard option processing (a la getopt) for builtin routines. The 9203 * only argument that is passed to nextopt is the option string; the 9204 * other arguments are unnecessary. It return the character, or '\0' on 9205 * end of input. 9206 */ 9207 9208 static int 9209 nextopt(const char *optstring) 9210 { 9211 char *p; 9212 const char *q; 9213 char c; 9214 9215 if ((p = optptr) == NULL || *p == '\0') { 9216 p = *argptr; 9217 if (p == NULL || *p != '-' || *++p == '\0') 9218 return '\0'; 9219 argptr++; 9220 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 9221 return '\0'; 9222 } 9223 c = *p++; 9224 for (q = optstring ; *q != c ; ) { 9225 if (*q == '\0') 9226 sh_error("Illegal option -%c", c); 9227 if (*++q == ':') 9228 q++; 9229 } 9230 if (*++q == ':') { 9231 if (*p == '\0' && (p = *argptr++) == NULL) 9232 sh_error("No arg for -%c option", c); 9233 optionarg = p; 9234 p = NULL; 9235 } 9236 optptr = p; 9237 return c; 9238 } 9239 9240 9241 /* output.c */ 9242 9243 void 9244 outstr(const char *p, FILE *file) 9245 { 9246 INTOFF; 9247 fputs(p, file); 9248 INTON; 9249 } 9250 9251 void 9252 flushall(void) 9253 { 9254 INTOFF; 9255 fflush(stdout); 9256 fflush(stderr); 9257 INTON; 9258 } 9259 9260 void 9261 flusherr(void) 9262 { 9263 INTOFF; 9264 fflush(stderr); 9265 INTON; 9266 } 9267 9268 static void 9269 outcslow(int c, FILE *dest) 9270 { 9271 INTOFF; 9272 putc(c, dest); 9273 fflush(dest); 9274 INTON; 9275 } 9276 9277 9278 static int 9279 out1fmt(const char *fmt, ...) 9280 { 9281 va_list ap; 9282 int r; 9283 9284 INTOFF; 9285 va_start(ap, fmt); 9286 r = vprintf(fmt, ap); 9287 va_end(ap); 9288 INTON; 9289 return r; 9290 } 9291 9292 9293 int 9294 fmtstr(char *outbuf, size_t length, const char *fmt, ...) 9295 { 9296 va_list ap; 9297 int ret; 9298 9299 va_start(ap, fmt); 9300 INTOFF; 9301 ret = vsnprintf(outbuf, length, fmt, ap); 9302 va_end(ap); 9303 INTON; 9304 return ret; 9305 } 9306 9307 9308 9309 /* parser.c */ 9310 9311 9312 /* 9313 * Shell command parser. 9314 */ 9300 &shellparam.optoff); 9301 } 9302 #endif /* ASH_GETOPTS */ 9303 9304 9305 /* ============ Shell parser */ 9306 9307 static int tokpushback; /* last token pushed back */ 9308 #define NEOF ((union node *)&tokpushback) 9309 static int parsebackquote; /* nonzero if we are inside backquotes */ 9310 static int lasttoken; /* last token read */ 9311 static char *wordtext; /* text of last word returned by readtoken */ 9312 static struct nodelist *backquotelist; 9313 static union node *redirnode; 9314 static struct heredoc *heredoc; 9315 static int quoteflag; /* set if (part of) last token was quoted */ 9316 9317 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; 9318 static void 9319 raise_error_syntax(const char *msg) 9320 { 9321 ash_msg_and_raise_error("syntax error: %s", msg); 9322 /* NOTREACHED */ 9323 } 9324 9325 /* 9326 * Called when an unexpected token is read during the parse. The argument 9327 * is the token that is expected, or -1 if more than one type of token can 9328 * occur at this point. 9329 */ 9330 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN; 9331 static void 9332 raise_error_unexpected_syntax(int token) 9333 { 9334 char msg[64]; 9335 int l; 9336 9337 l = sprintf(msg, "%s unexpected", tokname(lasttoken)); 9338 if (token >= 0) 9339 sprintf(msg + l, " (expecting %s)", tokname(token)); 9340 raise_error_syntax(msg); 9341 /* NOTREACHED */ 9342 } 9315 9343 9316 9344 #define EOFMARKLEN 79 9317 9318 9345 9319 9346 struct heredoc { … … 9324 9351 }; 9325 9352 9326 9327 9328 9353 static struct heredoc *heredoclist; /* list of here documents to read */ 9329 9354 9330 9331 static union node *list(int); 9355 /* parsing is heavily cross-recursive, need these forward decls */ 9332 9356 static union node *andor(void); 9333 9357 static union node *pipeline(void); 9334 static union node *command(void); 9335 static union node *simplecmd(void); 9336 static union node *makename(void); 9337 static void parsefname(void); 9358 static union node *parse_command(void); 9338 9359 static void parseheredoc(void); 9339 9360 static char peektoken(void); 9340 9361 static int readtoken(void); 9341 static int xxreadtoken(void);9342 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);9343 static int noexpand(char *);9344 static void synexpect(int) ATTRIBUTE_NORETURN;9345 static void synerror(const char *) ATTRIBUTE_NORETURN;9346 static void setprompt(int);9347 9348 9349 9350 9351 /*9352 * Read and parse a command. Returns NEOF on end of file. (NULL is a9353 * valid parse tree indicating a blank line.)9354 */9355 9356 union node *9357 parsecmd(int interact)9358 {9359 int t;9360 9361 tokpushback = 0;9362 doprompt = interact;9363 if (doprompt)9364 setprompt(doprompt);9365 needprompt = 0;9366 t = readtoken();9367 if (t == TEOF)9368 return NEOF;9369 if (t == TNL)9370 return NULL;9371 tokpushback++;9372 return list(1);9373 }9374 9375 9362 9376 9363 static union node * … … 9402 9389 if (n1 == NULL) { 9403 9390 n1 = n2; 9404 } 9405 else { 9406 n3 = (union node *)stalloc(sizeof (struct nbinary)); 9391 } else { 9392 n3 = stalloc(sizeof(struct nbinary)); 9407 9393 n3->type = NSEMI; 9408 9394 n3->nbinary.ch1 = n1; … … 9435 9421 default: 9436 9422 if (nlflag == 1) 9437 synexpect(-1);9423 raise_error_unexpected_syntax(-1); 9438 9424 tokpushback++; 9439 9425 return n1; … … 9442 9428 } 9443 9429 9444 9445 9446 9430 static union node * 9447 9431 andor(void) … … 9452 9436 n1 = pipeline(); 9453 9437 for (;;) { 9454 if ((t = readtoken()) == TAND) { 9438 t = readtoken(); 9439 if (t == TAND) { 9455 9440 t = NAND; 9456 9441 } else if (t == TOR) { … … 9462 9447 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9463 9448 n2 = pipeline(); 9464 n3 = (union node *)stalloc(sizeof(struct nbinary));9449 n3 = stalloc(sizeof(struct nbinary)); 9465 9450 n3->type = t; 9466 9451 n3->nbinary.ch1 = n1; … … 9469 9454 } 9470 9455 } 9471 9472 9473 9456 9474 9457 static union node * … … 9486 9469 } else 9487 9470 tokpushback++; 9488 n1 = command();9471 n1 = parse_command(); 9489 9472 if (readtoken() == TPIPE) { 9490 pipenode = (union node *)stalloc(sizeof(struct npipe));9473 pipenode = stalloc(sizeof(struct npipe)); 9491 9474 pipenode->type = NPIPE; 9492 9475 pipenode->npipe.backgnd = 0; 9493 lp = (struct nodelist *)stalloc(sizeof(struct nodelist));9476 lp = stalloc(sizeof(struct nodelist)); 9494 9477 pipenode->npipe.cmdlist = lp; 9495 9478 lp->n = n1; 9496 9479 do { 9497 9480 prev = lp; 9498 lp = (struct nodelist *)stalloc(sizeof(struct nodelist));9481 lp = stalloc(sizeof(struct nodelist)); 9499 9482 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9500 lp->n = command();9483 lp->n = parse_command(); 9501 9484 prev->next = lp; 9502 9485 } while (readtoken() == TPIPE); … … 9506 9489 tokpushback++; 9507 9490 if (negate) { 9508 n2 = (union node *)stalloc(sizeof(struct nnot));9491 n2 = stalloc(sizeof(struct nnot)); 9509 9492 n2->type = NNOT; 9510 9493 n2->nnot.com = n1; 9511 9494 return n2; 9512 } else 9513 return n1; 9514 } 9515 9516 9495 } 9496 return n1; 9497 } 9517 9498 9518 9499 static union node * 9519 command(void) 9520 { 9521 union node *n1, *n2; 9522 union node *ap, **app; 9523 union node *cp, **cpp; 9524 union node *redir, **rpp; 9525 union node **rpp2; 9526 int t; 9527 9528 redir = NULL; 9529 rpp2 = &redir; 9530 9531 switch (readtoken()) { 9532 default: 9533 synexpect(-1); 9534 /* NOTREACHED */ 9535 case TIF: 9536 n1 = (union node *)stalloc(sizeof (struct nif)); 9537 n1->type = NIF; 9538 n1->nif.test = list(0); 9539 if (readtoken() != TTHEN) 9540 synexpect(TTHEN); 9541 n1->nif.ifpart = list(0); 9542 n2 = n1; 9543 while (readtoken() == TELIF) { 9544 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 9545 n2 = n2->nif.elsepart; 9546 n2->type = NIF; 9547 n2->nif.test = list(0); 9548 if (readtoken() != TTHEN) 9549 synexpect(TTHEN); 9550 n2->nif.ifpart = list(0); 9551 } 9552 if (lasttoken == TELSE) 9553 n2->nif.elsepart = list(0); 9500 makename(void) 9501 { 9502 union node *n; 9503 9504 n = stalloc(sizeof(struct narg)); 9505 n->type = NARG; 9506 n->narg.next = NULL; 9507 n->narg.text = wordtext; 9508 n->narg.backquote = backquotelist; 9509 return n; 9510 } 9511 9512 static void 9513 fixredir(union node *n, const char *text, int err) 9514 { 9515 TRACE(("Fix redir %s %d\n", text, err)); 9516 if (!err) 9517 n->ndup.vname = NULL; 9518 9519 if (isdigit(text[0]) && text[1] == '\0') 9520 n->ndup.dupfd = text[0] - '0'; 9521 else if (LONE_DASH(text)) 9522 n->ndup.dupfd = -1; 9523 else { 9524 if (err) 9525 raise_error_syntax("Bad fd number"); 9526 n->ndup.vname = makename(); 9527 } 9528 } 9529 9530 /* 9531 * Returns true if the text contains nothing to expand (no dollar signs 9532 * or backquotes). 9533 */ 9534 static int 9535 noexpand(char *text) 9536 { 9537 char *p; 9538 char c; 9539 9540 p = text; 9541 while ((c = *p++) != '\0') { 9542 if (c == CTLQUOTEMARK) 9543 continue; 9544 if (c == CTLESC) 9545 p++; 9546 else if (SIT(c, BASESYNTAX) == CCTL) 9547 return 0; 9548 } 9549 return 1; 9550 } 9551 9552 static void 9553 parsefname(void) 9554 { 9555 union node *n = redirnode; 9556 9557 if (readtoken() != TWORD) 9558 raise_error_unexpected_syntax(-1); 9559 if (n->type == NHERE) { 9560 struct heredoc *here = heredoc; 9561 struct heredoc *p; 9562 int i; 9563 9564 if (quoteflag == 0) 9565 n->type = NXHERE; 9566 TRACE(("Here document %d\n", n->type)); 9567 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9568 raise_error_syntax("Illegal eof marker for << redirection"); 9569 rmescapes(wordtext); 9570 here->eofmark = wordtext; 9571 here->next = NULL; 9572 if (heredoclist == NULL) 9573 heredoclist = here; 9554 9574 else { 9555 n2->nif.elsepart = NULL; 9556 tokpushback++; 9557 } 9558 t = TFI; 9559 break; 9560 case TWHILE: 9561 case TUNTIL: { 9562 int got; 9563 n1 = (union node *)stalloc(sizeof (struct nbinary)); 9564 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 9565 n1->nbinary.ch1 = list(0); 9566 if ((got=readtoken()) != TDO) { 9567 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : "")); 9568 synexpect(TDO); 9569 } 9570 n1->nbinary.ch2 = list(0); 9571 t = TDONE; 9572 break; 9573 } 9574 case TFOR: 9575 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 9576 synerror("Bad for loop variable"); 9577 n1 = (union node *)stalloc(sizeof (struct nfor)); 9578 n1->type = NFOR; 9579 n1->nfor.var = wordtext; 9580 checkkwd = CHKKWD | CHKALIAS; 9581 if (readtoken() == TIN) { 9582 app = ≈ 9583 while (readtoken() == TWORD) { 9584 n2 = (union node *)stalloc(sizeof (struct narg)); 9585 n2->type = NARG; 9586 n2->narg.text = wordtext; 9587 n2->narg.backquote = backquotelist; 9588 *app = n2; 9589 app = &n2->narg.next; 9590 } 9591 *app = NULL; 9592 n1->nfor.args = ap; 9593 if (lasttoken != TNL && lasttoken != TSEMI) 9594 synexpect(-1); 9595 } else { 9596 n2 = (union node *)stalloc(sizeof (struct narg)); 9597 n2->type = NARG; 9598 n2->narg.text = (char *)dolatstr; 9599 n2->narg.backquote = NULL; 9600 n2->narg.next = NULL; 9601 n1->nfor.args = n2; 9602 /* 9603 * Newline or semicolon here is optional (but note 9604 * that the original Bourne shell only allowed NL). 9605 */ 9606 if (lasttoken != TNL && lasttoken != TSEMI) 9607 tokpushback++; 9608 } 9609 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9610 if (readtoken() != TDO) 9611 synexpect(TDO); 9612 n1->nfor.body = list(0); 9613 t = TDONE; 9614 break; 9615 case TCASE: 9616 n1 = (union node *)stalloc(sizeof (struct ncase)); 9617 n1->type = NCASE; 9618 if (readtoken() != TWORD) 9619 synexpect(TWORD); 9620 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 9621 n2->type = NARG; 9622 n2->narg.text = wordtext; 9623 n2->narg.backquote = backquotelist; 9624 n2->narg.next = NULL; 9625 do { 9626 checkkwd = CHKKWD | CHKALIAS; 9627 } while (readtoken() == TNL); 9628 if (lasttoken != TIN) 9629 synexpect(TIN); 9630 cpp = &n1->ncase.cases; 9631 next_case: 9632 checkkwd = CHKNL | CHKKWD; 9633 t = readtoken(); 9634 while(t != TESAC) { 9635 if (lasttoken == TLP) 9636 readtoken(); 9637 *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 9638 cp->type = NCLIST; 9639 app = &cp->nclist.pattern; 9640 for (;;) { 9641 *app = ap = (union node *)stalloc(sizeof (struct narg)); 9642 ap->type = NARG; 9643 ap->narg.text = wordtext; 9644 ap->narg.backquote = backquotelist; 9645 if (readtoken() != TPIPE) 9646 break; 9647 app = &ap->narg.next; 9648 readtoken(); 9649 } 9650 ap->narg.next = NULL; 9651 if (lasttoken != TRP) 9652 synexpect(TRP); 9653 cp->nclist.body = list(2); 9654 9655 cpp = &cp->nclist.next; 9656 9657 checkkwd = CHKNL | CHKKWD; 9658 if ((t = readtoken()) != TESAC) { 9659 if (t != TENDCASE) 9660 synexpect(TENDCASE); 9661 else 9662 goto next_case; 9663 } 9664 } 9665 *cpp = NULL; 9666 goto redir; 9667 case TLP: 9668 n1 = (union node *)stalloc(sizeof (struct nredir)); 9669 n1->type = NSUBSHELL; 9670 n1->nredir.n = list(0); 9671 n1->nredir.redirect = NULL; 9672 t = TRP; 9673 break; 9674 case TBEGIN: 9675 n1 = list(0); 9676 t = TEND; 9677 break; 9678 case TWORD: 9679 case TREDIR: 9680 tokpushback++; 9681 return simplecmd(); 9682 } 9683 9684 if (readtoken() != t) 9685 synexpect(t); 9686 9687 redir: 9688 /* Now check for redirection which may follow command */ 9689 checkkwd = CHKKWD | CHKALIAS; 9690 rpp = rpp2; 9691 while (readtoken() == TREDIR) { 9692 *rpp = n2 = redirnode; 9693 rpp = &n2->nfile.next; 9694 parsefname(); 9695 } 9696 tokpushback++; 9697 *rpp = NULL; 9698 if (redir) { 9699 if (n1->type != NSUBSHELL) { 9700 n2 = (union node *)stalloc(sizeof (struct nredir)); 9701 n2->type = NREDIR; 9702 n2->nredir.n = n1; 9703 n1 = n2; 9704 } 9705 n1->nredir.redirect = redir; 9706 } 9707 9708 return n1; 9709 } 9710 9575 for (p = heredoclist; p->next; p = p->next); 9576 p->next = here; 9577 } 9578 } else if (n->type == NTOFD || n->type == NFROMFD) { 9579 fixredir(n, wordtext, 0); 9580 } else { 9581 n->nfile.fname = makename(); 9582 } 9583 } 9711 9584 9712 9585 static union node * 9713 simplecmd(void) { 9586 simplecmd(void) 9587 { 9714 9588 union node *args, **app; 9715 9589 union node *n = NULL; … … 9730 9604 switch (readtoken()) { 9731 9605 case TWORD: 9732 n = (union node *)stalloc(sizeof(struct narg));9606 n = stalloc(sizeof(struct narg)); 9733 9607 n->type = NARG; 9734 9608 n->narg.text = wordtext; … … 9749 9623 break; 9750 9624 case TLP: 9751 if ( 9752 args && app == &args->narg.next && 9753 !vars && !redir 9625 if (args && app == &args->narg.next 9626 && !vars && !redir 9754 9627 ) { 9755 9628 struct builtincmd *bcmd; … … 9758 9631 /* We have a function */ 9759 9632 if (readtoken() != TRP) 9760 synexpect(TRP);9633 raise_error_unexpected_syntax(TRP); 9761 9634 name = n->narg.text; 9762 if ( 9763 !goodname(name) || ( 9764 (bcmd = find_builtin(name)) && 9765 IS_BUILTIN_SPECIAL(bcmd) 9766 ) 9767 ) 9768 synerror("Bad function name"); 9635 if (!goodname(name) 9636 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) 9637 ) { 9638 raise_error_syntax("Bad function name"); 9639 } 9769 9640 n->type = NDEFUN; 9770 9641 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9771 n->narg.next = command();9642 n->narg.next = parse_command(); 9772 9643 return n; 9773 9644 } … … 9778 9649 } 9779 9650 } 9780 out:9651 out: 9781 9652 *app = NULL; 9782 9653 *vpp = NULL; 9783 9654 *rpp = NULL; 9784 n = (union node *)stalloc(sizeof(struct ncmd));9655 n = stalloc(sizeof(struct ncmd)); 9785 9656 n->type = NCMD; 9786 9657 n->ncmd.args = args; … … 9791 9662 9792 9663 static union node * 9793 makename(void) 9794 { 9795 union node *n; 9796 9797 n = (union node *)stalloc(sizeof (struct narg)); 9798 n->type = NARG; 9799 n->narg.next = NULL; 9800 n->narg.text = wordtext; 9801 n->narg.backquote = backquotelist; 9802 return n; 9803 } 9804 9805 void fixredir(union node *n, const char *text, int err) 9806 { 9807 TRACE(("Fix redir %s %d\n", text, err)); 9808 if (!err) 9809 n->ndup.vname = NULL; 9810 9811 if (is_digit(text[0]) && text[1] == '\0') 9812 n->ndup.dupfd = digit_val(text[0]); 9813 else if (text[0] == '-' && text[1] == '\0') 9814 n->ndup.dupfd = -1; 9815 else { 9816 9817 if (err) 9818 synerror("Bad fd number"); 9819 else 9820 n->ndup.vname = makename(); 9821 } 9822 } 9823 9824 9825 static void 9826 parsefname(void) 9827 { 9828 union node *n = redirnode; 9829 9830 if (readtoken() != TWORD) 9831 synexpect(-1); 9832 if (n->type == NHERE) { 9833 struct heredoc *here = heredoc; 9834 struct heredoc *p; 9835 int i; 9836 9837 if (quoteflag == 0) 9838 n->type = NXHERE; 9839 TRACE(("Here document %d\n", n->type)); 9840 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9841 synerror("Illegal eof marker for << redirection"); 9842 rmescapes(wordtext); 9843 here->eofmark = wordtext; 9844 here->next = NULL; 9845 if (heredoclist == NULL) 9846 heredoclist = here; 9664 parse_command(void) 9665 { 9666 union node *n1, *n2; 9667 union node *ap, **app; 9668 union node *cp, **cpp; 9669 union node *redir, **rpp; 9670 union node **rpp2; 9671 int t; 9672 9673 redir = NULL; 9674 rpp2 = &redir; 9675 9676 switch (readtoken()) { 9677 default: 9678 raise_error_unexpected_syntax(-1); 9679 /* NOTREACHED */ 9680 case TIF: 9681 n1 = stalloc(sizeof(struct nif)); 9682 n1->type = NIF; 9683 n1->nif.test = list(0); 9684 if (readtoken() != TTHEN) 9685 raise_error_unexpected_syntax(TTHEN); 9686 n1->nif.ifpart = list(0); 9687 n2 = n1; 9688 while (readtoken() == TELIF) { 9689 n2->nif.elsepart = stalloc(sizeof(struct nif)); 9690 n2 = n2->nif.elsepart; 9691 n2->type = NIF; 9692 n2->nif.test = list(0); 9693 if (readtoken() != TTHEN) 9694 raise_error_unexpected_syntax(TTHEN); 9695 n2->nif.ifpart = list(0); 9696 } 9697 if (lasttoken == TELSE) 9698 n2->nif.elsepart = list(0); 9847 9699 else { 9848 for (p = heredoclist ; p->next ; p = p->next); 9849 p->next = here; 9850 } 9851 } else if (n->type == NTOFD || n->type == NFROMFD) { 9852 fixredir(n, wordtext, 0); 9853 } else { 9854 n->nfile.fname = makename(); 9855 } 9856 } 9857 9858 9859 /* 9860 * Input any here documents. 9861 */ 9862 9863 static void 9864 parseheredoc(void) 9865 { 9866 struct heredoc *here; 9867 union node *n; 9868 9869 here = heredoclist; 9870 heredoclist = 0; 9871 9872 while (here) { 9873 if (needprompt) { 9874 setprompt(2); 9875 } 9876 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 9877 here->eofmark, here->striptabs); 9878 n = (union node *)stalloc(sizeof (struct narg)); 9879 n->narg.type = NARG; 9880 n->narg.next = NULL; 9881 n->narg.text = wordtext; 9882 n->narg.backquote = backquotelist; 9883 here->here->nhere.doc = n; 9884 here = here->next; 9885 } 9886 } 9887 9888 static char peektoken(void) 9889 { 9890 int t; 9891 9892 t = readtoken(); 9700 n2->nif.elsepart = NULL; 9701 tokpushback++; 9702 } 9703 t = TFI; 9704 break; 9705 case TWHILE: 9706 case TUNTIL: { 9707 int got; 9708 n1 = stalloc(sizeof(struct nbinary)); 9709 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL; 9710 n1->nbinary.ch1 = list(0); 9711 got = readtoken(); 9712 if (got != TDO) { 9713 TRACE(("expecting DO got %s %s\n", tokname(got), 9714 got == TWORD ? wordtext : "")); 9715 raise_error_unexpected_syntax(TDO); 9716 } 9717 n1->nbinary.ch2 = list(0); 9718 t = TDONE; 9719 break; 9720 } 9721 case TFOR: 9722 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 9723 raise_error_syntax("Bad for loop variable"); 9724 n1 = stalloc(sizeof(struct nfor)); 9725 n1->type = NFOR; 9726 n1->nfor.var = wordtext; 9727 checkkwd = CHKKWD | CHKALIAS; 9728 if (readtoken() == TIN) { 9729 app = ≈ 9730 while (readtoken() == TWORD) { 9731 n2 = stalloc(sizeof(struct narg)); 9732 n2->type = NARG; 9733 n2->narg.text = wordtext; 9734 n2->narg.backquote = backquotelist; 9735 *app = n2; 9736 app = &n2->narg.next; 9737 } 9738 *app = NULL; 9739 n1->nfor.args = ap; 9740 if (lasttoken != TNL && lasttoken != TSEMI) 9741 raise_error_unexpected_syntax(-1); 9742 } else { 9743 n2 = stalloc(sizeof(struct narg)); 9744 n2->type = NARG; 9745 n2->narg.text = (char *)dolatstr; 9746 n2->narg.backquote = NULL; 9747 n2->narg.next = NULL; 9748 n1->nfor.args = n2; 9749 /* 9750 * Newline or semicolon here is optional (but note 9751 * that the original Bourne shell only allowed NL). 9752 */ 9753 if (lasttoken != TNL && lasttoken != TSEMI) 9754 tokpushback++; 9755 } 9756 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9757 if (readtoken() != TDO) 9758 raise_error_unexpected_syntax(TDO); 9759 n1->nfor.body = list(0); 9760 t = TDONE; 9761 break; 9762 case TCASE: 9763 n1 = stalloc(sizeof(struct ncase)); 9764 n1->type = NCASE; 9765 if (readtoken() != TWORD) 9766 raise_error_unexpected_syntax(TWORD); 9767 n1->ncase.expr = n2 = stalloc(sizeof(struct narg)); 9768 n2->type = NARG; 9769 n2->narg.text = wordtext; 9770 n2->narg.backquote = backquotelist; 9771 n2->narg.next = NULL; 9772 do { 9773 checkkwd = CHKKWD | CHKALIAS; 9774 } while (readtoken() == TNL); 9775 if (lasttoken != TIN) 9776 raise_error_unexpected_syntax(TIN); 9777 cpp = &n1->ncase.cases; 9778 next_case: 9779 checkkwd = CHKNL | CHKKWD; 9780 t = readtoken(); 9781 while (t != TESAC) { 9782 if (lasttoken == TLP) 9783 readtoken(); 9784 *cpp = cp = stalloc(sizeof(struct nclist)); 9785 cp->type = NCLIST; 9786 app = &cp->nclist.pattern; 9787 for (;;) { 9788 *app = ap = stalloc(sizeof(struct narg)); 9789 ap->type = NARG; 9790 ap->narg.text = wordtext; 9791 ap->narg.backquote = backquotelist; 9792 if (readtoken() != TPIPE) 9793 break; 9794 app = &ap->narg.next; 9795 readtoken(); 9796 } 9797 ap->narg.next = NULL; 9798 if (lasttoken != TRP) 9799 raise_error_unexpected_syntax(TRP); 9800 cp->nclist.body = list(2); 9801 9802 cpp = &cp->nclist.next; 9803 9804 checkkwd = CHKNL | CHKKWD; 9805 t = readtoken(); 9806 if (t != TESAC) { 9807 if (t != TENDCASE) 9808 raise_error_unexpected_syntax(TENDCASE); 9809 goto next_case; 9810 } 9811 } 9812 *cpp = NULL; 9813 goto redir; 9814 case TLP: 9815 n1 = stalloc(sizeof(struct nredir)); 9816 n1->type = NSUBSHELL; 9817 n1->nredir.n = list(0); 9818 n1->nredir.redirect = NULL; 9819 t = TRP; 9820 break; 9821 case TBEGIN: 9822 n1 = list(0); 9823 t = TEND; 9824 break; 9825 case TWORD: 9826 case TREDIR: 9827 tokpushback++; 9828 return simplecmd(); 9829 } 9830 9831 if (readtoken() != t) 9832 raise_error_unexpected_syntax(t); 9833 9834 redir: 9835 /* Now check for redirection which may follow command */ 9836 checkkwd = CHKKWD | CHKALIAS; 9837 rpp = rpp2; 9838 while (readtoken() == TREDIR) { 9839 *rpp = n2 = redirnode; 9840 rpp = &n2->nfile.next; 9841 parsefname(); 9842 } 9893 9843 tokpushback++; 9894 return tokname_array[t][0]; 9895 } 9896 9897 static int 9898 readtoken(void) 9899 { 9900 int t; 9901 #ifdef DEBUG 9902 int alreadyseen = tokpushback; 9903 #endif 9904 9905 #ifdef CONFIG_ASH_ALIAS 9906 top: 9907 #endif 9908 9909 t = xxreadtoken(); 9910 9911 /* 9912 * eat newlines 9913 */ 9914 if (checkkwd & CHKNL) { 9915 while (t == TNL) { 9916 parseheredoc(); 9917 t = xxreadtoken(); 9918 } 9919 } 9920 9921 if (t != TWORD || quoteflag) { 9922 goto out; 9923 } 9924 9925 /* 9926 * check for keywords 9927 */ 9928 if (checkkwd & CHKKWD) { 9929 const char *const *pp; 9930 9931 if ((pp = findkwd(wordtext))) { 9932 lasttoken = t = pp - tokname_array; 9933 TRACE(("keyword %s recognized\n", tokname(t))); 9934 goto out; 9935 } 9936 } 9937 9938 if (checkkwd & CHKALIAS) { 9939 #ifdef CONFIG_ASH_ALIAS 9940 struct alias *ap; 9941 if ((ap = lookupalias(wordtext, 1)) != NULL) { 9942 if (*ap->val) { 9943 pushstring(ap->val, ap); 9944 } 9945 goto top; 9946 } 9947 #endif 9948 } 9949 out: 9950 checkkwd = 0; 9951 #ifdef DEBUG 9952 if (!alreadyseen) 9953 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 9954 else 9955 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 9956 #endif 9957 return (t); 9958 } 9959 9960 9961 /* 9962 * Read the next input token. 9963 * If the token is a word, we set backquotelist to the list of cmds in 9964 * backquotes. We set quoteflag to true if any part of the word was 9965 * quoted. 9966 * If the token is TREDIR, then we set redirnode to a structure containing 9967 * the redirection. 9968 * In all cases, the variable startlinno is set to the number of the line 9969 * on which the token starts. 9970 * 9971 * [Change comment: here documents and internal procedures] 9972 * [Readtoken shouldn't have any arguments. Perhaps we should make the 9973 * word parsing code into a separate routine. In this case, readtoken 9974 * doesn't need to have any internal procedures, but parseword does. 9975 * We could also make parseoperator in essence the main routine, and 9976 * have parseword (readtoken1?) handle both words and redirection.] 9977 */ 9978 9979 #define NEW_xxreadtoken 9980 #ifdef NEW_xxreadtoken 9981 9982 /* singles must be first! */ 9983 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 }; 9984 9985 static const char xxreadtoken_tokens[] = { 9986 TNL, TLP, TRP, /* only single occurrence allowed */ 9987 TBACKGND, TPIPE, TSEMI, /* if single occurrence */ 9988 TEOF, /* corresponds to trailing nul */ 9989 TAND, TOR, TENDCASE, /* if double occurrence */ 9990 }; 9991 9992 #define xxreadtoken_doubles \ 9993 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars)) 9994 #define xxreadtoken_singles \ 9995 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1) 9996 9997 static int xxreadtoken(void) 9998 { 9999 int c; 10000 10001 if (tokpushback) { 10002 tokpushback = 0; 10003 return lasttoken; 10004 } 10005 if (needprompt) { 10006 setprompt(2); 10007 } 10008 startlinno = plinno; 10009 for (;;) { /* until token or start of word found */ 10010 c = pgetc_macro(); 10011 10012 if ((c != ' ') && (c != '\t') 10013 #ifdef CONFIG_ASH_ALIAS 10014 && (c != PEOA) 10015 #endif 10016 ) { 10017 if (c == '#') { 10018 while ((c = pgetc()) != '\n' && c != PEOF); 10019 pungetc(); 10020 } else if (c == '\\') { 10021 if (pgetc() != '\n') { 10022 pungetc(); 10023 goto READTOKEN1; 10024 } 10025 startlinno = ++plinno; 10026 if (doprompt) 10027 setprompt(2); 10028 } else { 10029 const char *p 10030 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10031 10032 if (c != PEOF) { 10033 if (c == '\n') { 10034 plinno++; 10035 needprompt = doprompt; 10036 } 10037 10038 p = strchr(xxreadtoken_chars, c); 10039 if (p == NULL) { 10040 READTOKEN1: 10041 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10042 } 10043 10044 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10045 if (pgetc() == *p) { /* double occurrence? */ 10046 p += xxreadtoken_doubles + 1; 10047 } else { 10048 pungetc(); 10049 } 10050 } 10051 } 10052 10053 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 10054 } 10055 } 10056 } 10057 } 10058 10059 10060 #else 10061 #define RETURN(token) return lasttoken = token 10062 10063 static int 10064 xxreadtoken(void) 10065 { 10066 int c; 10067 10068 if (tokpushback) { 10069 tokpushback = 0; 10070 return lasttoken; 10071 } 10072 if (needprompt) { 10073 setprompt(2); 10074 } 10075 startlinno = plinno; 10076 for (;;) { /* until token or start of word found */ 10077 c = pgetc_macro(); 10078 switch (c) { 10079 case ' ': case '\t': 10080 #ifdef CONFIG_ASH_ALIAS 10081 case PEOA: 10082 #endif 10083 continue; 10084 case '#': 10085 while ((c = pgetc()) != '\n' && c != PEOF); 10086 pungetc(); 10087 continue; 10088 case '\\': 10089 if (pgetc() == '\n') { 10090 startlinno = ++plinno; 10091 if (doprompt) 10092 setprompt(2); 10093 continue; 10094 } 10095 pungetc(); 10096 goto breakloop; 10097 case '\n': 10098 plinno++; 10099 needprompt = doprompt; 10100 RETURN(TNL); 10101 case PEOF: 10102 RETURN(TEOF); 10103 case '&': 10104 if (pgetc() == '&') 10105 RETURN(TAND); 10106 pungetc(); 10107 RETURN(TBACKGND); 10108 case '|': 10109 if (pgetc() == '|') 10110 RETURN(TOR); 10111 pungetc(); 10112 RETURN(TPIPE); 10113 case ';': 10114 if (pgetc() == ';') 10115 RETURN(TENDCASE); 10116 pungetc(); 10117 RETURN(TSEMI); 10118 case '(': 10119 RETURN(TLP); 10120 case ')': 10121 RETURN(TRP); 10122 default: 10123 goto breakloop; 10124 } 10125 } 10126 breakloop: 10127 return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 10128 #undef RETURN 10129 } 10130 #endif /* NEW_xxreadtoken */ 10131 9844 *rpp = NULL; 9845 if (redir) { 9846 if (n1->type != NSUBSHELL) { 9847 n2 = stalloc(sizeof(struct nredir)); 9848 n2->type = NREDIR; 9849 n2->nredir.n = n1; 9850 n1 = n2; 9851 } 9852 n1->nredir.redirect = redir; 9853 } 9854 return n1; 9855 } 10132 9856 10133 9857 /* … … 10142 9866 * will run code that appears at the end of readtoken1. 10143 9867 */ 9868 9869 static int parsebackquote; /* nonzero if we are inside backquotes */ 10144 9870 10145 9871 #define CHECKEND() {goto checkend; checkend_return:;} … … 10196 9922 for (;;) { /* until end of line or end of word */ 10197 9923 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 10198 switch (SIT(c, syntax)) {9924 switch (SIT(c, syntax)) { 10199 9925 case CNL: /* '\n' */ 10200 9926 if (syntax == BASESYNTAX) … … 10241 9967 case CSQUOTE: 10242 9968 syntax = SQSYNTAX; 10243 quotemark:9969 quotemark: 10244 9970 if (eofmark == NULL) { 10245 9971 USTPUTC(CTLQUOTEMARK, out); … … 10251 9977 goto quotemark; 10252 9978 case CENDQUOTE: 10253 if (eofmark != NULL && arinest == 0 && 10254 varnest == 0) { 9979 if (eofmark != NULL && arinest == 0 9980 && varnest == 0 9981 ) { 10255 9982 USTPUTC(c, out); 10256 9983 } else { … … 10277 10004 } 10278 10005 break; 10279 #if def CONFIG_ASH_MATH_SUPPORT10006 #if ENABLE_ASH_MATH_SUPPORT 10280 10007 case CLP: /* '(' in arithmetic */ 10281 10008 parenlevel++; … … 10318 10045 if (varnest == 0) 10319 10046 goto endword; /* exit outer loop */ 10320 #if def CONFIG_ASH_ALIAS10047 #if ENABLE_ASH_ALIAS 10321 10048 if (c != PEOA) 10322 10049 #endif … … 10327 10054 } 10328 10055 } 10329 endword:10330 #if def CONFIG_ASH_MATH_SUPPORT10056 endword: 10057 #if ENABLE_ASH_MATH_SUPPORT 10331 10058 if (syntax == ARISYNTAX) 10332 synerror("Missing '))'");10333 #endif 10334 if (syntax != BASESYNTAX && ! 10335 synerror("Unterminated quoted string");10059 raise_error_syntax("Missing '))'"); 10060 #endif 10061 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10062 raise_error_syntax("Unterminated quoted string"); 10336 10063 if (varnest != 0) { 10337 10064 startlinno = plinno; 10338 10065 /* { */ 10339 synerror("Missing '}'");10066 raise_error_syntax("Missing '}'"); 10340 10067 } 10341 10068 USTPUTC('\0', out); … … 10346 10073 && quotef == 0 10347 10074 && len <= 2 10348 && (*out == '\0' || is _digit(*out))) {10075 && (*out == '\0' || isdigit(*out))) { 10349 10076 PARSEREDIR(); 10350 10077 return lasttoken = TREDIR; … … 10357 10084 grabstackblock(len); 10358 10085 wordtext = out; 10359 return lasttoken = TWORD; 10086 lasttoken = TWORD; 10087 return lasttoken; 10360 10088 /* end of readtoken routine */ 10361 10362 10363 10089 10364 10090 /* … … 10367 10093 * we are at the end of the here document, this routine sets the c to PEOF. 10368 10094 */ 10369 10370 10095 checkend: { 10371 10096 if (eofmark) { 10372 #if def CONFIG_ASH_ALIAS10097 #if ENABLE_ASH_ALIAS 10373 10098 if (c == PEOA) { 10374 10099 c = pgetc2(); … … 10381 10106 } 10382 10107 if (c == *eofmark) { 10383 if (pfgets(line, sizeof line) != NULL) {10108 if (pfgets(line, sizeof(line)) != NULL) { 10384 10109 char *p, *q; 10385 10110 10386 10111 p = line; 10387 for (q = eofmark + 1 ; *q && *p == *q; p++, q++);10112 for (q = eofmark + 1; *q && *p == *q; p++, q++); 10388 10113 if (*p == '\n' && *q == '\0') { 10389 10114 c = PEOF; … … 10399 10124 } 10400 10125 10401 10402 10126 /* 10403 10127 * Parse a redirection operator. The variable "out" points to a string … … 10405 10129 * first character of the redirection operator. 10406 10130 */ 10407 10408 10131 parseredir: { 10409 10132 char fd = *out; 10410 10133 union node *np; 10411 10134 10412 np = (union node *)stalloc(sizeof(struct nfile));10135 np = stalloc(sizeof(struct nfile)); 10413 10136 if (c == '>') { 10414 10137 np->nfile.fd = 1; … … 10426 10149 } else { /* c == '<' */ 10427 10150 np->nfile.fd = 0; 10428 switch (c = pgetc()) { 10151 c = pgetc(); 10152 switch (c) { 10429 10153 case '<': 10430 if (sizeof (struct nfile) != sizeof(struct nhere)) {10431 np = (union node *)stalloc(sizeof(struct nhere));10154 if (sizeof(struct nfile) != sizeof(struct nhere)) { 10155 np = stalloc(sizeof(struct nhere)); 10432 10156 np->nfile.fd = 0; 10433 10157 } 10434 10158 np->type = NHERE; 10435 heredoc = (struct heredoc *)stalloc(sizeof(struct heredoc));10159 heredoc = stalloc(sizeof(struct heredoc)); 10436 10160 heredoc->here = np; 10437 if ((c = pgetc()) == '-') { 10161 c = pgetc(); 10162 if (c == '-') { 10438 10163 heredoc->striptabs = 1; 10439 10164 } else { … … 10458 10183 } 10459 10184 if (fd != '\0') 10460 np->nfile.fd = digit_val(fd);10185 np->nfile.fd = fd - '0'; 10461 10186 redirnode = np; 10462 10187 goto parseredir_return; 10463 10188 } 10464 10189 10465 10466 10190 /* 10467 10191 * Parse a substitution. At this point, we have read the dollar sign … … 10469 10193 */ 10470 10194 10195 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise 10196 * (assuming ascii char codes, as the original implementation did) */ 10197 #define is_special(c) \ 10198 ((((unsigned int)c) - 33 < 32) \ 10199 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) 10471 10200 parsesub: { 10472 10201 int subtype; … … 10474 10203 int flags; 10475 10204 char *p; 10476 static const char types[] = "}-+?=";10205 static const char types[] ALIGN1 = "}-+?="; 10477 10206 10478 10207 c = pgetc(); … … 10485 10214 } else if (c == '(') { /* $(command) or $((arith)) */ 10486 10215 if (pgetc() == '(') { 10487 #if def CONFIG_ASH_MATH_SUPPORT10216 #if ENABLE_ASH_MATH_SUPPORT 10488 10217 PARSEARITH(); 10489 10218 #else 10490 synerror("We unsupport $((arith))");10219 raise_error_syntax("We unsupport $((arith))"); 10491 10220 #endif 10492 10221 } else { … … 10502 10231 c = pgetc(); 10503 10232 if (c == '#') { 10504 if ((c = pgetc()) == '}') 10233 c = pgetc(); 10234 if (c == '}') 10505 10235 c = '#'; 10506 10236 else 10507 10237 subtype = VSLENGTH; 10508 } 10509 else 10238 } else 10510 10239 subtype = 0; 10511 10240 } … … 10515 10244 c = pgetc(); 10516 10245 } while (c > PEOA_OR_PEOF && is_in_name(c)); 10517 } else if (is _digit(c)) {10246 } else if (isdigit(c)) { 10518 10247 do { 10519 10248 STPUTC(c, out); 10520 10249 c = pgetc(); 10521 } while (is_digit(c)); 10522 } 10523 else if (is_special(c)) { 10250 } while (isdigit(c)); 10251 } else if (is_special(c)) { 10524 10252 USTPUTC(c, out); 10525 10253 c = pgetc(); 10526 } 10527 else 10528 badsub: synerror("Bad substitution"); 10254 } else 10255 badsub: raise_error_syntax("Bad substitution"); 10529 10256 10530 10257 STPUTC('=', out); … … 10547 10274 int cc = c; 10548 10275 subtype = c == '#' ? VSTRIMLEFT : 10549 10276 VSTRIMRIGHT; 10550 10277 c = pgetc(); 10551 10278 if (c == cc) … … 10572 10299 } 10573 10300 10574 10575 10301 /* 10576 10302 * Called to parse command substitutions. Newstyle is set if the command … … 10579 10305 * characters on the top of the stack which must be preserved. 10580 10306 */ 10581 10582 10307 parsebackq: { 10583 10308 struct nodelist **nlpp; … … 10596 10321 if (setjmp(jmploc.loc)) { 10597 10322 if (str) 10598 ckfree(str);10323 free(str); 10599 10324 parsebackquote = 0; 10600 handler = savehandler;10601 longjmp( handler->loc, 1);10602 } 10603 INT OFF;10325 exception_handler = savehandler; 10326 longjmp(exception_handler->loc, 1); 10327 } 10328 INT_OFF; 10604 10329 str = NULL; 10605 10330 savelen = out - (char *)stackblock(); … … 10608 10333 memcpy(str, stackblock(), savelen); 10609 10334 } 10610 savehandler = handler;10611 handler = &jmploc;10612 INT ON;10335 savehandler = exception_handler; 10336 exception_handler = &jmploc; 10337 INT_ON; 10613 10338 if (oldstyle) { 10614 10339 /* We must read until the closing backquote, giving special … … 10626 10351 setprompt(2); 10627 10352 } 10628 switch (pc = pgetc()) { 10353 pc = pgetc(); 10354 switch (pc) { 10629 10355 case '`': 10630 10356 goto done; 10631 10357 10632 10358 case '\\': 10633 if ((pc = pgetc()) == '\n') { 10359 pc = pgetc(); 10360 if (pc == '\n') { 10634 10361 plinno++; 10635 10362 if (doprompt) … … 10644 10371 } 10645 10372 if (pc != '\\' && pc != '`' && pc != '$' 10646 10373 && (!dblquote || pc != '"')) 10647 10374 STPUTC('\\', pout); 10648 10375 if (pc > PEOA_OR_PEOF) { … … 10652 10379 10653 10380 case PEOF: 10654 #if def CONFIG_ASH_ALIAS10381 #if ENABLE_ASH_ALIAS 10655 10382 case PEOA: 10656 10383 #endif 10657 10384 startlinno = plinno; 10658 synerror("EOF in backquote substitution");10385 raise_error_syntax("EOF in backquote substitution"); 10659 10386 10660 10387 case '\n': … … 10668 10395 STPUTC(pc, pout); 10669 10396 } 10670 done:10397 done: 10671 10398 STPUTC('\0', pout); 10672 10399 psavelen = pout - (char *)stackblock(); … … 10679 10406 while (*nlpp) 10680 10407 nlpp = &(*nlpp)->next; 10681 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));10408 *nlpp = stalloc(sizeof(**nlpp)); 10682 10409 (*nlpp)->next = NULL; 10683 10410 parsebackquote = oldstyle; … … 10692 10419 if (oldstyle) 10693 10420 doprompt = saveprompt; 10694 else { 10695 if (readtoken() != TRP) 10696 synexpect(TRP); 10697 } 10421 else if (readtoken() != TRP) 10422 raise_error_unexpected_syntax(TRP); 10698 10423 10699 10424 (*nlpp)->n = n; … … 10712 10437 memcpy(out, str, savelen); 10713 10438 STADJUST(savelen, out); 10714 INT OFF;10715 ckfree(str);10439 INT_OFF; 10440 free(str); 10716 10441 str = NULL; 10717 INT ON;10442 INT_ON; 10718 10443 } 10719 10444 parsebackquote = savepbq; 10720 handler = savehandler;10445 exception_handler = savehandler; 10721 10446 if (arinest || dblquote) 10722 10447 USTPUTC(CTLBACKQ | CTLQUOTE, out); … … 10725 10450 if (oldstyle) 10726 10451 goto parsebackq_oldreturn; 10727 else 10728 goto parsebackq_newreturn; 10729 } 10730 10731 #ifdef CONFIG_ASH_MATH_SUPPORT 10452 goto parsebackq_newreturn; 10453 } 10454 10455 #if ENABLE_ASH_MATH_SUPPORT 10732 10456 /* 10733 10457 * Parse an arithmetic expansion (indicate start of one and set state) 10734 10458 */ 10735 10459 parsearith: { 10736 10737 10460 if (++arinest == 1) { 10738 10461 prevsyntax = syntax; … … 10740 10463 USTPUTC(CTLARI, out); 10741 10464 if (dblquote) 10742 USTPUTC('"', out);10465 USTPUTC('"', out); 10743 10466 else 10744 USTPUTC(' ', out);10467 USTPUTC(' ', out); 10745 10468 } else { 10746 10469 /* … … 10756 10479 } /* end of readtoken */ 10757 10480 10758 10759 10760 /* 10761 * Returns true if the text contains nothing to expand (no dollar signs 10762 * or backquotes). 10763 */ 10481 /* 10482 * Read the next input token. 10483 * If the token is a word, we set backquotelist to the list of cmds in 10484 * backquotes. We set quoteflag to true if any part of the word was 10485 * quoted. 10486 * If the token is TREDIR, then we set redirnode to a structure containing 10487 * the redirection. 10488 * In all cases, the variable startlinno is set to the number of the line 10489 * on which the token starts. 10490 * 10491 * [Change comment: here documents and internal procedures] 10492 * [Readtoken shouldn't have any arguments. Perhaps we should make the 10493 * word parsing code into a separate routine. In this case, readtoken 10494 * doesn't need to have any internal procedures, but parseword does. 10495 * We could also make parseoperator in essence the main routine, and 10496 * have parseword (readtoken1?) handle both words and redirection.] 10497 */ 10498 #define NEW_xxreadtoken 10499 #ifdef NEW_xxreadtoken 10500 /* singles must be first! */ 10501 static const char xxreadtoken_chars[7] ALIGN1 = { 10502 '\n', '(', ')', '&', '|', ';', 0 10503 }; 10504 10505 static const char xxreadtoken_tokens[] ALIGN1 = { 10506 TNL, TLP, TRP, /* only single occurrence allowed */ 10507 TBACKGND, TPIPE, TSEMI, /* if single occurrence */ 10508 TEOF, /* corresponds to trailing nul */ 10509 TAND, TOR, TENDCASE /* if double occurrence */ 10510 }; 10511 10512 #define xxreadtoken_doubles \ 10513 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars)) 10514 #define xxreadtoken_singles \ 10515 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1) 10764 10516 10765 10517 static int 10766 noexpand(char *text) 10767 { 10768 char *p; 10769 char c; 10770 10771 p = text; 10772 while ((c = *p++) != '\0') { 10773 if (c == CTLQUOTEMARK) 10518 xxreadtoken(void) 10519 { 10520 int c; 10521 10522 if (tokpushback) { 10523 tokpushback = 0; 10524 return lasttoken; 10525 } 10526 if (needprompt) { 10527 setprompt(2); 10528 } 10529 startlinno = plinno; 10530 for (;;) { /* until token or start of word found */ 10531 c = pgetc_macro(); 10532 10533 if ((c != ' ') && (c != '\t') 10534 #if ENABLE_ASH_ALIAS 10535 && (c != PEOA) 10536 #endif 10537 ) { 10538 if (c == '#') { 10539 while ((c = pgetc()) != '\n' && c != PEOF); 10540 pungetc(); 10541 } else if (c == '\\') { 10542 if (pgetc() != '\n') { 10543 pungetc(); 10544 goto READTOKEN1; 10545 } 10546 startlinno = ++plinno; 10547 if (doprompt) 10548 setprompt(2); 10549 } else { 10550 const char *p 10551 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10552 10553 if (c != PEOF) { 10554 if (c == '\n') { 10555 plinno++; 10556 needprompt = doprompt; 10557 } 10558 10559 p = strchr(xxreadtoken_chars, c); 10560 if (p == NULL) { 10561 READTOKEN1: 10562 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10563 } 10564 10565 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10566 if (pgetc() == *p) { /* double occurrence? */ 10567 p += xxreadtoken_doubles + 1; 10568 } else { 10569 pungetc(); 10570 } 10571 } 10572 } 10573 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 10574 } 10575 } 10576 } /* for */ 10577 } 10578 #else 10579 #define RETURN(token) return lasttoken = token 10580 static int 10581 xxreadtoken(void) 10582 { 10583 int c; 10584 10585 if (tokpushback) { 10586 tokpushback = 0; 10587 return lasttoken; 10588 } 10589 if (needprompt) { 10590 setprompt(2); 10591 } 10592 startlinno = plinno; 10593 for (;;) { /* until token or start of word found */ 10594 c = pgetc_macro(); 10595 switch (c) { 10596 case ' ': case '\t': 10597 #if ENABLE_ASH_ALIAS 10598 case PEOA: 10599 #endif 10774 10600 continue; 10775 if (c == CTLESC) 10776 p++; 10777 else if (SIT(c, BASESYNTAX) == CCTL) 10778 return 0; 10779 } 10780 return 1; 10781 } 10782 10783 10784 /* 10785 * Return of a legal variable name (a letter or underscore followed by zero or 10786 * more letters, underscores, and digits). 10787 */ 10788 10789 static char * 10790 endofname(const char *name) 10791 { 10792 char *p; 10793 10794 p = (char *) name; 10795 if (! is_name(*p)) 10796 return p; 10797 while (*++p) { 10798 if (! is_in_name(*p)) 10799 break; 10800 } 10801 return p; 10802 } 10803 10804 10805 /* 10806 * Called when an unexpected token is read during the parse. The argument 10807 * is the token that is expected, or -1 if more than one type of token can 10808 * occur at this point. 10809 */ 10810 10811 static void synexpect(int token) 10812 { 10813 char msg[64]; 10814 int l; 10815 10816 l = sprintf(msg, "%s unexpected", tokname(lasttoken)); 10817 if (token >= 0) 10818 sprintf(msg + l, " (expecting %s)", tokname(token)); 10819 synerror(msg); 10820 /* NOTREACHED */ 10821 } 10822 10823 static void 10824 synerror(const char *msg) 10825 { 10826 sh_error("Syntax error: %s", msg); 10827 /* NOTREACHED */ 10828 } 10829 10830 10831 /* 10832 * called by editline -- any expansions to the prompt 10833 * should be added here. 10834 */ 10835 10836 #ifdef CONFIG_ASH_EXPAND_PRMT 10601 case '#': 10602 while ((c = pgetc()) != '\n' && c != PEOF); 10603 pungetc(); 10604 continue; 10605 case '\\': 10606 if (pgetc() == '\n') { 10607 startlinno = ++plinno; 10608 if (doprompt) 10609 setprompt(2); 10610 continue; 10611 } 10612 pungetc(); 10613 goto breakloop; 10614 case '\n': 10615 plinno++; 10616 needprompt = doprompt; 10617 RETURN(TNL); 10618 case PEOF: 10619 RETURN(TEOF); 10620 case '&': 10621 if (pgetc() == '&') 10622 RETURN(TAND); 10623 pungetc(); 10624 RETURN(TBACKGND); 10625 case '|': 10626 if (pgetc() == '|') 10627 RETURN(TOR); 10628 pungetc(); 10629 RETURN(TPIPE); 10630 case ';': 10631 if (pgetc() == ';') 10632 RETURN(TENDCASE); 10633 pungetc(); 10634 RETURN(TSEMI); 10635 case '(': 10636 RETURN(TLP); 10637 case ')': 10638 RETURN(TRP); 10639 default: 10640 goto breakloop; 10641 } 10642 } 10643 breakloop: 10644 return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 10645 #undef RETURN 10646 } 10647 #endif /* NEW_xxreadtoken */ 10648 10649 static int 10650 readtoken(void) 10651 { 10652 int t; 10653 #if DEBUG 10654 int alreadyseen = tokpushback; 10655 #endif 10656 10657 #if ENABLE_ASH_ALIAS 10658 top: 10659 #endif 10660 10661 t = xxreadtoken(); 10662 10663 /* 10664 * eat newlines 10665 */ 10666 if (checkkwd & CHKNL) { 10667 while (t == TNL) { 10668 parseheredoc(); 10669 t = xxreadtoken(); 10670 } 10671 } 10672 10673 if (t != TWORD || quoteflag) { 10674 goto out; 10675 } 10676 10677 /* 10678 * check for keywords 10679 */ 10680 if (checkkwd & CHKKWD) { 10681 const char *const *pp; 10682 10683 pp = findkwd(wordtext); 10684 if (pp) { 10685 lasttoken = t = pp - tokname_array; 10686 TRACE(("keyword %s recognized\n", tokname(t))); 10687 goto out; 10688 } 10689 } 10690 10691 if (checkkwd & CHKALIAS) { 10692 #if ENABLE_ASH_ALIAS 10693 struct alias *ap; 10694 ap = lookupalias(wordtext, 1); 10695 if (ap != NULL) { 10696 if (*ap->val) { 10697 pushstring(ap->val, ap); 10698 } 10699 goto top; 10700 } 10701 #endif 10702 } 10703 out: 10704 checkkwd = 0; 10705 #if DEBUG 10706 if (!alreadyseen) 10707 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 10708 else 10709 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 10710 #endif 10711 return t; 10712 } 10713 10714 static char 10715 peektoken(void) 10716 { 10717 int t; 10718 10719 t = readtoken(); 10720 tokpushback++; 10721 return tokname_array[t][0]; 10722 } 10723 10724 /* 10725 * Read and parse a command. Returns NEOF on end of file. (NULL is a 10726 * valid parse tree indicating a blank line.) 10727 */ 10728 static union node * 10729 parsecmd(int interact) 10730 { 10731 int t; 10732 10733 tokpushback = 0; 10734 doprompt = interact; 10735 if (doprompt) 10736 setprompt(doprompt); 10737 needprompt = 0; 10738 t = readtoken(); 10739 if (t == TEOF) 10740 return NEOF; 10741 if (t == TNL) 10742 return NULL; 10743 tokpushback++; 10744 return list(1); 10745 } 10746 10747 /* 10748 * Input any here documents. 10749 */ 10750 static void 10751 parseheredoc(void) 10752 { 10753 struct heredoc *here; 10754 union node *n; 10755 10756 here = heredoclist; 10757 heredoclist = 0; 10758 10759 while (here) { 10760 if (needprompt) { 10761 setprompt(2); 10762 } 10763 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 10764 here->eofmark, here->striptabs); 10765 n = stalloc(sizeof(struct narg)); 10766 n->narg.type = NARG; 10767 n->narg.next = NULL; 10768 n->narg.text = wordtext; 10769 n->narg.backquote = backquotelist; 10770 here->here->nhere.doc = n; 10771 here = here->next; 10772 } 10773 } 10774 10775 10776 /* 10777 * called by editline -- any expansions to the prompt should be added here. 10778 */ 10779 #if ENABLE_ASH_EXPAND_PRMT 10837 10780 static const char * 10838 10781 expandstr(const char *ps) … … 10855 10798 #endif 10856 10799 10857 static void setprompt(int whichprompt) 10858 { 10859 const char *prompt; 10860 #ifdef CONFIG_ASH_EXPAND_PRMT 10800 /* 10801 * Execute a command or commands contained in a string. 10802 */ 10803 static int 10804 evalstring(char *s, int mask) 10805 { 10806 union node *n; 10861 10807 struct stackmark smark; 10862 #endif 10863 10864 needprompt = 0; 10865 10866 switch (whichprompt) { 10867 case 1: 10868 prompt = ps1val(); 10869 break; 10870 case 2: 10871 prompt = ps2val(); 10872 break; 10873 default: /* 0 */ 10874 prompt = nullstr; 10875 } 10876 #ifdef CONFIG_ASH_EXPAND_PRMT 10808 int skip; 10809 10810 setinputstring(s); 10877 10811 setstackmark(&smark); 10878 stalloc(stackblocksize()); 10879 #endif 10880 putprompt(expandstr(prompt)); 10881 #ifdef CONFIG_ASH_EXPAND_PRMT 10882 popstackmark(&smark); 10883 #endif 10884 } 10885 10886 10887 static const char *const *findkwd(const char *s) 10888 { 10889 return bsearch(s, tokname_array + KWDOFFSET, 10890 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET, 10891 sizeof(const char *), pstrcmp); 10892 } 10893 10894 /* redir.c */ 10895 10896 /* 10897 * Code for dealing with input/output redirection. 10898 */ 10899 10900 #define EMPTY -2 /* marks an unused slot in redirtab */ 10901 #ifndef PIPE_BUF 10902 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 10903 #else 10904 # define PIPESIZE PIPE_BUF 10905 #endif 10906 10907 /* 10908 * Open a file in noclobber mode. 10909 * The code was copied from bash. 10910 */ 10911 static inline int 10912 noclobberopen(const char *fname) 10913 { 10914 int r, fd; 10915 struct stat finfo, finfo2; 10916 10917 /* 10918 * If the file exists and is a regular file, return an error 10919 * immediately. 10920 */ 10921 r = stat(fname, &finfo); 10922 if (r == 0 && S_ISREG(finfo.st_mode)) { 10923 errno = EEXIST; 10924 return -1; 10925 } 10926 10927 /* 10928 * If the file was not present (r != 0), make sure we open it 10929 * exclusively so that if it is created before we open it, our open 10930 * will fail. Make sure that we do not truncate an existing file. 10931 * Note that we don't turn on O_EXCL unless the stat failed -- if the 10932 * file was not a regular file, we leave O_EXCL off. 10933 */ 10934 if (r != 0) 10935 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); 10936 fd = open(fname, O_WRONLY|O_CREAT, 0666); 10937 10938 /* If the open failed, return the file descriptor right away. */ 10939 if (fd < 0) 10940 return fd; 10941 10942 /* 10943 * OK, the open succeeded, but the file may have been changed from a 10944 * non-regular file to a regular file between the stat and the open. 10945 * We are assuming that the O_EXCL open handles the case where FILENAME 10946 * did not exist and is symlinked to an existing file between the stat 10947 * and open. 10948 */ 10949 10950 /* 10951 * If we can open it and fstat the file descriptor, and neither check 10952 * revealed that it was a regular file, and the file has not been 10953 * replaced, return the file descriptor. 10954 */ 10955 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && 10956 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 10957 return fd; 10958 10959 /* The file has been replaced. badness. */ 10960 close(fd); 10961 errno = EEXIST; 10962 return -1; 10963 } 10964 10965 /* 10966 * Handle here documents. Normally we fork off a process to write the 10967 * data to a pipe. If the document is short, we can stuff the data in 10968 * the pipe without forking. 10969 */ 10970 10971 static inline int 10972 openhere(union node *redir) 10973 { 10974 int pip[2]; 10975 size_t len = 0; 10976 10977 if (pipe(pip) < 0) 10978 sh_error("Pipe call failed"); 10979 if (redir->type == NHERE) { 10980 len = strlen(redir->nhere.doc->narg.text); 10981 if (len <= PIPESIZE) { 10982 bb_full_write(pip[1], redir->nhere.doc->narg.text, len); 10983 goto out; 10984 } 10985 } 10986 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 10987 close(pip[0]); 10988 signal(SIGINT, SIG_IGN); 10989 signal(SIGQUIT, SIG_IGN); 10990 signal(SIGHUP, SIG_IGN); 10991 #ifdef SIGTSTP 10992 signal(SIGTSTP, SIG_IGN); 10993 #endif 10994 signal(SIGPIPE, SIG_DFL); 10995 if (redir->type == NHERE) 10996 bb_full_write(pip[1], redir->nhere.doc->narg.text, len); 10812 10813 skip = 0; 10814 while ((n = parsecmd(0)) != NEOF) { 10815 evaltree(n, 0); 10816 popstackmark(&smark); 10817 skip = evalskip; 10818 if (skip) 10819 break; 10820 } 10821 popfile(); 10822 10823 skip &= mask; 10824 evalskip = skip; 10825 return skip; 10826 } 10827 10828 /* 10829 * The eval command. 10830 */ 10831 static int 10832 evalcmd(int argc, char **argv) 10833 { 10834 char *p; 10835 char *concat; 10836 char **ap; 10837 10838 if (argc > 1) { 10839 p = argv[1]; 10840 if (argc > 2) { 10841 STARTSTACKSTR(concat); 10842 ap = argv + 2; 10843 for (;;) { 10844 concat = stack_putstr(p, concat); 10845 p = *ap++; 10846 if (p == NULL) 10847 break; 10848 STPUTC(' ', concat); 10849 } 10850 STPUTC('\0', concat); 10851 p = grabstackstr(concat); 10852 } 10853 evalstring(p, ~SKIPEVAL); 10854 10855 } 10856 return exitstatus; 10857 } 10858 10859 /* 10860 * Read and execute commands. "Top" is nonzero for the top level command 10861 * loop; it turns on prompting if the shell is interactive. 10862 */ 10863 static int 10864 cmdloop(int top) 10865 { 10866 union node *n; 10867 struct stackmark smark; 10868 int inter; 10869 int numeof = 0; 10870 10871 TRACE(("cmdloop(%d) called\n", top)); 10872 for (;;) { 10873 int skip; 10874 10875 setstackmark(&smark); 10876 #if JOBS 10877 if (jobctl) 10878 showjobs(stderr, SHOW_CHANGED); 10879 #endif 10880 inter = 0; 10881 if (iflag && top) { 10882 inter++; 10883 #if ENABLE_ASH_MAIL 10884 chkmail(); 10885 #endif 10886 } 10887 n = parsecmd(inter); 10888 /* showtree(n); DEBUG */ 10889 if (n == NEOF) { 10890 if (!top || numeof >= 50) 10891 break; 10892 if (!stoppedjobs()) { 10893 if (!Iflag) 10894 break; 10895 out2str("\nUse \"exit\" to leave shell.\n"); 10896 } 10897 numeof++; 10898 } else if (nflag == 0) { 10899 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ 10900 job_warning >>= 1; 10901 numeof = 0; 10902 evaltree(n, 0); 10903 } 10904 popstackmark(&smark); 10905 skip = evalskip; 10906 10907 if (skip) { 10908 evalskip = 0; 10909 return skip & SKIPEVAL; 10910 } 10911 } 10912 return 0; 10913 } 10914 10915 /* 10916 * Take commands from a file. To be compatible we should do a path 10917 * search for the file, which is necessary to find sub-commands. 10918 */ 10919 static char * 10920 find_dot_file(char *name) 10921 { 10922 char *fullname; 10923 const char *path = pathval(); 10924 struct stat statb; 10925 10926 /* don't try this for absolute or relative paths */ 10927 if (strchr(name, '/')) 10928 return name; 10929 10930 while ((fullname = padvance(&path, name)) != NULL) { 10931 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 10932 /* 10933 * Don't bother freeing here, since it will 10934 * be freed by the caller. 10935 */ 10936 return fullname; 10937 } 10938 stunalloc(fullname); 10939 } 10940 10941 /* not found in the PATH */ 10942 ash_msg_and_raise_error("%s: not found", name); 10943 /* NOTREACHED */ 10944 } 10945 10946 static int 10947 dotcmd(int argc, char **argv) 10948 { 10949 struct strlist *sp; 10950 volatile struct shparam saveparam; 10951 int status = 0; 10952 10953 for (sp = cmdenviron; sp; sp = sp->next) 10954 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 10955 10956 if (argc >= 2) { /* That's what SVR2 does */ 10957 char *fullname; 10958 10959 fullname = find_dot_file(argv[1]); 10960 10961 if (argc > 2) { 10962 saveparam = shellparam; 10963 shellparam.malloc = 0; 10964 shellparam.nparam = argc - 2; 10965 shellparam.p = argv + 2; 10966 }; 10967 10968 setinputfile(fullname, INPUT_PUSH_FILE); 10969 commandname = fullname; 10970 cmdloop(0); 10971 popfile(); 10972 10973 if (argc > 2) { 10974 freeparam(&shellparam); 10975 shellparam = saveparam; 10976 }; 10977 status = exitstatus; 10978 } 10979 return status; 10980 } 10981 10982 static int 10983 exitcmd(int argc, char **argv) 10984 { 10985 if (stoppedjobs()) 10986 return 0; 10987 if (argc > 1) 10988 exitstatus = number(argv[1]); 10989 raise_exception(EXEXIT); 10990 /* NOTREACHED */ 10991 } 10992 10993 #if ENABLE_ASH_BUILTIN_ECHO 10994 static int 10995 echocmd(int argc, char **argv) 10996 { 10997 return bb_echo(argv); 10998 } 10999 #endif 11000 11001 #if ENABLE_ASH_BUILTIN_TEST 11002 static int 11003 testcmd(int argc, char **argv) 11004 { 11005 return test_main(argc, argv); 11006 } 11007 #endif 11008 11009 /* 11010 * Read a file containing shell functions. 11011 */ 11012 static void 11013 readcmdfile(char *name) 11014 { 11015 setinputfile(name, INPUT_PUSH_FILE); 11016 cmdloop(0); 11017 popfile(); 11018 } 11019 11020 11021 /* ============ find_command inplementation */ 11022 11023 /* 11024 * Resolve a command name. If you change this routine, you may have to 11025 * change the shellexec routine as well. 11026 */ 11027 static void 11028 find_command(char *name, struct cmdentry *entry, int act, const char *path) 11029 { 11030 struct tblentry *cmdp; 11031 int idx; 11032 int prev; 11033 char *fullname; 11034 struct stat statb; 11035 int e; 11036 int updatetbl; 11037 struct builtincmd *bcmd; 11038 11039 /* If name contains a slash, don't use PATH or hash table */ 11040 if (strchr(name, '/') != NULL) { 11041 entry->u.index = -1; 11042 if (act & DO_ABS) { 11043 while (stat(name, &statb) < 0) { 11044 #ifdef SYSV 11045 if (errno == EINTR) 11046 continue; 11047 #endif 11048 entry->cmdtype = CMDUNKNOWN; 11049 return; 11050 } 11051 } 11052 entry->cmdtype = CMDNORMAL; 11053 return; 11054 } 11055 11056 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 11057 11058 updatetbl = (path == pathval()); 11059 if (!updatetbl) { 11060 act |= DO_ALTPATH; 11061 if (strstr(path, "%builtin") != NULL) 11062 act |= DO_ALTBLTIN; 11063 } 11064 11065 /* If name is in the table, check answer will be ok */ 11066 cmdp = cmdlookup(name, 0); 11067 if (cmdp != NULL) { 11068 int bit; 11069 11070 switch (cmdp->cmdtype) { 11071 default: 11072 #if DEBUG 11073 abort(); 11074 #endif 11075 case CMDNORMAL: 11076 bit = DO_ALTPATH; 11077 break; 11078 case CMDFUNCTION: 11079 bit = DO_NOFUNC; 11080 break; 11081 case CMDBUILTIN: 11082 bit = DO_ALTBLTIN; 11083 break; 11084 } 11085 if (act & bit) { 11086 updatetbl = 0; 11087 cmdp = NULL; 11088 } else if (cmdp->rehash == 0) 11089 /* if not invalidated by cd, we're done */ 11090 goto success; 11091 } 11092 11093 /* If %builtin not in path, check for builtin next */ 11094 bcmd = find_builtin(name); 11095 if (bcmd) { 11096 if (IS_BUILTIN_REGULAR(bcmd)) 11097 goto builtin_success; 11098 if (act & DO_ALTPATH) { 11099 if (!(act & DO_ALTBLTIN)) 11100 goto builtin_success; 11101 } else if (builtinloc <= 0) { 11102 goto builtin_success; 11103 } 11104 } 11105 11106 #if ENABLE_FEATURE_SH_STANDALONE 11107 if (find_applet_by_name(name)) { 11108 entry->cmdtype = CMDNORMAL; 11109 entry->u.index = -1; 11110 return; 11111 } 11112 #endif 11113 11114 /* We have to search path. */ 11115 prev = -1; /* where to start */ 11116 if (cmdp && cmdp->rehash) { /* doing a rehash */ 11117 if (cmdp->cmdtype == CMDBUILTIN) 11118 prev = builtinloc; 10997 11119 else 10998 expandhere(redir->nhere.doc, pip[1]); 10999 _exit(0); 11000 } 11001 out: 11002 close(pip[1]); 11003 return pip[0]; 11004 } 11005 11120 prev = cmdp->param.index; 11121 } 11122 11123 e = ENOENT; 11124 idx = -1; 11125 loop: 11126 while ((fullname = padvance(&path, name)) != NULL) { 11127 stunalloc(fullname); 11128 /* NB: code below will still use fullname 11129 * despite it being "unallocated" */ 11130 idx++; 11131 if (pathopt) { 11132 if (prefix(pathopt, "builtin")) { 11133 if (bcmd) 11134 goto builtin_success; 11135 continue; 11136 } else if (!(act & DO_NOFUNC) 11137 && prefix(pathopt, "func")) { 11138 /* handled below */ 11139 } else { 11140 /* ignore unimplemented options */ 11141 continue; 11142 } 11143 } 11144 /* if rehash, don't redo absolute path names */ 11145 if (fullname[0] == '/' && idx <= prev) { 11146 if (idx < prev) 11147 continue; 11148 TRACE(("searchexec \"%s\": no change\n", name)); 11149 goto success; 11150 } 11151 while (stat(fullname, &statb) < 0) { 11152 #ifdef SYSV 11153 if (errno == EINTR) 11154 continue; 11155 #endif 11156 if (errno != ENOENT && errno != ENOTDIR) 11157 e = errno; 11158 goto loop; 11159 } 11160 e = EACCES; /* if we fail, this will be the error */ 11161 if (!S_ISREG(statb.st_mode)) 11162 continue; 11163 if (pathopt) { /* this is a %func directory */ 11164 stalloc(strlen(fullname) + 1); 11165 /* NB: stalloc will return space pointed by fullname 11166 * (because we don't have any intervening allocations 11167 * between stunalloc above and this stalloc) */ 11168 readcmdfile(fullname); 11169 cmdp = cmdlookup(name, 0); 11170 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION) 11171 ash_msg_and_raise_error("%s not defined in %s", name, fullname); 11172 stunalloc(fullname); 11173 goto success; 11174 } 11175 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 11176 if (!updatetbl) { 11177 entry->cmdtype = CMDNORMAL; 11178 entry->u.index = idx; 11179 return; 11180 } 11181 INT_OFF; 11182 cmdp = cmdlookup(name, 1); 11183 cmdp->cmdtype = CMDNORMAL; 11184 cmdp->param.index = idx; 11185 INT_ON; 11186 goto success; 11187 } 11188 11189 /* We failed. If there was an entry for this command, delete it */ 11190 if (cmdp && updatetbl) 11191 delete_cmd_entry(); 11192 if (act & DO_ERR) 11193 ash_msg("%s: %s", name, errmsg(e, "not found")); 11194 entry->cmdtype = CMDUNKNOWN; 11195 return; 11196 11197 builtin_success: 11198 if (!updatetbl) { 11199 entry->cmdtype = CMDBUILTIN; 11200 entry->u.cmd = bcmd; 11201 return; 11202 } 11203 INT_OFF; 11204 cmdp = cmdlookup(name, 1); 11205 cmdp->cmdtype = CMDBUILTIN; 11206 cmdp->param.cmd = bcmd; 11207 INT_ON; 11208 success: 11209 cmdp->rehash = 0; 11210 entry->cmdtype = cmdp->cmdtype; 11211 entry->u = cmdp->param; 11212 } 11213 11214 11215 /* ============ trap.c */ 11216 11217 /* 11218 * The trap builtin. 11219 */ 11006 11220 static int 11007 openredirect(union node *redir)11008 {11009 char *fname;11010 int f;11011 11012 switch (redir->nfile.type) {11013 case NFROM:11014 fname = redir->nfile.expfname;11015 if ((f = open(fname, O_RDONLY)) < 0)11016 goto eopen;11017 break;11018 case NFROMTO:11019 fname = redir->nfile.expfname;11020 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)11021 goto ecreate;11022 break;11023 case NTO:11024 /* Take care of noclobber mode. */11025 if (Cflag) {11026 fname = redir->nfile.expfname;11027 if ((f = noclobberopen(fname)) < 0)11028 goto ecreate;11029 break;11030 }11031 /* FALLTHROUGH */11032 case NCLOBBER:11033 fname = redir->nfile.expfname;11034 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)11035 goto ecreate;11036 break;11037 case NAPPEND:11038 fname = redir->nfile.expfname;11039 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)11040 goto ecreate;11041 break;11042 default:11043 #ifdef DEBUG11044 abort();11045 #endif11046 /* Fall through to eliminate warning. */11047 case NTOFD:11048 case NFROMFD:11049 f = -1;11050 break;11051 case NHERE:11052 case NXHERE:11053 f = openhere(redir);11054 break;11055 }11056 11057 return f;11058 ecreate:11059 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));11060 eopen:11061 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));11062 }11063 11064 static inline void11065 dupredirect(union node *redir, int f)11066 {11067 int fd = redir->nfile.fd;11068 11069 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {11070 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */11071 copyfd(redir->ndup.dupfd, fd);11072 }11073 return;11074 }11075 11076 if (f != fd) {11077 copyfd(f, fd);11078 close(f);11079 }11080 return;11081 }11082 11083 /*11084 * Process a list of redirection commands. If the REDIR_PUSH flag is set,11085 * old file descriptors are stashed away so that the redirection can be11086 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the11087 * standard output, and the standard error if it becomes a duplicate of11088 * stdout, is saved in memory.11089 */11090 11091 static void11092 redirect(union node *redir, int flags)11093 {11094 union node *n;11095 struct redirtab *sv;11096 int i;11097 int fd;11098 int newfd;11099 int *p;11100 nullredirs++;11101 if (!redir) {11102 return;11103 }11104 sv = NULL;11105 INTOFF;11106 if (flags & REDIR_PUSH) {11107 struct redirtab *q;11108 q = ckmalloc(sizeof (struct redirtab));11109 q->next = redirlist;11110 redirlist = q;11111 q->nullredirs = nullredirs - 1;11112 for (i = 0 ; i < 10 ; i++)11113 q->renamed[i] = EMPTY;11114 nullredirs = 0;11115 sv = q;11116 }11117 n = redir;11118 do {11119 fd = n->nfile.fd;11120 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&11121 n->ndup.dupfd == fd)11122 continue; /* redirect from/to same file descriptor */11123 11124 newfd = openredirect(n);11125 if (fd == newfd)11126 continue;11127 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {11128 i = fcntl(fd, F_DUPFD, 10);11129 11130 if (i == -1) {11131 i = errno;11132 if (i != EBADF) {11133 close(newfd);11134 errno = i;11135 sh_error("%d: %m", fd);11136 /* NOTREACHED */11137 }11138 } else {11139 *p = i;11140 close(fd);11141 }11142 } else {11143 close(fd);11144 }11145 dupredirect(n, newfd);11146 } while ((n = n->nfile.next));11147 INTON;11148 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)11149 preverrout_fd = sv->renamed[2];11150 }11151 11152 11153 /*11154 * Undo the effects of the last redirection.11155 */11156 11157 void11158 popredir(int drop)11159 {11160 struct redirtab *rp;11161 int i;11162 11163 if (--nullredirs >= 0)11164 return;11165 INTOFF;11166 rp = redirlist;11167 for (i = 0 ; i < 10 ; i++) {11168 if (rp->renamed[i] != EMPTY) {11169 if (!drop) {11170 close(i);11171 copyfd(rp->renamed[i], i);11172 }11173 close(rp->renamed[i]);11174 }11175 }11176 redirlist = rp->next;11177 nullredirs = rp->nullredirs;11178 ckfree(rp);11179 INTON;11180 }11181 11182 /*11183 * Undo all redirections. Called on error or interrupt.11184 */11185 11186 /*11187 * Discard all saved file descriptors.11188 */11189 11190 void11191 clearredir(int drop)11192 {11193 for (;;) {11194 nullredirs = 0;11195 if (!redirlist)11196 break;11197 popredir(drop);11198 }11199 }11200 11201 11202 /*11203 * Copy a file descriptor to be >= to. Returns -111204 * if the source file descriptor is closed, EMPTY if there are no unused11205 * file descriptors left.11206 */11207 11208 int11209 copyfd(int from, int to)11210 {11211 int newfd;11212 11213 newfd = fcntl(from, F_DUPFD, to);11214 if (newfd < 0) {11215 if (errno == EMFILE)11216 return EMPTY;11217 else11218 sh_error("%d: %m", from);11219 }11220 return newfd;11221 }11222 11223 11224 int11225 redirectsafe(union node *redir, int flags)11226 {11227 int err;11228 volatile int saveint;11229 struct jmploc *volatile savehandler = handler;11230 struct jmploc jmploc;11231 11232 SAVEINT(saveint);11233 if (!(err = setjmp(jmploc.loc) * 2)) {11234 handler = &jmploc;11235 redirect(redir, flags);11236 }11237 handler = savehandler;11238 if (err && exception != EXERROR)11239 longjmp(handler->loc, 1);11240 RESTOREINT(saveint);11241 return err;11242 }11243 11244 /* show.c */11245 11246 #ifdef DEBUG11247 static void shtree(union node *, int, char *, FILE*);11248 static void shcmd(union node *, FILE *);11249 static void sharg(union node *, FILE *);11250 static void indent(int, char *, FILE *);11251 static void trstring(char *);11252 11253 11254 void11255 showtree(union node *n)11256 {11257 trputs("showtree called\n");11258 shtree(n, 1, NULL, stdout);11259 }11260 11261 11262 static void11263 shtree(union node *n, int ind, char *pfx, FILE *fp)11264 {11265 struct nodelist *lp;11266 const char *s;11267 11268 if (n == NULL)11269 return;11270 11271 indent(ind, pfx, fp);11272 switch(n->type) {11273 case NSEMI:11274 s = "; ";11275 goto binop;11276 case NAND:11277 s = " && ";11278 goto binop;11279 case NOR:11280 s = " || ";11281 binop:11282 shtree(n->nbinary.ch1, ind, NULL, fp);11283 /* if (ind < 0) */11284 fputs(s, fp);11285 shtree(n->nbinary.ch2, ind, NULL, fp);11286 break;11287 case NCMD:11288 shcmd(n, fp);11289 if (ind >= 0)11290 putc('\n', fp);11291 break;11292 case NPIPE:11293 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {11294 shcmd(lp->n, fp);11295 if (lp->next)11296 fputs(" | ", fp);11297 }11298 if (n->npipe.backgnd)11299 fputs(" &", fp);11300 if (ind >= 0)11301 putc('\n', fp);11302 break;11303 default:11304 fprintf(fp, "<node type %d>", n->type);11305 if (ind >= 0)11306 putc('\n', fp);11307 break;11308 }11309 }11310 11311 11312 static void11313 shcmd(union node *cmd, FILE *fp)11314 {11315 union node *np;11316 int first;11317 const char *s;11318 int dftfd;11319 11320 first = 1;11321 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {11322 if (! first)11323 putchar(' ');11324 sharg(np, fp);11325 first = 0;11326 }11327 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {11328 if (! first)11329 putchar(' ');11330 switch (np->nfile.type) {11331 case NTO: s = ">"; dftfd = 1; break;11332 case NCLOBBER: s = ">|"; dftfd = 1; break;11333 case NAPPEND: s = ">>"; dftfd = 1; break;11334 case NTOFD: s = ">&"; dftfd = 1; break;11335 case NFROM: s = "<"; dftfd = 0; break;11336 case NFROMFD: s = "<&"; dftfd = 0; break;11337 case NFROMTO: s = "<>"; dftfd = 0; break;11338 default: s = "*error*"; dftfd = 0; break;11339 }11340 if (np->nfile.fd != dftfd)11341 fprintf(fp, "%d", np->nfile.fd);11342 fputs(s, fp);11343 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {11344 fprintf(fp, "%d", np->ndup.dupfd);11345 } else {11346 sharg(np->nfile.fname, fp);11347 }11348 first = 0;11349 }11350 }11351 11352 11353 11354 static void11355 sharg(union node *arg, FILE *fp)11356 {11357 char *p;11358 struct nodelist *bqlist;11359 int subtype;11360 11361 if (arg->type != NARG) {11362 out1fmt("<node type %d>\n", arg->type);11363 abort();11364 }11365 bqlist = arg->narg.backquote;11366 for (p = arg->narg.text ; *p ; p++) {11367 switch (*p) {11368 case CTLESC:11369 putc(*++p, fp);11370 break;11371 case CTLVAR:11372 putc('$', fp);11373 putc('{', fp);11374 subtype = *++p;11375 if (subtype == VSLENGTH)11376 putc('#', fp);11377 11378 while (*p != '=')11379 putc(*p++, fp);11380 11381 if (subtype & VSNUL)11382 putc(':', fp);11383 11384 switch (subtype & VSTYPE) {11385 case VSNORMAL:11386 putc('}', fp);11387 break;11388 case VSMINUS:11389 putc('-', fp);11390 break;11391 case VSPLUS:11392 putc('+', fp);11393 break;11394 case VSQUESTION:11395 putc('?', fp);11396 break;11397 case VSASSIGN:11398 putc('=', fp);11399 break;11400 case VSTRIMLEFT:11401 putc('#', fp);11402 break;11403 case VSTRIMLEFTMAX:11404 putc('#', fp);11405 putc('#', fp);11406 break;11407 case VSTRIMRIGHT:11408 putc('%', fp);11409 break;11410 case VSTRIMRIGHTMAX:11411 putc('%', fp);11412 putc('%', fp);11413 break;11414 case VSLENGTH:11415 break;11416 default:11417 out1fmt("<subtype %d>", subtype);11418 }11419 break;11420 case CTLENDVAR:11421 putc('}', fp);11422 break;11423 case CTLBACKQ:11424 case CTLBACKQ|CTLQUOTE:11425 putc('$', fp);11426 putc('(', fp);11427 shtree(bqlist->n, -1, NULL, fp);11428 putc(')', fp);11429 break;11430 default:11431 putc(*p, fp);11432 break;11433 }11434 }11435 }11436 11437 11438 static void11439 indent(int amount, char *pfx, FILE *fp)11440 {11441 int i;11442 11443 for (i = 0 ; i < amount ; i++) {11444 if (pfx && i == amount - 1)11445 fputs(pfx, fp);11446 putc('\t', fp);11447 }11448 }11449 11450 11451 11452 /*11453 * Debugging stuff.11454 */11455 11456 11457 FILE *tracefile;11458 11459 11460 void11461 trputc(int c)11462 {11463 if (debug != 1)11464 return;11465 putc(c, tracefile);11466 }11467 11468 void11469 trace(const char *fmt, ...)11470 {11471 va_list va;11472 11473 if (debug != 1)11474 return;11475 va_start(va, fmt);11476 (void) vfprintf(tracefile, fmt, va);11477 va_end(va);11478 }11479 11480 void11481 tracev(const char *fmt, va_list va)11482 {11483 if (debug != 1)11484 return;11485 (void) vfprintf(tracefile, fmt, va);11486 }11487 11488 11489 void11490 trputs(const char *s)11491 {11492 if (debug != 1)11493 return;11494 fputs(s, tracefile);11495 }11496 11497 11498 static void11499 trstring(char *s)11500 {11501 char *p;11502 char c;11503 11504 if (debug != 1)11505 return;11506 putc('"', tracefile);11507 for (p = s ; *p ; p++) {11508 switch (*p) {11509 case '\n': c = 'n'; goto backslash;11510 case '\t': c = 't'; goto backslash;11511 case '\r': c = 'r'; goto backslash;11512 case '"': c = '"'; goto backslash;11513 case '\\': c = '\\'; goto backslash;11514 case CTLESC: c = 'e'; goto backslash;11515 case CTLVAR: c = 'v'; goto backslash;11516 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;11517 case CTLBACKQ: c = 'q'; goto backslash;11518 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;11519 backslash: putc('\\', tracefile);11520 putc(c, tracefile);11521 break;11522 default:11523 if (*p >= ' ' && *p <= '~')11524 putc(*p, tracefile);11525 else {11526 putc('\\', tracefile);11527 putc(*p >> 6 & 03, tracefile);11528 putc(*p >> 3 & 07, tracefile);11529 putc(*p & 07, tracefile);11530 }11531 break;11532 }11533 }11534 putc('"', tracefile);11535 }11536 11537 11538 void11539 trargs(char **ap)11540 {11541 if (debug != 1)11542 return;11543 while (*ap) {11544 trstring(*ap++);11545 if (*ap)11546 putc(' ', tracefile);11547 else11548 putc('\n', tracefile);11549 }11550 }11551 11552 11553 void11554 opentrace(void)11555 {11556 char s[100];11557 #ifdef O_APPEND11558 int flags;11559 #endif11560 11561 if (debug != 1) {11562 if (tracefile)11563 fflush(tracefile);11564 /* leave open because libedit might be using it */11565 return;11566 }11567 scopy("./trace", s);11568 if (tracefile) {11569 if (!freopen(s, "a", tracefile)) {11570 fprintf(stderr, "Can't re-open %s\n", s);11571 debug = 0;11572 return;11573 }11574 } else {11575 if ((tracefile = fopen(s, "a")) == NULL) {11576 fprintf(stderr, "Can't open %s\n", s);11577 debug = 0;11578 return;11579 }11580 }11581 #ifdef O_APPEND11582 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)11583 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);11584 #endif11585 setlinebuf(tracefile);11586 fputs("\nTracing started.\n", tracefile);11587 }11588 #endif /* DEBUG */11589 11590 11591 /* trap.c */11592 11593 /*11594 * Sigmode records the current value of the signal handlers for the various11595 * modes. A value of zero means that the current handler is not known.11596 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,11597 */11598 11599 #define S_DFL 1 /* default signal handling (SIG_DFL) */11600 #define S_CATCH 2 /* signal is caught */11601 #define S_IGN 3 /* signal is ignored (SIG_IGN) */11602 #define S_HARD_IGN 4 /* signal is ignored permenantly */11603 #define S_RESET 5 /* temporary - to reset a hard ignored sig */11604 11605 11606 11607 /*11608 * The trap builtin.11609 */11610 11611 int11612 11221 trapcmd(int argc, char **argv) 11613 11222 { … … 11619 11228 ap = argptr; 11620 11229 if (!*ap) { 11621 for (signo = 0 ; signo < NSIG; signo++) {11230 for (signo = 0; signo < NSIG; signo++) { 11622 11231 if (trap[signo] != NULL) { 11623 11232 const char *sn; 11624 11233 11625 sn = u_signal_names(0, &signo, 0); 11626 if (sn == NULL) 11627 sn = "???"; 11234 sn = get_signame(signo); 11628 11235 out1fmt("trap -- %s %s\n", 11629 11236 single_quote(trap[signo]), sn); … … 11637 11244 action = *ap++; 11638 11245 while (*ap) { 11639 if ((signo = decode_signal(*ap, 0)) < 0) 11640 sh_error("%s: bad trap", *ap); 11641 INTOFF; 11246 signo = get_signum(*ap); 11247 if (signo < 0) 11248 ash_msg_and_raise_error("%s: bad trap", *ap); 11249 INT_OFF; 11642 11250 if (action) { 11643 if ( action[0] == '-' && action[1] == '\0')11251 if (LONE_DASH(action)) 11644 11252 action = NULL; 11645 11253 else 11646 action = savestr(action);11254 action = ckstrdup(action); 11647 11255 } 11648 11256 if (trap[signo]) 11649 ckfree(trap[signo]);11257 free(trap[signo]); 11650 11258 trap[signo] = action; 11651 11259 if (signo != 0) 11652 11260 setsignal(signo); 11653 INT ON;11261 INT_ON; 11654 11262 ap++; 11655 11263 } … … 11658 11266 11659 11267 11660 /* 11661 * Clear traps on a fork. 11662 */ 11663 11664 void 11665 clear_traps(void) 11666 { 11667 char **tp; 11668 11669 for (tp = trap ; tp < &trap[NSIG] ; tp++) { 11670 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 11671 INTOFF; 11672 ckfree(*tp); 11673 *tp = NULL; 11674 if (tp != &trap[0]) 11675 setsignal(tp - trap); 11676 INTON; 11677 } 11678 } 11679 } 11680 11681 11682 /* 11683 * Set the signal handler for the specified signal. The routine figures 11684 * out what it should be set to. 11685 */ 11686 11687 void 11688 setsignal(int signo) 11689 { 11690 int action; 11691 char *t, tsig; 11692 struct sigaction act; 11693 11694 if ((t = trap[signo]) == NULL) 11695 action = S_DFL; 11696 else if (*t != '\0') 11697 action = S_CATCH; 11698 else 11699 action = S_IGN; 11700 if (rootshell && action == S_DFL) { 11701 switch (signo) { 11702 case SIGINT: 11703 if (iflag || minusc || sflag == 0) 11704 action = S_CATCH; 11705 break; 11706 case SIGQUIT: 11707 #ifdef DEBUG 11708 if (debug) 11709 break; 11710 #endif 11711 /* FALLTHROUGH */ 11712 case SIGTERM: 11713 if (iflag) 11714 action = S_IGN; 11715 break; 11716 #if JOBS 11717 case SIGTSTP: 11718 case SIGTTOU: 11719 if (mflag) 11720 action = S_IGN; 11721 break; 11722 #endif 11723 } 11724 } 11725 11726 t = &sigmode[signo - 1]; 11727 tsig = *t; 11728 if (tsig == 0) { 11729 /* 11730 * current setting unknown 11731 */ 11732 if (sigaction(signo, 0, &act) == -1) { 11733 /* 11734 * Pretend it worked; maybe we should give a warning 11735 * here, but other shells don't. We don't alter 11736 * sigmode, so that we retry every time. 11737 */ 11738 return; 11739 } 11740 if (act.sa_handler == SIG_IGN) { 11741 if (mflag && (signo == SIGTSTP || 11742 signo == SIGTTIN || signo == SIGTTOU)) { 11743 tsig = S_IGN; /* don't hard ignore these */ 11744 } else 11745 tsig = S_HARD_IGN; 11746 } else { 11747 tsig = S_RESET; /* force to be set */ 11748 } 11749 } 11750 if (tsig == S_HARD_IGN || tsig == action) 11751 return; 11752 switch (action) { 11753 case S_CATCH: 11754 act.sa_handler = onsig; 11755 break; 11756 case S_IGN: 11757 act.sa_handler = SIG_IGN; 11758 break; 11759 default: 11760 act.sa_handler = SIG_DFL; 11761 } 11762 *t = action; 11763 act.sa_flags = 0; 11764 sigfillset(&act.sa_mask); 11765 sigaction(signo, &act, 0); 11766 } 11767 11768 /* 11769 * Ignore a signal. 11770 */ 11771 11772 void 11773 ignoresig(int signo) 11774 { 11775 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 11776 signal(signo, SIG_IGN); 11777 } 11778 sigmode[signo - 1] = S_HARD_IGN; 11779 } 11780 11781 11782 /* 11783 * Signal handler. 11784 */ 11785 11786 void 11787 onsig(int signo) 11788 { 11789 gotsig[signo - 1] = 1; 11790 pendingsigs = signo; 11791 11792 if (exsig || (signo == SIGINT && !trap[SIGINT])) { 11793 if (!suppressint) 11794 onint(); 11795 intpending = 1; 11796 } 11797 } 11798 11799 11800 /* 11801 * Called to execute a trap. Perhaps we should avoid entering new trap 11802 * handlers while we are executing a trap handler. 11803 */ 11804 11805 int 11806 dotrap(void) 11807 { 11808 char *p; 11809 char *q; 11810 int i; 11811 int savestatus; 11812 int skip = 0; 11813 11814 savestatus = exitstatus; 11815 pendingsigs = 0; 11816 xbarrier(); 11817 11818 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 11819 if (!*q) 11820 continue; 11821 *q = 0; 11822 11823 p = trap[i + 1]; 11824 if (!p) 11825 continue; 11826 skip = evalstring(p, SKIPEVAL); 11827 exitstatus = savestatus; 11828 if (skip) 11829 break; 11830 } 11831 11832 return skip; 11833 } 11834 11835 11836 /* 11837 * Controls whether the shell is interactive or not. 11838 */ 11839 11840 void 11841 setinteractive(int on) 11842 { 11843 static int is_interactive; 11844 11845 if (++on == is_interactive) 11846 return; 11847 is_interactive = on; 11848 setsignal(SIGINT); 11849 setsignal(SIGQUIT); 11850 setsignal(SIGTERM); 11851 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 11852 if(is_interactive > 1) { 11853 /* Looks like they want an interactive shell */ 11854 static int do_banner; 11855 11856 if(!do_banner) { 11857 out1fmt( 11858 "\n\n%s Built-in shell (ash)\n" 11859 "Enter 'help' for a list of built-in commands.\n\n", 11860 BB_BANNER); 11861 do_banner++; 11862 } 11863 } 11864 #endif 11865 } 11866 11867 11868 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 11869 /*** List the available builtins ***/ 11870 11871 static int helpcmd(int argc, char **argv) 11268 /* ============ Builtins */ 11269 11270 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 11271 /* 11272 * Lists available builtins 11273 */ 11274 static int 11275 helpcmd(int argc, char **argv) 11872 11276 { 11873 11277 int col, i; 11874 11278 11875 11279 out1fmt("\nBuilt-in commands:\n-------------------\n"); 11876 for (col = 0, i = 0; i < NUMBUILTINS; i++) {11280 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { 11877 11281 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), 11878 builtincmd[i].name + 1);11282 builtintab[i].name + 1); 11879 11283 if (col > 60) { 11880 11284 out1fmt("\n"); … … 11882 11286 } 11883 11287 } 11884 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 11885 { 11886 extern const struct BB_applet applets[]; 11887 extern const size_t NUM_APPLETS; 11888 11889 for (i = 0; i < NUM_APPLETS; i++) { 11890 11891 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11892 if (col > 60) { 11893 out1fmt("\n"); 11894 col = 0; 11895 } 11288 #if ENABLE_FEATURE_SH_STANDALONE 11289 for (i = 0; i < NUM_APPLETS; i++) { 11290 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11291 if (col > 60) { 11292 out1fmt("\n"); 11293 col = 0; 11896 11294 } 11897 11295 } … … 11900 11298 return EXIT_SUCCESS; 11901 11299 } 11902 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */ 11903 11904 /* 11905 * Called to exit the shell. 11906 */ 11907 11908 void 11909 exitshell(void) 11910 { 11911 struct jmploc loc; 11912 char *p; 11913 int status; 11914 11915 status = exitstatus; 11916 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 11917 if (setjmp(loc.loc)) { 11918 if (exception == EXEXIT) 11919 _exit(exitstatus); 11920 goto out; 11921 } 11922 handler = &loc; 11923 if ((p = trap[0])) { 11924 trap[0] = NULL; 11925 evalstring(p, 0); 11926 } 11927 flushall(); 11928 setjobctl(0); 11929 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 11930 if (iflag && rootshell) { 11931 const char *hp = lookupvar("HISTFILE"); 11932 11933 if(hp != NULL ) 11934 save_history ( hp ); 11935 } 11936 #endif 11937 out: 11938 _exit(status); 11939 /* NOTREACHED */ 11940 } 11941 11942 static int decode_signal(const char *string, int minsig) 11943 { 11944 int signo; 11945 const char *name = u_signal_names(string, &signo, minsig); 11946 11947 return name ? signo : -1; 11948 } 11949 11950 /* var.c */ 11951 11952 static struct var *vartab[VTABSIZE]; 11953 11954 static int vpcmp(const void *, const void *); 11955 static struct var **findvar(struct var **, const char *); 11956 11957 /* 11958 * Initialize the variable symbol tables and import the environment 11959 */ 11960 11961 11962 #ifdef CONFIG_ASH_GETOPTS 11963 /* 11964 * Safe version of setvar, returns 1 on success 0 on failure. 11965 */ 11966 11967 int 11968 setvarsafe(const char *name, const char *val, int flags) 11969 { 11970 int err; 11971 volatile int saveint; 11972 struct jmploc *volatile savehandler = handler; 11973 struct jmploc jmploc; 11974 11975 SAVEINT(saveint); 11976 if (setjmp(jmploc.loc)) 11977 err = 1; 11978 else { 11979 handler = &jmploc; 11980 setvar(name, val, flags); 11981 err = 0; 11982 } 11983 handler = savehandler; 11984 RESTOREINT(saveint); 11985 return err; 11986 } 11987 #endif 11988 11989 /* 11990 * Set the value of a variable. The flags argument is ored with the 11991 * flags of the variable. If val is NULL, the variable is unset. 11992 */ 11993 11994 static void 11995 setvar(const char *name, const char *val, int flags) 11996 { 11997 char *p, *q; 11998 size_t namelen; 11999 char *nameeq; 12000 size_t vallen; 12001 12002 q = endofname(name); 12003 p = strchrnul(q, '='); 12004 namelen = p - name; 12005 if (!namelen || p != q) 12006 sh_error("%.*s: bad variable name", namelen, name); 12007 vallen = 0; 12008 if (val == NULL) { 12009 flags |= VUNSET; 12010 } else { 12011 vallen = strlen(val); 12012 } 12013 INTOFF; 12014 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen); 12015 if (val) { 12016 *p++ = '='; 12017 p = mempcpy(p, val, vallen); 12018 } 12019 *p = '\0'; 12020 setvareq(nameeq, flags | VNOSAVE); 12021 INTON; 12022 } 12023 12024 12025 /* 12026 * Same as setvar except that the variable and value are passed in 12027 * the first argument as name=value. Since the first argument will 12028 * be actually stored in the table, it should not be a string that 12029 * will go away. 12030 * Called with interrupts off. 12031 */ 12032 12033 void 12034 setvareq(char *s, int flags) 12035 { 12036 struct var *vp, **vpp; 12037 12038 vpp = hashvar(s); 12039 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 12040 vp = *findvar(vpp, s); 12041 if (vp) { 12042 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { 12043 const char *n; 12044 12045 if (flags & VNOSAVE) 12046 free(s); 12047 n = vp->text; 12048 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n); 12049 } 12050 12051 if (flags & VNOSET) 12052 return; 12053 12054 if (vp->func && (flags & VNOFUNC) == 0) 12055 (*vp->func)(strchrnul(s, '=') + 1); 12056 12057 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 12058 ckfree(vp->text); 12059 12060 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 12061 } else { 12062 if (flags & VNOSET) 12063 return; 12064 /* not found */ 12065 vp = ckmalloc(sizeof (*vp)); 12066 vp->next = *vpp; 12067 vp->func = NULL; 12068 *vpp = vp; 12069 } 12070 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 12071 s = savestr(s); 12072 vp->text = s; 12073 vp->flags = flags; 12074 } 12075 12076 12077 /* 12078 * Process a linked list of variable assignments. 12079 */ 12080 12081 static void 12082 listsetvar(struct strlist *list_set_var, int flags) 12083 { 12084 struct strlist *lp = list_set_var; 12085 12086 if (!lp) 12087 return; 12088 INTOFF; 12089 do { 12090 setvareq(lp->text, flags); 12091 } while ((lp = lp->next)); 12092 INTON; 12093 } 12094 12095 12096 /* 12097 * Find the value of a variable. Returns NULL if not set. 12098 */ 12099 12100 static char * 12101 lookupvar(const char *name) 12102 { 12103 struct var *v; 12104 12105 if ((v = *findvar(hashvar(name), name))) { 12106 #ifdef DYNAMIC_VAR 12107 /* 12108 * Dynamic variables are implemented roughly the same way they are 12109 * in bash. Namely, they're "special" so long as they aren't unset. 12110 * As soon as they're unset, they're no longer dynamic, and dynamic 12111 * lookup will no longer happen at that point. -- PFM. 12112 */ 12113 if((v->flags & VDYNAMIC)) 12114 (*v->func)(NULL); 12115 #endif 12116 if(!(v->flags & VUNSET)) 12117 return strchrnul(v->text, '=') + 1; 12118 } 12119 12120 return NULL; 12121 } 12122 12123 12124 /* 12125 * Search the environment of a builtin command. 12126 */ 12127 12128 static char * 12129 bltinlookup(const char *name) 12130 { 12131 struct strlist *sp; 12132 12133 for (sp = cmdenviron ; sp ; sp = sp->next) { 12134 if (varequal(sp->text, name)) 12135 return strchrnul(sp->text, '=') + 1; 12136 } 12137 return lookupvar(name); 12138 } 12139 12140 12141 /* 12142 * Generate a list of variables satisfying the given conditions. 12143 */ 12144 12145 static char ** 12146 listvars(int on, int off, char ***end) 12147 { 12148 struct var **vpp; 12149 struct var *vp; 12150 char **ep; 12151 int mask; 12152 12153 STARTSTACKSTR(ep); 12154 vpp = vartab; 12155 mask = on | off; 12156 do { 12157 for (vp = *vpp ; vp ; vp = vp->next) 12158 if ((vp->flags & mask) == on) { 12159 if (ep == stackstrend()) 12160 ep = growstackstr(); 12161 *ep++ = (char *) vp->text; 12162 } 12163 } while (++vpp < vartab + VTABSIZE); 12164 if (ep == stackstrend()) 12165 ep = growstackstr(); 12166 if (end) 12167 *end = ep; 12168 *ep++ = NULL; 12169 return grabstackstr(ep); 12170 } 12171 12172 12173 /* 12174 * POSIX requires that 'set' (but not export or readonly) output the 12175 * variables in lexicographic order - by the locale's collating order (sigh). 12176 * Maybe we could keep them in an ordered balanced binary tree 12177 * instead of hashed lists. 12178 * For now just roll 'em through qsort for printing... 12179 */ 12180 12181 static int 12182 showvars(const char *sep_prefix, int on, int off) 12183 { 12184 const char *sep; 12185 char **ep, **epend; 12186 12187 ep = listvars(on, off, &epend); 12188 qsort(ep, epend - ep, sizeof(char *), vpcmp); 12189 12190 sep = *sep_prefix ? spcstr : sep_prefix; 12191 12192 for (; ep < epend; ep++) { 12193 const char *p; 12194 const char *q; 12195 12196 p = strchrnul(*ep, '='); 12197 q = nullstr; 12198 if (*p) 12199 q = single_quote(++p); 12200 12201 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); 12202 } 12203 12204 return 0; 12205 } 12206 12207 11300 #endif /* FEATURE_SH_EXTRA_QUIET */ 12208 11301 12209 11302 /* 12210 11303 * The export and readonly commands. 12211 11304 */ 12212 12213 11305 static int 12214 11306 exportcmd(int argc, char **argv) … … 12219 11311 char **aptr; 12220 11312 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 12221 int notp; 12222 12223 notp = nextopt("p") - 'p'; 12224 if (notp && ((name = *(aptr = argptr)))) { 12225 do { 12226 if ((p = strchr(name, '=')) != NULL) { 12227 p++; 12228 } else { 12229 if ((vp = *findvar(hashvar(name), name))) { 12230 vp->flags |= flag; 12231 continue; 11313 11314 if (nextopt("p") != 'p') { 11315 aptr = argptr; 11316 name = *aptr; 11317 if (name) { 11318 do { 11319 p = strchr(name, '='); 11320 if (p != NULL) { 11321 p++; 11322 } else { 11323 vp = *findvar(hashvar(name), name); 11324 if (vp) { 11325 vp->flags |= flag; 11326 continue; 11327 } 12232 11328 } 12233 }12234 setvar(name, p, flag);12235 } while ((name = *++aptr) != NULL);12236 } else {12237 showvars(argv[0], flag, 0);12238 }11329 setvar(name, p, flag); 11330 } while ((name = *++aptr) != NULL); 11331 return 0; 11332 } 11333 } 11334 showvars(argv[0], flag, 0); 12239 11335 return 0; 12240 11336 } 12241 11337 12242 12243 /* 12244 * Make a variable a local variable. When a variable is made local, it's 12245 * value and flags are saved in a localvar structure. The saved values 12246 * will be restored when the shell function returns. We handle the name 12247 * "-" as a special case. 12248 */ 12249 12250 static inline void 12251 mklocal(char *name) 12252 { 12253 struct localvar *lvp; 12254 struct var **vpp; 12255 struct var *vp; 12256 12257 INTOFF; 12258 lvp = ckmalloc(sizeof (struct localvar)); 12259 if (name[0] == '-' && name[1] == '\0') { 12260 char *p; 12261 p = ckmalloc(sizeof(optlist)); 12262 lvp->text = memcpy(p, optlist, sizeof(optlist)); 12263 vp = NULL; 12264 } else { 12265 char *eq; 12266 12267 vpp = hashvar(name); 12268 vp = *findvar(vpp, name); 12269 eq = strchr(name, '='); 12270 if (vp == NULL) { 12271 if (eq) 12272 setvareq(name, VSTRFIXED); 12273 else 12274 setvar(name, NULL, VSTRFIXED); 12275 vp = *vpp; /* the new variable */ 12276 lvp->flags = VUNSET; 12277 } else { 12278 lvp->text = vp->text; 12279 lvp->flags = vp->flags; 12280 vp->flags |= VSTRFIXED|VTEXTFIXED; 12281 if (eq) 12282 setvareq(name, 0); 12283 } 12284 } 12285 lvp->vp = vp; 12286 lvp->next = localvars; 12287 localvars = lvp; 12288 INTON; 12289 } 12290 12291 /* 12292 * The "local" command. 12293 */ 12294 12295 static int 12296 localcmd(int argc, char **argv) 12297 { 12298 char *name; 12299 12300 argv = argptr; 12301 while ((name = *argv++) != NULL) { 12302 mklocal(name); 12303 } 12304 return 0; 12305 } 12306 12307 12308 /* 12309 * Called after a function returns. 12310 * Interrupts must be off. 12311 */ 12312 12313 static void 12314 poplocalvars(void) 12315 { 12316 struct localvar *lvp; 12317 struct var *vp; 12318 12319 while ((lvp = localvars) != NULL) { 12320 localvars = lvp->next; 12321 vp = lvp->vp; 12322 TRACE(("poplocalvar %s", vp ? vp->text : "-")); 12323 if (vp == NULL) { /* $- saved */ 12324 memcpy(optlist, lvp->text, sizeof(optlist)); 12325 ckfree(lvp->text); 12326 optschanged(); 12327 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 12328 unsetvar(vp->text); 12329 } else { 12330 if (vp->func) 12331 (*vp->func)(strchrnul(lvp->text, '=') + 1); 12332 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 12333 ckfree(vp->text); 12334 vp->flags = lvp->flags; 12335 vp->text = lvp->text; 12336 } 12337 ckfree(lvp); 12338 } 12339 } 12340 11338 /* 11339 * Delete a function if it exists. 11340 */ 11341 static void 11342 unsetfunc(const char *name) 11343 { 11344 struct tblentry *cmdp; 11345 11346 cmdp = cmdlookup(name, 0); 11347 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION) 11348 delete_cmd_entry(); 11349 } 12341 11350 12342 11351 /* … … 12345 11354 * with the same name. 12346 11355 */ 12347 12348 int 11356 static int 12349 11357 unsetcmd(int argc, char **argv) 12350 11358 { … … 12358 11366 } 12359 11367 12360 for (ap = argptr; *ap 11368 for (ap = argptr; *ap; ap++) { 12361 11369 if (flag != 'f') { 12362 11370 i = unsetvar(*ap); … … 12372 11380 12373 11381 12374 /*12375 * Unset the specified variable.12376 */12377 12378 int12379 unsetvar(const char *s)12380 {12381 struct var **vpp;12382 struct var *vp;12383 int retval;12384 12385 vpp = findvar(hashvar(s), s);12386 vp = *vpp;12387 retval = 2;12388 if (vp) {12389 int flags = vp->flags;12390 12391 retval = 1;12392 if (flags & VREADONLY)12393 goto out;12394 #ifdef DYNAMIC_VAR12395 vp->flags &= ~VDYNAMIC;12396 #endif12397 if (flags & VUNSET)12398 goto ok;12399 if ((flags & VSTRFIXED) == 0) {12400 INTOFF;12401 if ((flags & (VTEXTFIXED|VSTACK)) == 0)12402 ckfree(vp->text);12403 *vpp = vp->next;12404 ckfree(vp);12405 INTON;12406 } else {12407 setvar(s, 0, 0);12408 vp->flags &= ~VEXPORT;12409 }12410 ok:12411 retval = 0;12412 }12413 12414 out:12415 return retval;12416 }12417 12418 12419 12420 /*12421 * Find the appropriate entry in the hash table from the name.12422 */12423 12424 static struct var **12425 hashvar(const char *p)12426 {12427 unsigned int hashval;12428 12429 hashval = ((unsigned char) *p) << 4;12430 while (*p && *p != '=')12431 hashval += (unsigned char) *p++;12432 return &vartab[hashval % VTABSIZE];12433 }12434 12435 12436 12437 /*12438 * Compares two strings up to the first = or '\0'. The first12439 * string must be terminated by '='; the second may be terminated by12440 * either '=' or '\0'.12441 */12442 12443 int12444 varcmp(const char *p, const char *q)12445 {12446 int c, d;12447 12448 while ((c = *p) == (d = *q)) {12449 if (!c || c == '=')12450 goto out;12451 p++;12452 q++;12453 }12454 if (c == '=')12455 c = 0;12456 if (d == '=')12457 d = 0;12458 out:12459 return c - d;12460 }12461 12462 static int12463 vpcmp(const void *a, const void *b)12464 {12465 return varcmp(*(const char **)a, *(const char **)b);12466 }12467 12468 static struct var **12469 findvar(struct var **vpp, const char *name)12470 {12471 for (; *vpp; vpp = &(*vpp)->next) {12472 if (varequal((*vpp)->text, name)) {12473 break;12474 }12475 }12476 return vpp;12477 }12478 11382 /* setmode.c */ 12479 11383 12480 11384 #include <sys/times.h> 12481 11385 12482 static const unsigned char timescmd_str[] = {11386 static const unsigned char timescmd_str[] ALIGN1 = { 12483 11387 ' ', offsetof(struct tms, tms_utime), 12484 11388 '\n', offsetof(struct tms, tms_stime), … … 12488 11392 }; 12489 11393 12490 static int timescmd(int ac, char **av) 12491 { 12492 long int clk_tck, s, t; 11394 static int 11395 timescmd(int ac, char **av) 11396 { 11397 long clk_tck, s, t; 12493 11398 const unsigned char *p; 12494 11399 struct tms buf; … … 12510 11415 } 12511 11416 12512 #if def CONFIG_ASH_MATH_SUPPORT11417 #if ENABLE_ASH_MATH_SUPPORT 12513 11418 static arith_t 12514 11419 dash_arith(const char *s) … … 12517 11422 int errcode = 0; 12518 11423 12519 INT OFF;11424 INT_OFF; 12520 11425 result = arith(s, &errcode); 12521 11426 if (errcode < 0) { 12522 11427 if (errcode == -3) 12523 sh_error("exponent less than 0"); 12524 else if (errcode == -2) 12525 sh_error("divide by zero"); 12526 else if (errcode == -5) 12527 sh_error("expression recursion loop detected"); 12528 else 12529 synerror(s); 12530 } 12531 INTON; 12532 12533 return (result); 12534 } 12535 11428 ash_msg_and_raise_error("exponent less than 0"); 11429 if (errcode == -2) 11430 ash_msg_and_raise_error("divide by zero"); 11431 if (errcode == -5) 11432 ash_msg_and_raise_error("expression recursion loop detected"); 11433 raise_error_syntax(s); 11434 } 11435 INT_ON; 11436 11437 return result; 11438 } 12536 11439 12537 11440 /* … … 12541 11444 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 12542 11445 */ 12543 12544 11446 static int 12545 11447 letcmd(int argc, char **argv) 12546 11448 { 12547 11449 char **ap; 12548 arith_t i ;11450 arith_t i = 0; 12549 11451 12550 11452 ap = argv + 1; 12551 if (!*ap)12552 sh_error("expression expected");11453 if (!*ap) 11454 ash_msg_and_raise_error("expression expected"); 12553 11455 for (ap = argv + 1; *ap; ap++) { 12554 11456 i = dash_arith(*ap); 12555 11457 } 12556 11458 12557 return (!i);12558 } 12559 #endif /* CONFIG_ASH_MATH_SUPPORT */12560 12561 /* miscbltin.c */ 12562 12563 /*11459 return !i; 11460 } 11461 #endif /* ASH_MATH_SUPPORT */ 11462 11463 11464 /* ============ miscbltin.c 11465 * 12564 11466 * Miscellaneous builtins. 12565 11467 */ … … 12567 11469 #undef rflag 12568 11470 12569 #ifdef __GLIBC__ 12570 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 11471 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 12571 11472 typedef enum __rlimit_resource rlim_t; 12572 11473 #endif 12573 #endif12574 12575 11474 12576 11475 /* … … 12580 11479 * This uses unbuffered input, which may be avoidable in some cases. 12581 11480 */ 12582 12583 11481 static int 12584 11482 readcmd(int argc, char **argv) … … 12594 11492 int status; 12595 11493 int i; 12596 #if defined(CONFIG_ASH_READ_NCHARS)11494 #if ENABLE_ASH_READ_NCHARS 12597 11495 int nch_flag = 0; 12598 11496 int nchars = 0; … … 12600 11498 struct termios tty, old_tty; 12601 11499 #endif 12602 #if defined(CONFIG_ASH_READ_TIMEOUT)11500 #if ENABLE_ASH_READ_TIMEOUT 12603 11501 fd_set set; 12604 11502 struct timeval ts; … … 12609 11507 rflag = 0; 12610 11508 prompt = NULL; 12611 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)11509 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT 12612 11510 while ((i = nextopt("p:rt:n:s")) != '\0') 12613 #elif defined(CONFIG_ASH_READ_NCHARS)11511 #elif ENABLE_ASH_READ_NCHARS 12614 11512 while ((i = nextopt("p:rn:s")) != '\0') 12615 #elif defined(CONFIG_ASH_READ_TIMEOUT)11513 #elif ENABLE_ASH_READ_TIMEOUT 12616 11514 while ((i = nextopt("p:rt:")) != '\0') 12617 11515 #else … … 12619 11517 #endif 12620 11518 { 12621 switch (i) {11519 switch (i) { 12622 11520 case 'p': 12623 11521 prompt = optionarg; 12624 11522 break; 12625 #if defined(CONFIG_ASH_READ_NCHARS)11523 #if ENABLE_ASH_READ_NCHARS 12626 11524 case 'n': 12627 11525 nchars = strtol(optionarg, &p, 10); 12628 11526 if (*p) 12629 sh_error("invalid count");11527 ash_msg_and_raise_error("invalid count"); 12630 11528 nch_flag = (nchars > 0); 12631 11529 break; … … 12634 11532 break; 12635 11533 #endif 12636 #if defined(CONFIG_ASH_READ_TIMEOUT)11534 #if ENABLE_ASH_READ_TIMEOUT 12637 11535 case 't': 12638 11536 ts.tv_sec = strtol(optionarg, &p, 10); … … 12644 11542 ts.tv_usec = strtol(p, &p2, 10); 12645 11543 if (*p2) 12646 sh_error("invalid timeout");11544 ash_msg_and_raise_error("invalid timeout"); 12647 11545 scale = p2 - p; 12648 11546 /* normalize to usec */ 12649 11547 if (scale > 6) 12650 sh_error("invalid timeout");11548 ash_msg_and_raise_error("invalid timeout"); 12651 11549 while (scale++ < 6) 12652 11550 ts.tv_usec *= 10; 12653 11551 } 12654 11552 } else if (*p) { 12655 sh_error("invalid timeout");11553 ash_msg_and_raise_error("invalid timeout"); 12656 11554 } 12657 11555 if ( ! ts.tv_sec && ! ts.tv_usec) 12658 sh_error("invalid timeout");11556 ash_msg_and_raise_error("invalid timeout"); 12659 11557 break; 12660 11558 #endif … … 12669 11567 out2str(prompt); 12670 11568 } 12671 if (*(ap = argptr) == NULL) 12672 sh_error("arg count"); 12673 if ((ifs = bltinlookup("IFS")) == NULL) 11569 ap = argptr; 11570 if (*ap == NULL) 11571 ash_msg_and_raise_error("arg count"); 11572 ifs = bltinlookup("IFS"); 11573 if (ifs == NULL) 12674 11574 ifs = defifs; 12675 #if defined(CONFIG_ASH_READ_NCHARS)11575 #if ENABLE_ASH_READ_NCHARS 12676 11576 if (nch_flag || silent) { 12677 11577 tcgetattr(0, &tty); 12678 11578 old_tty = tty; 12679 11579 if (nch_flag) { 12680 12681 11580 tty.c_lflag &= ~ICANON; 11581 tty.c_cc[VMIN] = nchars; 12682 11582 } 12683 11583 if (silent) { 12684 11584 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); 12685 11585 12686 11586 } … … 12688 11588 } 12689 11589 #endif 12690 #if defined(CONFIG_ASH_READ_TIMEOUT)11590 #if ENABLE_ASH_READ_TIMEOUT 12691 11591 if (ts.tv_sec || ts.tv_usec) { 12692 FD_ZERO 12693 FD_SET 12694 12695 i = select 11592 FD_ZERO(&set); 11593 FD_SET(0, &set); 11594 11595 i = select(FD_SETSIZE, &set, NULL, NULL, &ts); 12696 11596 if (!i) { 12697 #if defined(CONFIG_ASH_READ_NCHARS)11597 #if ENABLE_ASH_READ_NCHARS 12698 11598 if (nch_flag) 12699 11599 tcsetattr(0, TCSANOW, &old_tty); … … 12707 11607 backslash = 0; 12708 11608 STARTSTACKSTR(p); 12709 #if defined(CONFIG_ASH_READ_NCHARS)11609 #if ENABLE_ASH_READ_NCHARS 12710 11610 while (!nch_flag || nchars--) 12711 11611 #else … … 12742 11642 STARTSTACKSTR(p); 12743 11643 } else { 12744 put:11644 put: 12745 11645 STPUTC(c, p); 12746 11646 } 12747 11647 } 12748 #if defined(CONFIG_ASH_READ_NCHARS)11648 #if ENABLE_ASH_READ_NCHARS 12749 11649 if (nch_flag || silent) 12750 11650 tcsetattr(0, TCSANOW, &old_tty); … … 12761 11661 } 12762 11662 12763 12764 static intumaskcmd(int argc, char **argv)12765 { 12766 static const char permuser[3] = "ugo";12767 static const char permmode[3] = "rwx";12768 static const short int permmask[]= {11663 static int 11664 umaskcmd(int argc, char **argv) 11665 { 11666 static const char permuser[3] ALIGN1 = "ugo"; 11667 static const char permmode[3] ALIGN1 = "rwx"; 11668 static const short permmask[] ALIGN2 = { 12769 11669 S_IRUSR, S_IWUSR, S_IXUSR, 12770 11670 S_IRGRP, S_IWGRP, S_IXGRP, … … 12781 11681 } 12782 11682 12783 INT OFF;11683 INT_OFF; 12784 11684 mask = umask(0); 12785 11685 umask(mask); 12786 INTON; 12787 12788 if ((ap = *argptr) == NULL) { 11686 INT_ON; 11687 11688 ap = *argptr; 11689 if (ap == NULL) { 12789 11690 if (symbolic_mode) { 12790 11691 char buf[18]; … … 12809 11710 } 12810 11711 } else { 12811 if (is _digit((unsigned char) *ap)) {11712 if (isdigit((unsigned char) *ap)) { 12812 11713 mask = 0; 12813 11714 do { 12814 11715 if (*ap >= '8' || *ap < '0') 12815 sh_error(illnum, argv[1]);11716 ash_msg_and_raise_error(illnum, argv[1]); 12816 11717 mask = (mask << 3) + (*ap - '0'); 12817 11718 } while (*++ap != '\0'); … … 12820 11721 mask = ~mask & 0777; 12821 11722 if (!bb_parse_mode(ap, &mask)) { 12822 sh_error("Illegal mode: %s", ap);11723 ash_msg_and_raise_error("illegal mode: %s", ap); 12823 11724 } 12824 11725 umask(~mask & 0777); … … 12879 11780 { "locks", RLIMIT_LOCKS, 1, 'w' }, 12880 11781 #endif 12881 { (char *) 0,0, 0, '\0' }11782 { NULL, 0, 0, '\0' } 12882 11783 }; 12883 11784 12884 11785 enum limtype { SOFT = 0x1, HARD = 0x2 }; 12885 11786 12886 static void printlim(enum limtype how, const struct rlimit *limit, 11787 static void 11788 printlim(enum limtype how, const struct rlimit *limit, 12887 11789 const struct limits *l) 12888 11790 { … … 12901 11803 } 12902 11804 12903 int11805 static int 12904 11806 ulimitcmd(int argc, char **argv) 12905 11807 { 12906 int 11808 int c; 12907 11809 rlim_t val = 0; 12908 11810 enum limtype how = SOFT | HARD; 12909 const struct limits 12910 int 12911 int 12912 struct rlimit 11811 const struct limits *l; 11812 int set, all = 0; 11813 int optc, what; 11814 struct rlimit limit; 12913 11815 12914 11816 what = 'f'; … … 12947 11849 "w" 12948 11850 #endif 12949 11851 )) != '\0') 12950 11852 switch (optc) { 12951 11853 case 'H': … … 12970 11872 12971 11873 if (all || argptr[1]) 12972 sh_error("too many arguments");11874 ash_msg_and_raise_error("too many arguments"); 12973 11875 if (strncmp(p, "unlimited\n", 9) == 0) 12974 11876 val = RLIM_INFINITY; … … 12976 11878 val = (rlim_t) 0; 12977 11879 12978 while ((c = *p++) >= '0' && c <= '9') 12979 { 11880 while ((c = *p++) >= '0' && c <= '9') { 12980 11881 val = (val * 10) + (long)(c - '0'); 12981 11882 if (val < (rlim_t) 0) … … 12983 11884 } 12984 11885 if (c) 12985 sh_error("bad number");11886 ash_msg_and_raise_error("bad number"); 12986 11887 val *= l->factor; 12987 11888 } … … 13003 11904 limit.rlim_cur = val; 13004 11905 if (setrlimit(l->cmd, &limit) < 0) 13005 sh_error("error setting limit (%m)");11906 ash_msg_and_raise_error("error setting limit (%m)"); 13006 11907 } else { 13007 11908 printlim(how, &limit, l); … … 13011 11912 13012 11913 13013 #ifdef CONFIG_ASH_MATH_SUPPORT 11914 /* ============ Math support */ 11915 11916 #if ENABLE_ASH_MATH_SUPPORT 13014 11917 13015 11918 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> … … 13107 12010 */ 13108 12011 13109 13110 12012 #define arith_isspace(arithval) \ 13111 12013 (arithval == ' ' || arithval == '\n' || arithval == '\t') 13112 13113 12014 13114 12015 typedef unsigned char operator; … … 13141 12042 13142 12043 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 13143 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while(0)12044 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 13144 12045 13145 12046 /* conditional is right associativity too */ … … 13203 12104 #define NUMPTR (*numstackptr) 13204 12105 13205 static inline int tok_have_assign(operator op) 12106 static int 12107 tok_have_assign(operator op) 13206 12108 { 13207 12109 operator prec = PREC(op); … … 13212 12114 } 13213 12115 13214 static in line int is_right_associativity(operator prec)13215 { 13216 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) || 13217 prec == PREC(TOK_CONDITIONAL));13218 } 13219 12116 static int 12117 is_right_associativity(operator prec) 12118 { 12119 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 12120 || prec == PREC(TOK_CONDITIONAL)); 12121 } 13220 12122 13221 12123 typedef struct ARITCH_VAR_NUM { … … 13227 12129 } v_n_t; 13228 12130 13229 13230 12131 typedef struct CHK_VAR_RECURSIVE_LOOPED { 13231 12132 const char *var; … … 13235 12136 static chk_var_recursive_looped_t *prev_chk_var_recursive; 13236 12137 13237 13238 static int arith_lookup_val(v_n_t *t) 13239 { 13240 if(t->var) { 13241 const char * p = lookupvar(t->var); 13242 13243 if(p) { 13244 int errcode; 13245 13246 /* recursive try as expression */ 13247 chk_var_recursive_looped_t *cur; 13248 chk_var_recursive_looped_t cur_save; 13249 13250 for(cur = prev_chk_var_recursive; cur; cur = cur->next) { 13251 if(strcmp(cur->var, t->var) == 0) { 13252 /* expression recursion loop detected */ 13253 return -5; 13254 } 13255 } 13256 /* save current lookuped var name */ 13257 cur = prev_chk_var_recursive; 13258 cur_save.var = t->var; 13259 cur_save.next = cur; 13260 prev_chk_var_recursive = &cur_save; 13261 13262 t->val = arith (p, &errcode); 13263 /* restore previous ptr after recursiving */ 13264 prev_chk_var_recursive = cur; 13265 return errcode; 13266 } else { 13267 /* allow undefined var as 0 */ 13268 t->val = 0; 13269 } 13270 } 13271 return 0; 12138 static int 12139 arith_lookup_val(v_n_t *t) 12140 { 12141 if (t->var) { 12142 const char * p = lookupvar(t->var); 12143 12144 if (p) { 12145 int errcode; 12146 12147 /* recursive try as expression */ 12148 chk_var_recursive_looped_t *cur; 12149 chk_var_recursive_looped_t cur_save; 12150 12151 for (cur = prev_chk_var_recursive; cur; cur = cur->next) { 12152 if (strcmp(cur->var, t->var) == 0) { 12153 /* expression recursion loop detected */ 12154 return -5; 12155 } 12156 } 12157 /* save current lookuped var name */ 12158 cur = prev_chk_var_recursive; 12159 cur_save.var = t->var; 12160 cur_save.next = cur; 12161 prev_chk_var_recursive = &cur_save; 12162 12163 t->val = arith (p, &errcode); 12164 /* restore previous ptr after recursiving */ 12165 prev_chk_var_recursive = cur; 12166 return errcode; 12167 } 12168 /* allow undefined var as 0 */ 12169 t->val = 0; 12170 } 12171 return 0; 13272 12172 } 13273 12173 … … 13275 12175 * stack. For a unary operator it will only change the top element, but a 13276 12176 * binary operator will pop two arguments and push a result */ 13277 static in line int12177 static int 13278 12178 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) 13279 12179 { … … 13282 12182 int ret_arith_lookup_val; 13283 12183 13284 if (NUMPTR == numstack) goto err; /* There is no operator that can work13285 without arguments */12184 /* There is no operator that can work without arguments */ 12185 if (NUMPTR == numstack) goto err; 13286 12186 numptr_m1 = NUMPTR - 1; 13287 12187 13288 12188 /* check operand is var with noninteger value */ 13289 12189 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 13290 if (ret_arith_lookup_val)12190 if (ret_arith_lookup_val) 13291 12191 return ret_arith_lookup_val; 13292 12192 … … 13305 12205 /* Binary operators */ 13306 12206 13307 13308 13309 13310 13311 13312 13313 13314 if(! numptr_m1->contidional_second_val_initialized) {13315 13316 13317 }13318 rez = numptr_m1->contidional_second_val;13319 } else if(numptr_m1->contidional_second_val_initialized) {13320 13321 13322 13323 13324 if(op != TOK_ASSIGN) {13325 /* check operand is var with noninteger value for not '=' */13326 ret_arith_lookup_val = arith_lookup_val(numptr_m1);13327 if(ret_arith_lookup_val)13328 13329 13330 13331 13332 13333 13334 12207 /* check and binary operators need two arguments */ 12208 if (numptr_m1 == numstack) goto err; 12209 12210 /* ... and they pop one */ 12211 --NUMPTR; 12212 numptr_val = rez; 12213 if (op == TOK_CONDITIONAL) { 12214 if (! numptr_m1->contidional_second_val_initialized) { 12215 /* protect $((expr1 ? expr2)) without ": expr" */ 12216 goto err; 12217 } 12218 rez = numptr_m1->contidional_second_val; 12219 } else if (numptr_m1->contidional_second_val_initialized) { 12220 /* protect $((expr1 : expr2)) without "expr ? " */ 12221 goto err; 12222 } 12223 numptr_m1 = NUMPTR - 1; 12224 if (op != TOK_ASSIGN) { 12225 /* check operand is var with noninteger value for not '=' */ 12226 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12227 if (ret_arith_lookup_val) 12228 return ret_arith_lookup_val; 12229 } 12230 if (op == TOK_CONDITIONAL) { 12231 numptr_m1->contidional_second_val = rez; 12232 } 12233 rez = numptr_m1->val; 12234 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 13335 12235 rez |= numptr_val; 13336 12236 else if (op == TOK_OR) 13337 12237 rez = numptr_val || rez; 13338 12238 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 13339 12239 rez &= numptr_val; 13340 12240 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 13341 12241 rez ^= numptr_val; 13342 12242 else if (op == TOK_AND) 13343 12243 rez = rez && numptr_val; 13344 12244 else if (op == TOK_EQ) 13345 12245 rez = (rez == numptr_val); 13346 12246 else if (op == TOK_NE) 13347 12247 rez = (rez != numptr_val); 13348 12248 else if (op == TOK_GE) 13349 12249 rez = (rez >= numptr_val); 13350 12250 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 13351 12251 rez >>= numptr_val; 13352 12252 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 13353 12253 rez <<= numptr_val; 13354 12254 else if (op == TOK_GT) 13355 12255 rez = (rez > numptr_val); 13356 12256 else if (op == TOK_LT) 13357 12257 rez = (rez < numptr_val); 13358 12258 else if (op == TOK_LE) 13359 12259 rez = (rez <= numptr_val); 13360 12260 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 13361 12261 rez *= numptr_val; 13362 12262 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 13363 12263 rez += numptr_val; 13364 12264 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 13365 12265 rez -= numptr_val; 13366 12266 else if (op == TOK_ASSIGN || op == TOK_COMMA) 13367 12267 rez = numptr_val; 13368 12268 else if (op == TOK_CONDITIONAL_SEP) { 13369 12269 if (numptr_m1 == numstack) { 13370 13371 12270 /* protect $((expr : expr)) without "expr ? " */ 12271 goto err; 13372 12272 } 13373 12273 numptr_m1->contidional_second_val_initialized = op; 13374 12274 numptr_m1->contidional_second_val = numptr_val; 13375 } 13376 else if (op == TOK_CONDITIONAL) { 12275 } else if (op == TOK_CONDITIONAL) { 13377 12276 rez = rez ? 13378 numptr_val : numptr_m1->contidional_second_val; 13379 } 13380 else if(op == TOK_EXPONENT) { 13381 if(numptr_val < 0) 12277 numptr_val : numptr_m1->contidional_second_val; 12278 } else if (op == TOK_EXPONENT) { 12279 if (numptr_val < 0) 13382 12280 return -3; /* exponent less than 0 */ 13383 12281 else { 13384 12282 arith_t c = 1; 13385 12283 13386 if (numptr_val)13387 while (numptr_val--)12284 if (numptr_val) 12285 while (numptr_val--) 13388 12286 c *= rez; 13389 12287 rez = c; 13390 12288 } 13391 } 13392 else if(numptr_val==0) /* zero divisor check */ 12289 } else if (numptr_val==0) /* zero divisor check */ 13393 12290 return -2; 13394 12291 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 13395 12292 rez /= numptr_val; 13396 12293 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 13397 12294 rez %= numptr_val; 13398 12295 } 13399 if (tok_have_assign(op)) {13400 char buf[ 32];13401 13402 if (numptr_m1->var == NULL) {12296 if (tok_have_assign(op)) { 12297 char buf[sizeof(arith_t_type)*3 + 2]; 12298 12299 if (numptr_m1->var == NULL) { 13403 12300 /* Hmm, 1=2 ? */ 13404 12301 goto err; 13405 12302 } 13406 12303 /* save to shell variable */ 13407 #if def CONFIG_ASH_MATH_SUPPORT_6413408 snprintf(buf, sizeof(buf), "%lld", arith_t_typerez);12304 #if ENABLE_ASH_MATH_SUPPORT_64 12305 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); 13409 12306 #else 13410 snprintf(buf, sizeof(buf), "%ld", arith_t_typerez);12307 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); 13411 12308 #endif 13412 12309 setvar(numptr_m1->var, buf, 0); 13413 12310 /* after saving, make previous value for v++ or v-- */ 13414 if (op == TOK_POST_INC)12311 if (op == TOK_POST_INC) 13415 12312 rez--; 13416 else if (op == TOK_POST_DEC)12313 else if (op == TOK_POST_DEC) 13417 12314 rez++; 13418 12315 } … … 13421 12318 numptr_m1->var = NULL; 13422 12319 return 0; 13423 err: return(-1); 13424 } 13425 13426 /* longest must first */ 13427 static const char op_tokens[] = { 12320 err: 12321 return -1; 12322 } 12323 12324 /* longest must be first */ 12325 static const char op_tokens[] ALIGN1 = { 13428 12326 '<','<','=',0, TOK_LSHIFT_ASSIGN, 13429 12327 '>','>','=',0, TOK_RSHIFT_ASSIGN, … … 13471 12369 #define endexpression &op_tokens[sizeof(op_tokens)-7] 13472 12370 13473 13474 static arith_t arith (const char *expr, int *perrcode) 13475 { 13476 register char arithval; /* Current character under analysis */ 13477 operator lasttok, op; 13478 operator prec; 13479 13480 const char *p = endexpression; 13481 int errcode; 13482 13483 size_t datasizes = strlen(expr) + 2; 13484 13485 /* Stack of integers */ 13486 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 13487 * in any given correct or incorrect expression is left as an exercise to 13488 * the reader. */ 13489 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 13490 *numstackptr = numstack; 13491 /* Stack of operator tokens */ 13492 operator *stack = alloca((datasizes) * sizeof(operator)), 13493 *stackptr = stack; 13494 13495 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 13496 *perrcode = errcode = 0; 13497 13498 while(1) { 13499 if ((arithval = *expr) == 0) { 13500 if (p == endexpression) { 13501 /* Null expression. */ 13502 return 0; 13503 } 13504 13505 /* This is only reached after all tokens have been extracted from the 13506 * input stream. If there are still tokens on the operator stack, they 13507 * are to be applied in order. At the end, there should be a final 13508 * result on the integer stack */ 13509 13510 if (expr != endexpression + 1) { 13511 /* If we haven't done so already, */ 13512 /* append a closing right paren */ 13513 expr = endexpression; 13514 /* and let the loop process it. */ 13515 continue; 13516 } 13517 /* At this point, we're done with the expression. */ 13518 if (numstackptr != numstack+1) { 13519 /* ... but if there isn't, it's bad */ 13520 err: 13521 return (*perrcode = -1); 13522 } 13523 if(numstack->var) { 13524 /* expression is $((var)) only, lookup now */ 13525 errcode = arith_lookup_val(numstack); 13526 } 13527 ret: 13528 *perrcode = errcode; 13529 return numstack->val; 13530 } else { 12371 static arith_t 12372 arith(const char *expr, int *perrcode) 12373 { 12374 char arithval; /* Current character under analysis */ 12375 operator lasttok, op; 12376 operator prec; 12377 12378 const char *p = endexpression; 12379 int errcode; 12380 12381 size_t datasizes = strlen(expr) + 2; 12382 12383 /* Stack of integers */ 12384 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 12385 * in any given correct or incorrect expression is left as an exercise to 12386 * the reader. */ 12387 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 12388 *numstackptr = numstack; 12389 /* Stack of operator tokens */ 12390 operator *stack = alloca((datasizes) * sizeof(operator)), 12391 *stackptr = stack; 12392 12393 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 12394 *perrcode = errcode = 0; 12395 12396 while (1) { 12397 arithval = *expr; 12398 if (arithval == 0) { 12399 if (p == endexpression) { 12400 /* Null expression. */ 12401 return 0; 12402 } 12403 12404 /* This is only reached after all tokens have been extracted from the 12405 * input stream. If there are still tokens on the operator stack, they 12406 * are to be applied in order. At the end, there should be a final 12407 * result on the integer stack */ 12408 12409 if (expr != endexpression + 1) { 12410 /* If we haven't done so already, */ 12411 /* append a closing right paren */ 12412 expr = endexpression; 12413 /* and let the loop process it. */ 12414 continue; 12415 } 12416 /* At this point, we're done with the expression. */ 12417 if (numstackptr != numstack+1) { 12418 /* ... but if there isn't, it's bad */ 12419 err: 12420 return (*perrcode = -1); 12421 } 12422 if (numstack->var) { 12423 /* expression is $((var)) only, lookup now */ 12424 errcode = arith_lookup_val(numstack); 12425 } 12426 ret: 12427 *perrcode = errcode; 12428 return numstack->val; 12429 } 12430 13531 12431 /* Continue processing the expression. */ 13532 12432 if (arith_isspace(arithval)) { … … 13534 12434 goto prologue; 13535 12435 } 13536 if((p = endofname(expr)) != expr) { 12436 p = endofname(expr); 12437 if (p != expr) { 13537 12438 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 13538 12439 … … 13540 12441 safe_strncpy(numstackptr->var, expr, var_name_size); 13541 12442 expr = p; 13542 12443 num: 13543 12444 numstackptr->contidional_second_val_initialized = 0; 13544 12445 numstackptr++; 13545 12446 lasttok = TOK_NUM; 13546 12447 continue; 13547 } else if (is_digit(arithval)) { 12448 } 12449 if (isdigit(arithval)) { 13548 12450 numstackptr->var = NULL; 13549 #if def CONFIG_ASH_MATH_SUPPORT_6412451 #if ENABLE_ASH_MATH_SUPPORT_64 13550 12452 numstackptr->val = strtoll(expr, (char **) &expr, 0); 13551 12453 #else … … 13554 12456 goto num; 13555 12457 } 13556 for (p = op_tokens; ; p++) {12458 for (p = op_tokens; ; p++) { 13557 12459 const char *o; 13558 12460 13559 if (*p == 0) {12461 if (*p == 0) { 13560 12462 /* strange operator not found */ 13561 12463 goto err; 13562 12464 } 13563 for (o = expr; *p && *o == *p; p++)12465 for (o = expr; *p && *o == *p; p++) 13564 12466 o++; 13565 if (! *p) {12467 if (! *p) { 13566 12468 /* found */ 13567 12469 expr = o - 1; … … 13569 12471 } 13570 12472 /* skip tail uncompared token */ 13571 while (*p)12473 while (*p) 13572 12474 p++; 13573 12475 /* skip zero delim */ … … 13577 12479 13578 12480 /* post grammar: a++ reduce to num */ 13579 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)13580 12481 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 12482 lasttok = TOK_NUM; 13581 12483 13582 12484 /* Plus and minus are binary (not unary) _only_ if the last … … 13585 12487 * It makes sense. */ 13586 12488 if (lasttok != TOK_NUM) { 13587 switch (op) {13588 13589 13590 13591 13592 13593 13594 13595 13596 13597 13598 13599 12489 switch (op) { 12490 case TOK_ADD: 12491 op = TOK_UPLUS; 12492 break; 12493 case TOK_SUB: 12494 op = TOK_UMINUS; 12495 break; 12496 case TOK_POST_INC: 12497 op = TOK_PRE_INC; 12498 break; 12499 case TOK_POST_DEC: 12500 op = TOK_PRE_DEC; 12501 break; 13600 12502 } 13601 12503 } … … 13619 12521 } 13620 12522 while (stackptr != stack) { 13621 if (op == TOK_RPAREN) { 13622 /* The algorithm employed here is simple: while we don't 13623 * hit an open paren nor the bottom of the stack, pop 13624 * tokens and apply them */ 13625 if (stackptr[-1] == TOK_LPAREN) { 13626 --stackptr; 13627 /* Any operator directly after a */ 13628 lasttok = TOK_NUM; 13629 /* close paren should consider itself binary */ 13630 goto prologue; 12523 if (op == TOK_RPAREN) { 12524 /* The algorithm employed here is simple: while we don't 12525 * hit an open paren nor the bottom of the stack, pop 12526 * tokens and apply them */ 12527 if (stackptr[-1] == TOK_LPAREN) { 12528 --stackptr; 12529 /* Any operator directly after a */ 12530 lasttok = TOK_NUM; 12531 /* close paren should consider itself binary */ 12532 goto prologue; 12533 } 12534 } else { 12535 operator prev_prec = PREC(stackptr[-1]); 12536 12537 convert_prec_is_assing(prec); 12538 convert_prec_is_assing(prev_prec); 12539 if (prev_prec < prec) 12540 break; 12541 /* check right assoc */ 12542 if (prev_prec == prec && is_right_associativity(prec)) 12543 break; 13631 12544 } 13632 } else { 13633 operator prev_prec = PREC(stackptr[-1]); 13634 13635 convert_prec_is_assing(prec); 13636 convert_prec_is_assing(prev_prec); 13637 if (prev_prec < prec) 13638 break; 13639 /* check right assoc */ 13640 if(prev_prec == prec && is_right_associativity(prec)) 13641 break; 13642 } 13643 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 13644 if(errcode) goto ret; 12545 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 12546 if (errcode) goto ret; 13645 12547 } 13646 12548 if (op == TOK_RPAREN) { … … 13651 12553 /* Push this operator to the stack and remember it. */ 13652 12554 *stackptr++ = lasttok = op; 13653 13654 prologue: 12555 prologue: 13655 12556 ++expr; 13656 } 13657 } 13658 } 13659 #endif /* CONFIG_ASH_MATH_SUPPORT */ 13660 13661 13662 #ifdef DEBUG 13663 const char *bb_applet_name = "debug stuff usage"; 12557 } /* while */ 12558 } 12559 #endif /* ASH_MATH_SUPPORT */ 12560 12561 12562 /* ============ main() and helpers */ 12563 12564 /* 12565 * Called to exit the shell. 12566 */ 12567 static void exitshell(void) ATTRIBUTE_NORETURN; 12568 static void 12569 exitshell(void) 12570 { 12571 struct jmploc loc; 12572 char *p; 12573 int status; 12574 12575 status = exitstatus; 12576 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 12577 if (setjmp(loc.loc)) { 12578 if (exception == EXEXIT) 12579 /* dash bug: it just does _exit(exitstatus) here 12580 * but we have to do setjobctl(0) first! 12581 * (bug is still not fixed in dash-0.5.3 - if you run dash 12582 * under Midnight Commander, on exit from dash MC is backgrounded) */ 12583 status = exitstatus; 12584 goto out; 12585 } 12586 exception_handler = &loc; 12587 p = trap[0]; 12588 if (p) { 12589 trap[0] = NULL; 12590 evalstring(p, 0); 12591 } 12592 flush_stdout_stderr(); 12593 out: 12594 setjobctl(0); 12595 _exit(status); 12596 /* NOTREACHED */ 12597 } 12598 12599 static void 12600 init(void) 12601 { 12602 /* from input.c: */ 12603 basepf.nextc = basepf.buf = basebuf; 12604 12605 /* from trap.c: */ 12606 signal(SIGCHLD, SIG_DFL); 12607 12608 /* from var.c: */ 12609 { 12610 char **envp; 12611 char ppid[sizeof(int)*3 + 1]; 12612 const char *p; 12613 struct stat st1, st2; 12614 12615 initvar(); 12616 for (envp = environ; envp && *envp; envp++) { 12617 if (strchr(*envp, '=')) { 12618 setvareq(*envp, VEXPORT|VTEXTFIXED); 12619 } 12620 } 12621 12622 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); 12623 setvar("PPID", ppid, 0); 12624 12625 p = lookupvar("PWD"); 12626 if (p) 12627 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 12628 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 12629 p = '\0'; 12630 setpwd(p, 0); 12631 } 12632 } 12633 12634 /* 12635 * Process the shell command line arguments. 12636 */ 12637 static void 12638 procargs(int argc, char **argv) 12639 { 12640 int i; 12641 const char *xminusc; 12642 char **xargv; 12643 12644 xargv = argv; 12645 arg0 = xargv[0]; 12646 if (argc > 0) 12647 xargv++; 12648 for (i = 0; i < NOPTS; i++) 12649 optlist[i] = 2; 12650 argptr = xargv; 12651 options(1); 12652 xargv = argptr; 12653 xminusc = minusc; 12654 if (*xargv == NULL) { 12655 if (xminusc) 12656 ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); 12657 sflag = 1; 12658 } 12659 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 12660 iflag = 1; 12661 if (mflag == 2) 12662 mflag = iflag; 12663 for (i = 0; i < NOPTS; i++) 12664 if (optlist[i] == 2) 12665 optlist[i] = 0; 12666 #if DEBUG == 2 12667 debug = 1; 12668 #endif 12669 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 12670 if (xminusc) { 12671 minusc = *xargv++; 12672 if (*xargv) 12673 goto setarg0; 12674 } else if (!sflag) { 12675 setinputfile(*xargv, 0); 12676 setarg0: 12677 arg0 = *xargv++; 12678 commandname = arg0; 12679 } 12680 12681 shellparam.p = xargv; 12682 #if ENABLE_ASH_GETOPTS 12683 shellparam.optind = 1; 12684 shellparam.optoff = -1; 12685 #endif 12686 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 12687 while (*xargv) { 12688 shellparam.nparam++; 12689 xargv++; 12690 } 12691 optschanged(); 12692 } 12693 12694 /* 12695 * Read /etc/profile or .profile. 12696 */ 12697 static void 12698 read_profile(const char *name) 12699 { 12700 int skip; 12701 12702 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) 12703 return; 12704 skip = cmdloop(0); 12705 popfile(); 12706 if (skip) 12707 exitshell(); 12708 } 12709 12710 /* 12711 * This routine is called when an error or an interrupt occurs in an 12712 * interactive shell and control is returned to the main command loop. 12713 */ 12714 static void 12715 reset(void) 12716 { 12717 /* from eval.c: */ 12718 evalskip = 0; 12719 loopnest = 0; 12720 /* from input.c: */ 12721 parselleft = parsenleft = 0; /* clear input buffer */ 12722 popallfiles(); 12723 /* from parser.c: */ 12724 tokpushback = 0; 12725 checkkwd = 0; 12726 /* from redir.c: */ 12727 clearredir(0); 12728 } 12729 12730 #if PROFILE 12731 static short profile_buf[16384]; 12732 extern int etext(); 12733 #endif 12734 12735 /* 12736 * Main routine. We initialize things, parse the arguments, execute 12737 * profiles if we're a login shell, and then call cmdloop to execute 12738 * commands. The setjmp call sets up the location to jump to when an 12739 * exception occurs. When an exception occurs the variable "state" 12740 * is used to figure out how far we had gotten. 12741 */ 12742 int ash_main(int argc, char **argv); 12743 int ash_main(int argc, char **argv) 12744 { 12745 char *shinit; 12746 volatile int state; 12747 struct jmploc jmploc; 12748 struct stackmark smark; 12749 12750 #if PROFILE 12751 monitor(4, etext, profile_buf, sizeof(profile_buf), 50); 12752 #endif 12753 12754 #if ENABLE_FEATURE_EDITING 12755 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); 12756 #endif 12757 state = 0; 12758 if (setjmp(jmploc.loc)) { 12759 int e; 12760 int s; 12761 12762 reset(); 12763 12764 e = exception; 12765 if (e == EXERROR) 12766 exitstatus = 2; 12767 s = state; 12768 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 12769 exitshell(); 12770 12771 if (e == EXINT) { 12772 outcslow('\n', stderr); 12773 } 12774 popstackmark(&smark); 12775 FORCE_INT_ON; /* enable interrupts */ 12776 if (s == 1) 12777 goto state1; 12778 if (s == 2) 12779 goto state2; 12780 if (s == 3) 12781 goto state3; 12782 goto state4; 12783 } 12784 exception_handler = &jmploc; 12785 #if DEBUG 12786 opentrace(); 12787 trace_puts("Shell args: "); 12788 trace_puts_args(argv); 12789 #endif 12790 rootpid = getpid(); 12791 12792 #if ENABLE_ASH_RANDOM_SUPPORT 12793 rseed = rootpid + time(NULL); 12794 #endif 12795 init(); 12796 setstackmark(&smark); 12797 procargs(argc, argv); 12798 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 12799 if (iflag) { 12800 const char *hp = lookupvar("HISTFILE"); 12801 12802 if (hp == NULL) { 12803 hp = lookupvar("HOME"); 12804 if (hp != NULL) { 12805 char *defhp = concat_path_file(hp, ".ash_history"); 12806 setvar("HISTFILE", defhp, 0); 12807 free(defhp); 12808 } 12809 } 12810 } 12811 #endif 12812 if (argv[0] && argv[0][0] == '-') 12813 isloginsh = 1; 12814 if (isloginsh) { 12815 state = 1; 12816 read_profile("/etc/profile"); 12817 state1: 12818 state = 2; 12819 read_profile(".profile"); 12820 } 12821 state2: 12822 state = 3; 12823 if ( 12824 #ifndef linux 12825 getuid() == geteuid() && getgid() == getegid() && 12826 #endif 12827 iflag 12828 ) { 12829 shinit = lookupvar("ENV"); 12830 if (shinit != NULL && *shinit != '\0') { 12831 read_profile(shinit); 12832 } 12833 } 12834 state3: 12835 state = 4; 12836 if (minusc) 12837 evalstring(minusc, 0); 12838 12839 if (sflag || minusc == NULL) { 12840 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 12841 if ( iflag ) { 12842 const char *hp = lookupvar("HISTFILE"); 12843 12844 if (hp != NULL) 12845 line_input_state->hist_file = hp; 12846 } 12847 #endif 12848 state4: /* XXX ??? - why isn't this before the "if" statement */ 12849 cmdloop(1); 12850 } 12851 #if PROFILE 12852 monitor(0); 12853 #endif 12854 #ifdef GPROF 12855 { 12856 extern void _mcleanup(void); 12857 _mcleanup(); 12858 } 12859 #endif 12860 exitshell(); 12861 /* NOTREACHED */ 12862 } 12863 12864 #if DEBUG 12865 const char *applet_name = "debug stuff usage"; 13664 12866 int main(int argc, char **argv) 13665 12867 { … … 13667 12869 } 13668 12870 #endif 12871 13669 12872 13670 12873 /*- -
branches/stable/mindi-busybox/shell/hush.c
r821 r1770 21 21 * 22 22 * Other credits: 23 * simple_itoa() was lifted from boa-0.93.1524 23 * b_addchr() derived from similar w_addchar function in glibc-2.2 25 24 * setup_redirect(), redirect_opt_num(), and big chunks of main() 26 * 25 * and many builtins derived from contributions by Erik Andersen 27 26 * miscellaneous bugfixes from Matt Kraai 28 27 * … … 39 38 * 40 39 * Bash grammar not implemented: (how many of these were in original sh?) 41 * $@ (those sure look like weird quoting rules)42 40 * $_ 43 41 * ! negation operator for pipes … … 53 51 * Functions 54 52 * Major bugs: 55 * job handling woefully incomplete and buggy 53 * job handling woefully incomplete and buggy (improved --vda) 56 54 * reserved word execution woefully incomplete and buggy 57 55 * to-do: … … 73 71 * more testing, especially quoting rules and redirection 74 72 * document how quoting rules not precisely followed for variable assignments 75 * maybe change map[] to use 2-bit entries73 * maybe change charmap[] to use 2-bit entries 76 74 * (eventually) remove all the printf's 77 75 * … … 79 77 */ 80 78 81 #include "busybox.h" 82 #include <ctype.h> /* isalpha, isdigit */ 83 #include <unistd.h> /* getpid */ 84 #include <stdlib.h> /* getenv, atoi */ 85 #include <string.h> /* strchr */ 86 #include <stdio.h> /* popen etc. */ 79 87 80 #include <glob.h> /* glob, of course */ 88 #include <stdarg.h> /* va_list */89 #include <errno.h>90 #include <fcntl.h>91 81 #include <getopt.h> /* should be pretty obvious */ 92 93 #include <sys/stat.h> /* ulimit */94 #include <sys/types.h>95 #include <sys/wait.h>96 #include <signal.h>97 98 82 /* #include <dmalloc.h> */ 99 /* #define DEBUG_SHELL */ 100 101 #if 1 102 #include "cmdedit.h" 103 #else 104 #define bb_applet_name "hush" 105 //#include "standalone.h" 106 #define hush_main main 107 #undef CONFIG_FEATURE_SH_FANCY_PROMPT 108 #define BB_BANNER "" 109 #endif 110 #define SPECIAL_VAR_SYMBOL 03 111 #define FLAG_EXIT_FROM_LOOP 1 112 #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ 113 #define FLAG_REPARSING (1 << 2) /* >=2nd pass */ 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 89 /* If you comment out one of these below, it will be #defined later 90 * to perform debug printfs to stderr: */ 91 #define debug_printf(...) do {} while (0) 92 /* Finer-grained debug switches */ 93 #define debug_printf_parse(...) do {} while (0) 94 #define debug_print_tree(a, b) do {} while (0) 95 #define debug_printf_exec(...) do {} while (0) 96 #define debug_printf_jobs(...) do {} while (0) 97 #define debug_printf_expand(...) do {} while (0) 98 #define debug_printf_clean(...) do {} while (0) 99 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 143 #endif 144 145 #define SPECIAL_VAR_SYMBOL 3 146 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 */ 114 150 115 151 typedef enum { … … 123 159 /* The descrip member of this structure is only used to make debugging 124 160 * output pretty */ 125 static const struct {int mode; int default_fd; const char *descrip;} redir_table[] = { 161 static const struct { 162 int mode; 163 signed char default_fd; 164 char descrip[3]; 165 } redir_table[] = { 126 166 { 0, 0, "()" }, 127 167 { O_RDONLY, 0, "<" }, … … 142 182 typedef enum { 143 183 RES_NONE = 0, 184 #if ENABLE_HUSH_IF 144 185 RES_IF = 1, 145 186 RES_THEN = 2, … … 147 188 RES_ELSE = 4, 148 189 RES_FI = 5, 190 #endif 191 #if ENABLE_HUSH_LOOPS 149 192 RES_FOR = 6, 150 193 RES_WHILE = 7, … … 152 195 RES_DO = 9, 153 196 RES_DONE = 10, 154 RES_XXXX = 11, 155 RES_IN = 12, 197 RES_IN = 11, 198 #endif 199 RES_XXXX = 12, 156 200 RES_SNTX = 13 157 201 } reserved_style; 158 #define FLAG_END (1<<RES_NONE) 159 #define FLAG_IF (1<<RES_IF) 160 #define FLAG_THEN (1<<RES_THEN) 161 #define FLAG_ELIF (1<<RES_ELIF) 162 #define FLAG_ELSE (1<<RES_ELSE) 163 #define FLAG_FI (1<<RES_FI) 164 #define FLAG_FOR (1<<RES_FOR) 165 #define FLAG_WHILE (1<<RES_WHILE) 166 #define FLAG_UNTIL (1<<RES_UNTIL) 167 #define FLAG_DO (1<<RES_DO) 168 #define FLAG_DONE (1<<RES_DONE) 169 #define FLAG_IN (1<<RES_IN) 170 #define FLAG_START (1<<RES_XXXX) 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 }; 171 221 172 222 /* This holds pointers to the various results of parsing */ … … 176 226 struct pipe *pipe; 177 227 struct redir_struct *pending_redirect; 178 reserved_style w; 179 int old_flag; /* for figuring out valid reserved words */ 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 */ 180 231 struct p_context *stack; 181 int type; /* define type of parser : ";$" common or special symbol */182 232 /* How about quoting status? */ 183 233 }; 184 234 185 235 struct redir_struct { 186 redir_type type; /* type of redirection*/187 int fd; /* file descriptor being redirected*/188 int dup; /* -1, or file descriptor being duplicated */189 struct redir_struct *next; /* pointer to the next redirect in the list*/190 glob_t word; 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 */ 191 241 }; 192 242 193 243 struct child_prog { 194 pid_t pid; /* 0 if exited */ 195 char **argv; /* program name and arguments */ 196 struct pipe *group; /* if non-NULL, first in group or subshell */ 197 int subshell; /* flag, non-zero if group must be forked */ 198 struct redir_struct *redirects; /* I/O redirections */ 199 glob_t glob_result; /* result of parameter globbing */ 200 int is_stopped; /* is the program currently running? */ 201 struct pipe *family; /* pointer back to the child's parent pipe */ 202 int sp; /* number of SPECIAL_VAR_SYMBOL */ 203 int type; 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; 204 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 */ 205 262 206 263 struct pipe { 207 int jobid; /* job number */ 208 int num_progs; /* total number of programs in job */ 209 int running_progs; /* number of programs running */ 210 char *text; /* name of job */ 211 char *cmdbuf; /* buffer various argv's point into */ 212 pid_t pgrp; /* process group ID for the job */ 213 struct child_prog *progs; /* array of commands in pipe */ 214 struct pipe *next; /* to track background commands */ 215 int stopped_progs; /* number of programs alive, but stopped */ 216 int job_context; /* bitmask defining current context */ 217 pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ 218 reserved_style r_mode; /* supports if, for, while, until */ 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... */ 219 278 }; 220 279 221 280 struct close_me { 281 struct close_me *next; 222 282 int fd; 223 struct close_me *next;224 283 }; 225 284 226 struct variables { 227 char *name; 228 char *value; 229 int flg_export; 230 int flg_read_only; 231 struct variables *next; 285 /* On program start, environ points to initial environment. 286 * putenv adds new pointers into it, unsetenv removes them. 287 * Neither of these (de)allocates the strings. 288 * setenv allocates new strings in malloc space and does putenv, 289 * and thus setenv is unusable (leaky) for shell's purposes */ 290 #define setenv(...) setenv_is_leaky_dont_use() 291 struct variable { 292 struct variable *next; 293 char *varstr; /* points to "name=" portion */ 294 int max_len; /* if > 0, name is part of initial env; else name is malloced */ 295 smallint flg_export; /* putenv should be done on this var */ 296 smallint flg_read_only; 232 297 }; 233 234 /* globals, connect us to the outside world235 * the first three support $?, $#, and $1 */236 static char **global_argv;237 static int global_argc;238 static int last_return_code;239 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */240 241 /* "globals" within this file */242 static char *ifs;243 static unsigned char map[256];244 static int fake_mode;245 static int interactive;246 static struct close_me *close_me_head;247 static const char *cwd;248 static struct pipe *job_list;249 static unsigned int last_bg_pid;250 static int last_jobid;251 static unsigned int shell_terminal;252 static char *PS1;253 static char *PS2;254 static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };255 static struct variables *top_vars = &shell_ver;256 257 258 #define B_CHUNK (100)259 #define B_NOSPAC 1260 298 261 299 typedef struct { … … 267 305 } o_string; 268 306 #define NULL_O_STRING {NULL,0,0,0,0} 269 /* used for initialization: 270 o_string foo = NULL_O_STRING; */ 307 /* used for initialization: o_string foo = NULL_O_STRING; */ 271 308 272 309 /* I can almost use ordinary FILE *. Is open_memstream() universally … … 274 311 struct in_str { 275 312 const char *p; 313 /* eof_flag=1: last char in ->p is really an EOF */ 314 char eof_flag; /* meaningless if ->p == NULL */ 276 315 char peek_buf[2]; 277 int __promptme; 278 int promptmode; 316 #if ENABLE_HUSH_INTERACTIVE 317 smallint promptme; 318 smallint promptmode; /* 0: PS1, 1: PS2 */ 319 #endif 279 320 FILE *file; 280 321 int (*get) (struct in_str *); … … 284 325 #define b_peek(input) ((input)->peek(input)) 285 326 327 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: $ */ 332 }; 333 334 #define HUSH_VER_STR "0.02" 335 336 /* "Globals" within this file */ 337 338 /* Sorted roughly by size (smaller offsets == smaller code) */ 339 struct globals { 340 #if ENABLE_HUSH_INTERACTIVE 341 /* 'interactive_fd' is a fd# open to ctty, if we have one 342 * _AND_ if we decided to act interactively */ 343 int interactive_fd; 344 const char *PS1; 345 const char *PS2; 346 #endif 347 #if ENABLE_FEATURE_EDITING 348 line_input_t *line_input_state; 349 #endif 350 #if ENABLE_HUSH_JOB 351 int run_list_level; 352 pid_t saved_task_pgrp; 353 pid_t saved_tty_pgrp; 354 int last_jobid; 355 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 */ 361 char **global_argv; 362 int global_argc; 363 int last_return_code; 364 const char *ifs; 365 struct close_me *close_me_head; 366 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 373 #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 286 429 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 287 430 288 struct built_in_command { 289 const char *cmd; /* name */ 290 const char *descr; /* description */ 291 int (*function) (struct child_prog *); /* function ptr */ 292 }; 293 294 /* belongs in busybox.h */ 295 static inline int max(int a, int b) { 296 return (a>b)?a:b; 297 } 298 299 /* This should be in utility.c */ 300 #ifdef DEBUG_SHELL 301 static void debug_printf(const char *format, ...) 302 { 303 va_list args; 304 va_start(args, format); 305 vfprintf(stderr, format, args); 306 va_end(args); 307 } 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 308 444 #else 309 static inline void debug_printf(const char *format ATTRIBUTE_UNUSED, ...) { } 310 #endif 311 #define final_printf debug_printf 312 313 static void __syntax(char *file, int line) { 314 bb_error_msg("syntax error %s:%d", file, line); 315 } 316 #define syntax() __syntax(__FILE__, __LINE__) 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 317 455 318 456 /* Index of subroutines: */ 319 457 /* function prototypes for builtins */ 320 static int builtin_cd(struct child_prog *child); 321 static int builtin_env(struct child_prog *child); 322 static int builtin_eval(struct child_prog *child); 323 static int builtin_exec(struct child_prog *child); 324 static int builtin_exit(struct child_prog *child); 325 static int builtin_export(struct child_prog *child); 326 static int builtin_fg_bg(struct child_prog *child); 327 static int builtin_help(struct child_prog *child); 328 static int builtin_jobs(struct child_prog *child); 329 static int builtin_pwd(struct child_prog *child); 330 static int builtin_read(struct child_prog *child); 331 static int builtin_set(struct child_prog *child); 332 static int builtin_shift(struct child_prog *child); 333 static int builtin_source(struct child_prog *child); 334 static int builtin_umask(struct child_prog *child); 335 static int builtin_unset(struct child_prog *child); 336 static int builtin_not_written(struct child_prog *child); 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); 466 #endif 467 #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); 337 478 /* o_string manipulation: */ 338 479 static int b_check_space(o_string *o, int len); … … 340 481 static void b_reset(o_string *o); 341 482 static int b_addqchr(o_string *o, int ch, int quote); 342 static int b_adduint(o_string *o, unsigned int i);343 483 /* in_str manipulations: */ 344 484 static int static_get(struct in_str *i); … … 353 493 static void close_all(void); 354 494 /* "run" the final data structures: */ 355 static char *indenter(int i); 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 356 499 static int free_pipe_list(struct pipe *head, int indent); 357 500 static int free_pipe(struct pipe *pi, int indent); … … 359 502 static int setup_redirects(struct child_prog *prog, int squirrel[]); 360 503 static int run_list_real(struct pipe *pi); 504 static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; 361 505 static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; 362 506 static int run_pipe_real(struct pipe *pi); … … 376 520 static int redirect_dup_num(struct in_str *input); 377 521 static int redirect_opt_num(o_string *o); 378 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); 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 379 525 static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); 380 static char *lookup_param(char *src); 381 static char *make_string(char **inp); 526 static const char *lookup_param(const char *src); 382 527 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 383 static int parse_string(o_string *dest, struct p_context *ctx, const char *src); 384 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); 528 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); 385 529 /* setup: */ 386 static int parse_ stream_outer(struct in_str *inp, intflag);387 static int parse_ string_outer(const char *s, intflag);388 static int parse_ file_outer(FILE *f);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); 389 533 /* job management: */ 390 534 static int checkjobs(struct pipe* fg_pipe); 535 #if ENABLE_HUSH_JOB 536 static int checkjobs_and_fg_shell(struct pipe* fg_pipe); 391 537 static void insert_bg_job(struct pipe *pi); 392 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 393 543 /* local variable support */ 394 static char **make_list_in(char **inp, char *name); 395 static char *insert_var_value(char *inp); 396 static char *get_local_var(const char *var); 397 static void unset_local_var(const char *name); 398 static int set_local_var(const char *s, int flg_export); 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); 399 552 400 553 /* Table of built-in functions. They can be forked or not, depending on 401 554 * context: within pipes, they fork. As simple commands, they do not. 402 555 * When used in non-forking context, they can change global variables 403 * in the parent shell process. If forked, of course they can 556 * in the parent shell process. If forked, of course they cannot. 404 557 * For example, 'unset foo | whatever' will parse and run, but foo will 405 558 * still be set at the end. */ 559 struct built_in_command { 560 const char *cmd; /* name */ 561 int (*function) (char **argv); /* function ptr */ 562 #if ENABLE_HUSH_HELP 563 const char *descr; /* description */ 564 #define BLTIN(cmd, func, help) { cmd, func, help } 565 #else 566 #define BLTIN(cmd, func, help) { cmd, func } 567 #endif 568 }; 569 406 570 static const struct built_in_command bltins[] = { 407 {"bg", "Resume a job in the background", builtin_fg_bg}, 408 {"break", "Exit for, while or until loop", builtin_not_written}, 409 {"cd", "Change working directory", builtin_cd}, 410 {"continue", "Continue for, while or until loop", builtin_not_written}, 411 {"env", "Print all environment variables", builtin_env}, 412 {"eval", "Construct and run shell command", builtin_eval}, 413 {"exec", "Exec command, replacing this shell with the exec'd process", 414 builtin_exec}, 415 {"exit", "Exit from shell()", builtin_exit}, 416 {"export", "Set environment variable", builtin_export}, 417 {"fg", "Bring job into the foreground", builtin_fg_bg}, 418 {"jobs", "Lists the active jobs", builtin_jobs}, 419 {"pwd", "Print current directory", builtin_pwd}, 420 {"read", "Input environment variable", builtin_read}, 421 {"return", "Return from a function", builtin_not_written}, 422 {"set", "Set/unset shell local variables", builtin_set}, 423 {"shift", "Shift positional parameters", builtin_shift}, 424 {"trap", "Trap signals", builtin_not_written}, 425 {"ulimit","Controls resource limits", builtin_not_written}, 426 {"umask","Sets file creation mask", builtin_umask}, 427 {"unset", "Unset environment variable", builtin_unset}, 428 {".", "Source-in and run commands in a file", builtin_source}, 429 {"help", "List shell built-in commands", builtin_help}, 430 {NULL, NULL, NULL} 571 #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"), 581 #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"), 596 #if ENABLE_HUSH_HELP 597 BLTIN("help" , builtin_help, "List shell built-in commands"), 598 #endif 599 BLTIN(NULL, NULL, NULL) 431 600 }; 432 601 602 #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 } 686 687 /* Restores tty foreground process group, and exits. 688 * May be called as signal handler for fatal signal 689 * (will faithfully resend signal to itself, producing correct exit state) 690 * or called directly with -EXITCODE. 691 * We also call it if xfunc is exiting. */ 692 static void sigexit(int sig) ATTRIBUTE_NORETURN; 693 static void sigexit(int sig) 694 { 695 sigset_t block_all; 696 697 /* 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); 703 704 /* Not a signal, just exit */ 705 if (sig <= 0) 706 _exit(- sig); 707 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 } 715 716 /* Restores tty foreground process group, and exits. */ 717 static void hush_exit(int exitcode) ATTRIBUTE_NORETURN; 718 static void hush_exit(int exitcode) 719 { 720 fflush(NULL); /* flush all streams */ 721 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 433 734 static const char *set_cwd(void) 434 735 { 435 if (cwd==bb_msg_unknown)436 cwd = NULL; /* x getcwd(arg) called free(arg)*/437 cwd = x getcwd((char *)cwd);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); 438 739 if (!cwd) 439 740 cwd = bb_msg_unknown; … … 442 743 443 744 /* built-in 'eval' handler */ 444 static int builtin_eval(struct child_prog *child) 445 { 446 char *str = NULL; 745 static int builtin_eval(char **argv) 746 { 447 747 int rcode = EXIT_SUCCESS; 448 748 449 if ( child->argv[1]) {450 str = make_string(child->argv + 1);451 parse_ string_outer(str,FLAG_EXIT_FROM_LOOP |452 FLAG_PARSE_SEMICOLON);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); 453 753 free(str); 454 754 rcode = last_return_code; … … 458 758 459 759 /* built-in 'cd <path>' handler */ 460 static int builtin_cd( struct child_prog *child)461 { 462 c har *newdir;463 if ( child->argv[1] == NULL)464 newdir = getenv("HOME") ;760 static int builtin_cd(char **argv) 761 { 762 const char *newdir; 763 if (argv[1] == NULL) 764 newdir = getenv("HOME") ? : "/"; 465 765 else 466 newdir = child->argv[1];766 newdir = argv[1]; 467 767 if (chdir(newdir)) { 468 768 printf("cd: %s: %s\n", newdir, strerror(errno)); … … 473 773 } 474 774 475 /* built-in 'env' handler */ 476 static int builtin_env(struct child_prog *dummy ATTRIBUTE_UNUSED) 477 { 478 char **e = environ; 479 if (e == NULL) return EXIT_FAILURE; 480 for (; *e; e++) { 481 puts(*e); 482 } 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; 826 putenv(var->varstr); 827 } 828 /* bash does not return an error when trying to export 829 * an undefined variable. Do likewise. */ 830 return EXIT_SUCCESS; 831 } 832 833 set_local_var(xstrdup(name), 1); 483 834 return EXIT_SUCCESS; 484 835 } 485 836 486 /* built-in 'exec' handler */ 487 static int builtin_exec(struct child_prog *child) 488 { 489 if (child->argv[1] == NULL) 490 return EXIT_SUCCESS; /* Really? */ 491 child->argv++; 492 pseudo_exec(child); 493 /* never returns */ 494 } 495 496 /* built-in 'exit' handler */ 497 static int builtin_exit(struct child_prog *child) 498 { 499 if (child->argv[1] == NULL) 500 exit(last_return_code); 501 exit (atoi(child->argv[1])); 502 } 503 504 /* built-in 'export VAR=value' handler */ 505 static int builtin_export(struct child_prog *child) 506 { 507 int res = 0; 508 char *name = child->argv[1]; 509 510 if (name == NULL) { 511 return (builtin_env(child)); 512 } 513 514 name = strdup(name); 515 516 if(name) { 517 char *value = strchr(name, '='); 518 519 if (!value) { 520 char *tmp; 521 /* They are exporting something without an =VALUE */ 522 523 value = get_local_var(name); 524 if (value) { 525 size_t ln = strlen(name); 526 527 tmp = realloc(name, ln+strlen(value)+2); 528 if(tmp==NULL) 529 res = -1; 530 else { 531 sprintf(tmp+ln, "=%s", value); 532 name = tmp; 533 } 534 } else { 535 /* bash does not return an error when trying to export 536 * an undefined variable. Do likewise. */ 537 res = 1; 538 } 539 } 540 } 541 if (res<0) 542 bb_perror_msg("export"); 543 else if(res==0) 544 res = set_local_var(name, 1); 545 else 546 res = 0; 547 free(name); 548 return res; 549 } 550 837 #if ENABLE_HUSH_JOB 551 838 /* built-in 'fg' and 'bg' handler */ 552 static int builtin_fg_bg( struct child_prog *child)839 static int builtin_fg_bg(char **argv) 553 840 { 554 841 int i, jobnum; 555 struct pipe *pi =NULL;556 557 if (!interactive )842 struct pipe *pi; 843 844 if (!interactive_fd) 558 845 return EXIT_FAILURE; 559 846 /* If they gave us no args, assume they want the last backgrounded task */ 560 if (! child->argv[1]) {847 if (!argv[1]) { 561 848 for (pi = job_list; pi; pi = pi->next) { 562 849 if (pi->jobid == last_jobid) { 563 break; 564 } 565 } 566 if (!pi) { 567 bb_error_msg("%s: no current job", child->argv[0]); 568 return EXIT_FAILURE; 569 } 570 } else { 571 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { 572 bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); 573 return EXIT_FAILURE; 574 } 575 for (pi = job_list; pi; pi = pi->next) { 576 if (pi->jobid == jobnum) { 577 break; 578 } 579 } 580 if (!pi) { 581 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); 582 return EXIT_FAILURE; 583 } 584 } 585 586 if (*child->argv[0] == 'f') { 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 representation 869 // of job being foregrounded (like "sleep 1 | cat") 870 if (*argv[0] == 'f') { 587 871 /* Put the job into the foreground. */ 588 tcsetpgrp( shell_terminal, pi->pgrp);872 tcsetpgrp(interactive_fd, pi->pgrp); 589 873 } 590 874 591 875 /* Restart the processes in the job */ 592 for (i = 0; i < pi->num_progs; i++) 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); 593 879 pi->progs[i].is_stopped = 0; 594 595 if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { 596 if (i == ESRCH) { 597 remove_bg_job(pi); 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; 598 888 } else { 599 889 bb_perror_msg("kill (SIGCONT)"); … … 601 891 } 602 892 603 pi->stopped_progs = 0; 893 if (*argv[0] == 'f') { 894 remove_bg_job(pi); 895 return checkjobs_and_fg_shell(pi); 896 } 604 897 return EXIT_SUCCESS; 605 898 } 899 #endif 606 900 607 901 /* built-in 'help' handler */ 608 static int builtin_help(struct child_prog *dummy ATTRIBUTE_UNUSED) 902 #if ENABLE_HUSH_HELP 903 static int builtin_help(char **argv ATTRIBUTE_UNUSED) 609 904 { 610 905 const struct built_in_command *x; … … 613 908 printf("-------------------\n"); 614 909 for (x = bltins; x->cmd; x++) { 615 if (x->descr==NULL)616 continue;617 910 printf("%s\t%s\n", x->cmd, x->descr); 618 911 } … … 620 913 return EXIT_SUCCESS; 621 914 } 622 915 #endif 916 917 #if ENABLE_HUSH_JOB 623 918 /* built-in 'jobs' handler */ 624 static int builtin_jobs( struct child_prog *childATTRIBUTE_UNUSED)919 static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) 625 920 { 626 921 struct pipe *job; 627 c har *status_string;922 const char *status_string; 628 923 629 924 for (job = job_list; job; job = job->next) { … … 633 928 status_string = "Running"; 634 929 635 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job-> text);930 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); 636 931 } 637 932 return EXIT_SUCCESS; 638 933 } 639 934 #endif 640 935 641 936 /* built-in 'pwd' handler */ 642 static int builtin_pwd( struct child_prog *dummyATTRIBUTE_UNUSED)937 static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) 643 938 { 644 939 puts(set_cwd()); … … 647 942 648 943 /* built-in 'read VAR' handler */ 649 static int builtin_read(struct child_prog *child) 650 { 651 int res; 652 653 if (child->argv[1]) { 654 char string[BUFSIZ]; 655 char *var = 0; 656 657 string[0] = 0; /* In case stdin has only EOF */ 658 /* read string */ 659 fgets(string, sizeof(string), stdin); 660 chomp(string); 661 var = malloc(strlen(child->argv[1])+strlen(string)+2); 662 if(var) { 663 sprintf(var, "%s=%s", child->argv[1], string); 664 res = set_local_var(var, 0); 665 } else 666 res = -1; 667 if (res) 668 bb_perror_msg("read"); 669 free(var); /* So not move up to avoid breaking errno */ 670 return res; 671 } else { 672 do res=getchar(); while(res!='\n' && res!=EOF); 673 return 0; 674 } 675 } 676 677 /* built-in 'set VAR=value' handler */ 678 static int builtin_set(struct child_prog *child) 679 { 680 char *temp = child->argv[1]; 681 struct variables *e; 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; 682 958 683 959 if (temp == NULL) 684 for (e = top_vars; e; e=e->next)685 p rintf("%s=%s\n", e->name, e->value);960 for (e = top_var; e; e = e->next) 961 puts(e->varstr); 686 962 else 687 set_local_var( temp, 0);688 689 963 set_local_var(xstrdup(temp), 0); 964 965 return EXIT_SUCCESS; 690 966 } 691 967 692 968 693 969 /* Built-in 'shift' handler */ 694 static int builtin_shift( struct child_prog *child)695 { 696 int n =1;697 if ( child->argv[1]) {698 n =atoi(child->argv[1]);699 } 700 if (n >=0 && n<global_argc) {701 /* XXX This probably breaks $0 */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]; 702 978 global_argc -= n; 703 979 global_argv += n; 704 980 return EXIT_SUCCESS; 705 } else { 706 return EXIT_FAILURE; 707 } 981 } 982 return EXIT_FAILURE; 708 983 } 709 984 710 985 /* Built-in '.' handler (read-in and execute commands from file) */ 711 static int builtin_source( struct child_prog *child)986 static int builtin_source(char **argv) 712 987 { 713 988 FILE *input; 714 989 int status; 715 990 716 if ( child->argv[1] == NULL)991 if (argv[1] == NULL) 717 992 return EXIT_FAILURE; 718 993 719 994 /* XXX search through $PATH is missing */ 720 input = fopen( child->argv[1], "r");995 input = fopen(argv[1], "r"); 721 996 if (!input) { 722 bb_error_msg(" Couldn't open file '%s'", child->argv[1]);997 bb_error_msg("cannot open '%s'", argv[1]); 723 998 return EXIT_FAILURE; 724 999 } … … 727 1002 /* XXX argv and argc are broken; need to save old global_argv 728 1003 * (pointer only is OK!) on this stack frame, 729 * set global_argv= child->argv+1, recurse, and restore. */1004 * set global_argv=argv+1, recurse, and restore. */ 730 1005 mark_open(fileno(input)); 731 status = parse_ file_outer(input);1006 status = parse_and_run_file(input); 732 1007 mark_closed(fileno(input)); 733 1008 fclose(input); 734 return (status);735 } 736 737 static int builtin_umask( struct child_prog *child)1009 return status; 1010 } 1011 1012 static int builtin_umask(char **argv) 738 1013 { 739 1014 mode_t new_umask; 740 const char *arg = child->argv[1];1015 const char *arg = argv[1]; 741 1016 char *end; 742 1017 if (arg) { 743 new_umask =strtoul(arg, &end, 8);744 if (*end !='\0' || end == arg) {1018 new_umask = strtoul(arg, &end, 8); 1019 if (*end != '\0' || end == arg) { 745 1020 return EXIT_FAILURE; 746 1021 } 747 1022 } else { 748 printf("%.3o\n", (unsigned int) (new_umask=umask(0))); 1023 new_umask = umask(0); 1024 printf("%.3o\n", (unsigned) new_umask); 749 1025 } 750 1026 umask(new_umask); … … 753 1029 754 1030 /* built-in 'unset VAR' handler */ 755 static int builtin_unset( struct child_prog *child)756 { 757 /* bash returned alreadytrue */758 unset_local_var( child->argv[1]);1031 static int builtin_unset(char **argv) 1032 { 1033 /* bash always returns true */ 1034 unset_local_var(argv[1]); 759 1035 return EXIT_SUCCESS; 760 1036 } 761 1037 762 static int builtin_not_written(struct child_prog *child)763 {764 printf("builtin_%s not written\n",child->argv[0]);765 return EXIT_FAILURE;766 }1038 //static int builtin_not_written(char **argv) 1039 //{ 1040 // printf("builtin_%s not written\n", argv[0]); 1041 // return EXIT_FAILURE; 1042 //} 767 1043 768 1044 static int b_check_space(o_string *o, int len) … … 771 1047 * in here, such as setting a maximum string length */ 772 1048 if (o->length + len > o->maxlen) { 773 char *old_data = o->data; 774 /* assert (data == NULL || o->maxlen != 0); */ 775 o->maxlen += max(2*len, B_CHUNK); 776 o->data = realloc(o->data, 1 + o->maxlen); 777 if (o->data == NULL) { 778 free(old_data); 779 } 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); 780 1052 } 781 1053 return o->data == NULL; … … 784 1056 static int b_addchr(o_string *o, int ch) 785 1057 { 786 debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); 787 if (b_check_space(o, 1)) return B_NOSPAC; 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; 788 1061 o->data[o->length] = ch; 789 1062 o->length++; … … 796 1069 o->length = 0; 797 1070 o->nonnull = 0; 798 if (o->data != NULL) *o->data = '\0'; 1071 if (o->data != NULL) 1072 *o->data = '\0'; 799 1073 } 800 1074 … … 812 1086 static int b_addqchr(o_string *o, int ch, int quote) 813 1087 { 814 if (quote && strchr("*?[\\", ch)) {1088 if (quote && strchr("*?[\\", ch)) { 815 1089 int rc; 816 1090 rc = b_addchr(o, '\\'); 817 if (rc) return rc; 1091 if (rc) 1092 return rc; 818 1093 } 819 1094 return b_addchr(o, ch); 820 1095 } 821 1096 822 /* belongs in utility.c */823 static char *simple_itoa(unsigned int i)824 {825 /* 21 digits plus null terminator, good for 64-bit or smaller ints */826 static char local[22];827 char *p = &local[21];828 *p-- = '\0';829 do {830 *p-- = '0' + i % 10;831 i /= 10;832 } while (i > 0);833 return p + 1;834 }835 836 static int b_adduint(o_string *o, unsigned int i)837 {838 int r;839 char *p = simple_itoa(i);840 /* no escape checking necessary */841 do r=b_addchr(o, *p++); while (r==0 && *p);842 return r;843 }844 845 1097 static int static_get(struct in_str *i) 846 1098 { 847 int ch =*i->p++;848 if (ch =='\0') return EOF;1099 int ch = *i->p++; 1100 if (ch == '\0') return EOF; 849 1101 return ch; 850 1102 } … … 855 1107 } 856 1108 857 static inline void cmdedit_set_initial_prompt(void) 858 { 859 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT 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 860 1114 PS1 = NULL; 861 1115 #else 862 1116 PS1 = getenv("PS1"); 863 if (PS1==0)1117 if (PS1 == NULL) 864 1118 PS1 = "\\w \\$ "; 865 1119 #endif 866 1120 } 867 868 static inline void setup_prompt_string(int promptmode, char **prompt_str) 869 { 870 debug_printf("setup_prompt_string %d ",promptmode); 871 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT 1121 #endif /* EDITING */ 1122 1123 static const char* setup_prompt_string(int promptmode) 1124 { 1125 const char *prompt_str; 1126 debug_printf("setup_prompt_string %d ", promptmode); 1127 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 872 1128 /* Set up the prompt */ 873 if (promptmode == 1) { 874 free(PS1); 875 PS1=xmalloc(strlen(cwd)+4); 876 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); 877 *prompt_str = PS1; 1129 if (promptmode == 0) { /* PS1 */ 1130 free((char*)PS1); 1131 PS1 = xasprintf("%s %c ", cwd, (geteuid() != 0) ? '$' : '#'); 1132 prompt_str = PS1; 878 1133 } else { 879 *prompt_str = PS2;1134 prompt_str = PS2; 880 1135 } 881 1136 #else 882 *prompt_str = (promptmode==1)? PS1 : PS2; 883 #endif 884 debug_printf("result %s\n",*prompt_str); 1137 prompt_str = (promptmode == 0) ? PS1 : PS2; 1138 #endif 1139 debug_printf("result '%s'\n", prompt_str); 1140 return prompt_str; 885 1141 } 886 1142 887 1143 static void get_user_input(struct in_str *i) 888 1144 { 889 char *prompt_str; 890 static char the_command[BUFSIZ]; 891 892 setup_prompt_string(i->promptmode, &prompt_str); 893 #ifdef CONFIG_FEATURE_COMMAND_EDITING 894 /* 895 ** enable command line editing only while a command line 896 ** is actually being read; otherwise, we'll end up bequeathing 897 ** atexit() handlers and other unwanted stuff to our 898 ** child processes (rob@sysgo.de) 899 */ 900 cmdedit_read_input(prompt_str, the_command); 1145 int r; 1146 const char *prompt_str; 1147 1148 prompt_str = setup_prompt_string(i->promptmode); 1149 #if ENABLE_FEATURE_EDITING 1150 /* 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); 1155 i->eof_flag = (r < 0); 1156 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 } 901 1160 #else 902 1161 fputs(prompt_str, stdout); 903 1162 fflush(stdout); 904 the_command[0]=fgetc(i->file); 905 the_command[1]='\0'; 906 #endif 907 fflush(stdout); 908 i->p = the_command; 909 } 1163 user_input_buf[0] = r = fgetc(i->file); 1164 /*user_input_buf[1] = '\0'; - already is and never changed */ 1165 i->eof_flag = (r == EOF); 1166 #endif 1167 i->p = user_input_buf; 1168 } 1169 #endif /* INTERACTIVE */ 910 1170 911 1171 /* This is the magic location that prints prompts … … 915 1175 int ch; 916 1176 917 ch = 0;918 1177 /* If there is data waiting, eat it up */ 919 1178 if (i->p && *i->p) { 920 ch=*i->p++; 1179 #if ENABLE_HUSH_INTERACTIVE 1180 take_cached: 1181 #endif 1182 ch = *i->p++; 1183 if (i->eof_flag && !*i->p) 1184 ch = EOF; 921 1185 } else { 922 1186 /* need to double check i->file because we might be doing something 923 1187 * more complicated by now, like sourcing or substituting. */ 924 if (i->__promptme && interactive && i->file == stdin) { 925 while(! i->p || (interactive && strlen(i->p)==0) ) { 1188 #if ENABLE_HUSH_INTERACTIVE 1189 if (interactive_fd && i->promptme && i->file == stdin) { 1190 do { 926 1191 get_user_input(i); 927 } 928 i->promptmode =2;929 i-> __promptme = 0;930 if (i->p && *i->p) {931 ch=*i->p++;932 } 933 } else {934 ch = fgetc(i->file);935 }936 937 debug_printf("b_getch: got a %d\n", ch);938 }939 if (ch == '\n') i->__promptme=1; 1192 } while (!*i->p); /* need non-empty line */ 1193 i->promptmode = 1; /* PS2 */ 1194 i->promptme = 0; 1195 goto take_cached; 1196 } 1197 #endif 1198 ch = fgetc(i->file); 1199 } 1200 debug_printf("file_get: got a '%c' %d\n", ch, ch); 1201 #if ENABLE_HUSH_INTERACTIVE 1202 if (ch == '\n') 1203 i->promptme = 1; 1204 #endif 940 1205 return ch; 941 1206 } … … 946 1211 static int file_peek(struct in_str *i) 947 1212 { 1213 int ch; 948 1214 if (i->p && *i->p) { 1215 if (i->eof_flag && !i->p[1]) 1216 return EOF; 949 1217 return *i->p; 950 } else { 951 i->peek_buf[0] = fgetc(i->file); 952 i->peek_buf[1] = '\0'; 953 i->p = i->peek_buf; 954 debug_printf("b_peek: got a %d\n", *i->p); 955 return *i->p; 956 } 1218 } 1219 ch = fgetc(i->file); 1220 i->eof_flag = (ch == EOF); 1221 i->peek_buf[0] = ch; 1222 i->peek_buf[1] = '\0'; 1223 i->p = i->peek_buf; 1224 debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p); 1225 return ch; 957 1226 } 958 1227 … … 961 1230 i->peek = file_peek; 962 1231 i->get = file_get; 963 i->__promptme=1; 964 i->promptmode=1; 1232 #if ENABLE_HUSH_INTERACTIVE 1233 i->promptme = 1; 1234 i->promptmode = 0; /* PS1 */ 1235 #endif 965 1236 i->file = f; 966 1237 i->p = NULL; … … 971 1242 i->peek = static_peek; 972 1243 i->get = static_get; 973 i->__promptme=1; 974 i->promptmode=1; 1244 #if ENABLE_HUSH_INTERACTIVE 1245 i->promptme = 1; 1246 i->promptmode = 0; /* PS1 */ 1247 #endif 975 1248 i->p = s; 1249 i->eof_flag = 0; 976 1250 } 977 1251 … … 997 1271 { 998 1272 struct close_me *c; 999 for (c =close_me_head; c; c=c->next) {1273 for (c = close_me_head; c; c = c->next) { 1000 1274 close(c->fd); 1001 1275 } … … 1010 1284 struct redir_struct *redir; 1011 1285 1012 for (redir =prog->redirects; redir; redir=redir->next) {1286 for (redir = prog->redirects; redir; redir = redir->next) { 1013 1287 if (redir->dup == -1 && redir->word.gl_pathv == NULL) { 1014 1288 /* something went wrong in the parse. Pretend it didn't happen */ … … 1016 1290 } 1017 1291 if (redir->dup == -1) { 1018 mode =redir_table[redir->type].mode;1019 openfd = open (redir->word.gl_pathv[0], mode, 0666);1292 mode = redir_table[redir->type].mode; 1293 openfd = open_or_warn(redir->word.gl_pathv[0], mode); 1020 1294 if (openfd < 0) { 1021 1295 /* this could get lost if stderr has been redirected, but 1022 1296 bash and ash both lose it as well (though zsh doesn't!) */ 1023 bb_perror_msg("error opening %s", redir->word.gl_pathv[0]);1024 1297 return 1; 1025 1298 } … … 1037 1310 dup2(openfd, redir->fd); 1038 1311 if (redir->dup == -1) 1039 close 1312 close(openfd); 1040 1313 } 1041 1314 } … … 1047 1320 { 1048 1321 int i, fd; 1049 for (i =0; i<3; i++) {1322 for (i = 0; i < 3; i++) { 1050 1323 fd = squirrel[i]; 1051 1324 if (fd != -1) { 1052 /* No error checking. I sure wouldn't know what 1053 * to do with an error if I found one! */ 1054 dup2(fd, i); 1055 close(fd); 1325 /* We simply die on error */ 1326 xmove_fd(fd, i); 1056 1327 } 1057 1328 } … … 1061 1332 /* XXX no exit() here. If you don't exec, use _exit instead. 1062 1333 * The at_exit handlers apparently confuse the calling process, 1063 * in particular stdin handling. Not sure why? */1064 static void pseudo_exec (struct child_prog *child)1334 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 1335 static void pseudo_exec_argv(char **argv) 1065 1336 { 1066 1337 int i, rcode; 1067 1338 char *p; 1068 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) { 1353 _exit(EXIT_SUCCESS); 1354 } 1355 1356 argv = expand_strvec_to_strvec(argv); 1357 1358 /* 1359 * Check if the command matches any of the builtins. 1360 * Depending on context, this might be redundant. But it's 1361 * easier to waste a few CPU cycles than it is to figure out 1362 * if this is one of those cases. 1363 */ 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 1373 /* 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; 1380 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 */ 1385 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 1386 execvp(bb_busybox_exec_path, argv); 1387 /* If they called chroot or otherwise made the binary no longer 1388 * executable, fall through */ 1389 } 1390 } 1391 #endif 1392 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 1069 1405 if (child->argv) { 1070 for (i=0; is_assignment(child->argv[i]); i++) { 1071 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); 1072 p = insert_var_value(child->argv[i]); 1073 putenv(strdup(p)); 1074 if (p != child->argv[i]) free(p); 1075 } 1076 child->argv+=i; /* XXX this hack isn't so horrible, since we are about 1077 to exit, and therefore don't need to keep data 1078 structures consistent for free() use. */ 1079 /* If a variable is assigned in a forest, and nobody listens, 1080 * was it ever really set? 1081 */ 1082 if (child->argv[0] == NULL) { 1083 _exit(EXIT_SUCCESS); 1084 } 1085 1086 /* 1087 * Check if the command matches any of the builtins. 1088 * Depending on context, this might be redundant. But it's 1089 * easier to waste a few CPU cycles than it is to figure out 1090 * if this is one of those cases. 1091 */ 1092 for (x = bltins; x->cmd; x++) { 1093 if (strcmp(child->argv[0], x->cmd) == 0 ) { 1094 debug_printf("builtin exec %s\n", child->argv[0]); 1095 rcode = x->function(child); 1096 fflush(stdout); 1097 _exit(rcode); 1098 } 1099 } 1100 1101 /* Check if the command matches any busybox internal commands 1102 * ("applets") here. 1103 * FIXME: This feature is not 100% safe, since 1104 * BusyBox is not fully reentrant, so we have no guarantee the things 1105 * from the .bss are still zeroed, or that things from .data are still 1106 * at their defaults. We could exec ourself from /proc/self/exe, but I 1107 * really dislike relying on /proc for things. We could exec ourself 1108 * from global_argv[0], but if we are in a chroot, we may not be able 1109 * to find ourself... */ 1110 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 1111 { 1112 int argc_l; 1113 char** argv_l=child->argv; 1114 char *name = child->argv[0]; 1115 1116 /* Count argc for use in a second... */ 1117 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); 1118 optind = 1; 1119 debug_printf("running applet %s\n", name); 1120 run_applet_by_name(name, argc_l, child->argv); 1121 } 1122 #endif 1123 debug_printf("exec of %s\n",child->argv[0]); 1124 execvp(child->argv[0],child->argv); 1125 bb_perror_msg("couldn't exec: %s",child->argv[0]); 1126 _exit(1); 1127 } else if (child->group) { 1128 debug_printf("runtime nesting to group\n"); 1129 interactive=0; /* crucial!!!! */ 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"); 1130 1416 rcode = run_list_real(child->group); 1131 1417 /* OK to leak memory by not calling free_pipe_list, 1132 1418 * since this process is about to exit */ 1133 1419 _exit(rcode); 1134 } else { 1135 /* Can happen. See what bash does with ">foo" by itself. */ 1136 debug_printf("trying to pseudo_exec null command\n"); 1137 _exit(EXIT_SUCCESS); 1138 } 1420 } 1421 1422 /* Can happen. See what bash does with ">foo" by itself. */ 1423 debug_printf("trying to pseudo_exec null command\n"); 1424 _exit(EXIT_SUCCESS); 1425 } 1426 1427 #if ENABLE_HUSH_JOB 1428 static const char *get_cmdtext(struct pipe *pi) 1429 { 1430 char **argv; 1431 char *p; 1432 int len; 1433 1434 /* This is subtle. ->cmdtext is created only on first backgrounding. 1435 * (Think "cat, <ctrl-z>, fg, <ctrl-z>, fg, <ctrl-z>...." here...) 1436 * On subsequent bg argv is trashed, but we won't use it */ 1437 if (pi->cmdtext) 1438 return pi->cmdtext; 1439 argv = pi->progs[0].argv; 1440 if (!argv || !argv[0]) 1441 return (pi->cmdtext = xzalloc(1)); 1442 1443 len = 0; 1444 do len += strlen(*argv) + 1; while (*++argv); 1445 pi->cmdtext = p = xmalloc(len); 1446 argv = pi->progs[0].argv; 1447 do { 1448 len = strlen(*argv); 1449 memcpy(p, *argv, len); 1450 p += len; 1451 *p++ = ' '; 1452 } while (*++argv); 1453 p[-1] = '\0'; 1454 return pi->cmdtext; 1139 1455 } 1140 1456 … … 1142 1458 { 1143 1459 struct pipe *thejob; 1460 int i; 1144 1461 1145 1462 /* Linear search for the ID of the job to use */ … … 1149 1466 pi->jobid = thejob->jobid + 1; 1150 1467 1151 /* add thejob to the list of running jobs */1468 /* Add thejob to the list of running jobs */ 1152 1469 if (!job_list) { 1153 1470 thejob = job_list = xmalloc(sizeof(*thejob)); 1154 1471 } else { 1155 for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; 1472 for (thejob = job_list; thejob->next; thejob = thejob->next) 1473 continue; 1156 1474 thejob->next = xmalloc(sizeof(*thejob)); 1157 1475 thejob = thejob->next; 1158 1476 } 1159 1477 1160 /* physically copy the struct job */1478 /* Physically copy the struct job */ 1161 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 } 1162 1488 thejob->next = NULL; 1163 thejob->running_progs = thejob->num_progs; 1164 thejob->stopped_progs = 0; 1165 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ 1166 1167 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) 1168 { 1169 char *bar=thejob->text; 1170 char **foo=pi->progs[0].argv; 1171 while(foo && *foo) { 1172 bar += sprintf(bar, "%s ", *foo++); 1173 } 1174 } 1175 1176 /* we don't wait for background thejobs to return -- append it 1489 thejob->cmdtext = xstrdup(get_cmdtext(pi)); 1490 1491 /* We don't wait for background thejobs to return -- append it 1177 1492 to the list of backgrounded thejobs and leave it alone */ 1178 printf("[%d] %d \n", thejob->jobid, thejob->progs[0].pid);1493 printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext); 1179 1494 last_bg_pid = thejob->progs[0].pid; 1180 1495 last_jobid = thejob->jobid; 1181 1496 } 1182 1497 1183 /* remove a backgrounded job */1184 1498 static void remove_bg_job(struct pipe *pi) 1185 1499 { … … 1198 1512 else 1199 1513 last_jobid = 0; 1200 1514 } 1515 1516 /* remove a backgrounded job */ 1517 static void delete_finished_bg_job(struct pipe *pi) 1518 { 1519 remove_bg_job(pi); 1201 1520 pi->stopped_progs = 0; 1202 1521 free_pipe(pi, 0); 1203 1522 free(pi); 1204 1523 } 1524 #endif /* JOB */ 1205 1525 1206 1526 /* Checks to see if any processes have exited -- if they … … 1210 1530 int attributes; 1211 1531 int status; 1532 #if ENABLE_HUSH_JOB 1212 1533 int prognum = 0; 1213 1534 struct pipe *pi; 1535 #endif 1214 1536 pid_t childpid; 1537 int rcode = 0; 1215 1538 1216 1539 attributes = WUNTRACED; 1217 if (fg_pipe ==NULL) {1540 if (fg_pipe == NULL) { 1218 1541 attributes |= WNOHANG; 1219 1542 } 1220 1543 1544 /* Do we do this right? 1545 * bash-3.00# sleep 20 | false 1546 * <ctrl-Z pressed> 1547 * [3]+ Stopped sleep 20 | false 1548 * bash-3.00# echo $? 1549 * 1 <========== bg pipe is not fully done, but exitcode is already known! 1550 */ 1551 1552 //FIXME: non-interactive bash does not continue even if all processes in fg pipe 1553 //are stopped. Testcase: "cat | cat" in a script (not on command line) 1554 // + killall -STOP cat 1555 1556 wait_more: 1221 1557 while ((childpid = waitpid(-1, &status, attributes)) > 0) { 1558 const int dead = WIFEXITED(status) || WIFSIGNALED(status); 1559 1560 #ifdef DEBUG_SHELL_JOBS 1561 if (WIFSTOPPED(status)) 1562 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n", 1563 childpid, WSTOPSIG(status), WEXITSTATUS(status)); 1564 if (WIFSIGNALED(status)) 1565 debug_printf_jobs("pid %d killed by sig %d (exitcode %d)\n", 1566 childpid, WTERMSIG(status), WEXITSTATUS(status)); 1567 if (WIFEXITED(status)) 1568 debug_printf_jobs("pid %d exited, exitcode %d\n", 1569 childpid, WEXITSTATUS(status)); 1570 #endif 1571 /* Were we asked to wait for fg pipe? */ 1222 1572 if (fg_pipe) { 1223 int i, rcode = 0; 1224 for (i=0; i < fg_pipe->num_progs; i++) { 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); 1225 1576 if (fg_pipe->progs[i].pid == childpid) { 1226 if (i==fg_pipe->num_progs-1) 1227 rcode=WEXITSTATUS(status); 1228 (fg_pipe->num_progs)--; 1229 return(rcode); 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++; 1587 } 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 */ 1592 #if ENABLE_HUSH_JOB 1593 if (fg_pipe->running_progs) 1594 insert_bg_job(fg_pipe); 1595 #endif 1596 return rcode; 1597 } 1598 /* There are still running processes in the fg pipe */ 1599 goto wait_more; 1230 1600 } 1231 1601 } 1232 } 1233 1602 /* fall through to searching process in bg pipes */ 1603 } 1604 1605 #if ENABLE_HUSH_JOB 1606 /* We asked to wait for bg or orphaned children */ 1607 /* No need to remember exitcode in this case */ 1234 1608 for (pi = job_list; pi; pi = pi->next) { 1235 1609 prognum = 0; 1236 while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { 1610 while (prognum < pi->num_progs) { 1611 if (pi->progs[prognum].pid == childpid) 1612 goto found_pi_and_prognum; 1237 1613 prognum++; 1238 1614 } 1239 if (prognum < pi->num_progs)1240 break; 1241 } 1242 1243 if(pi==NULL) {1244 debug_printf("checkjobs: pid %d was not in our list!\n", childpid);1245 continue; 1246 } 1247 1248 if ( WIFEXITED(status) || WIFSIGNALED(status)) {1615 } 1616 #endif 1617 1618 /* Happens when shell is used as init process (init=/bin/sh) */ 1619 debug_printf("checkjobs: pid %d was not in our list!\n", childpid); 1620 goto wait_more; 1621 1622 #if ENABLE_HUSH_JOB 1623 found_pi_and_prognum: 1624 if (dead) { 1249 1625 /* child exited */ 1626 pi->progs[prognum].pid = 0; 1250 1627 pi->running_progs--; 1251 pi->progs[prognum].pid = 0;1252 1253 1628 if (!pi->running_progs) { 1254 printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); 1255 remove_bg_job(pi); 1629 printf(JOB_STATUS_FORMAT, pi->jobid, 1630 "Done", pi->cmdtext); 1631 delete_finished_bg_job(pi); 1256 1632 } 1257 1633 } else { … … 1259 1635 pi->stopped_progs++; 1260 1636 pi->progs[prognum].is_stopped = 1; 1261 1262 #if 0 1263 /* Printing this stuff is a pain, since it tends to 1264 * overwrite the prompt an inconveinient moments. So 1265 * don't do that. */ 1266 if (pi->stopped_progs == pi->num_progs) { 1267 printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); 1268 } 1269 #endif 1270 } 1271 } 1272 1273 if (childpid == -1 && errno != ECHILD) 1637 } 1638 #endif 1639 } 1640 1641 /* wait found no children or failed */ 1642 1643 if (childpid && errno != ECHILD) 1274 1644 bb_perror_msg("waitpid"); 1275 1276 /* move the shell to the foreground */ 1277 //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) 1278 // bb_perror_msg("tcsetpgrp-2"); 1279 return -1; 1280 } 1281 1282 /* Figure out our controlling tty, checking in order stderr, 1283 * stdin, and stdout. If check_pgrp is set, also check that 1284 * we belong to the foreground process group associated with 1285 * that tty. The value of shell_terminal is needed in order to call 1286 * tcsetpgrp(shell_terminal, ...); */ 1287 #if 0 1288 static void controlling_tty(int check_pgrp) 1289 { 1290 pid_t curpgrp; 1291 1292 if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0 1293 && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0 1294 && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0) 1295 goto shell_terminal_error; 1296 1297 if (check_pgrp && curpgrp != getpgid(0)) 1298 goto shell_terminal_error; 1299 1300 return; 1301 1302 shell_terminal_error: 1303 shell_terminal = -1; 1304 return; 1645 return rcode; 1646 } 1647 1648 #if ENABLE_HUSH_JOB 1649 static int checkjobs_and_fg_shell(struct pipe* fg_pipe) 1650 { 1651 pid_t p; 1652 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"); 1658 return rcode; 1305 1659 } 1306 1660 #endif … … 1321 1675 * now has its stdout directed to the input of the appropriate pipe, 1322 1676 * so this routine is noticeably simpler. 1677 * 1678 * Returns -1 only if started some children. IOW: we have to 1679 * mask out retvals of builtins etc with 0xff! 1323 1680 */ 1324 1681 static int run_pipe_real(struct pipe *pi) … … 1330 1687 const struct built_in_command *x; 1331 1688 char *p; 1689 /* it is not always needed, but we aim to smaller code */ 1690 int squirrel[] = { -1, -1, -1 }; 1691 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); 1332 1695 1333 1696 nextin = 0; 1697 #if ENABLE_HUSH_JOB 1334 1698 pi->pgrp = -1; 1699 #endif 1700 pi->running_progs = 1; 1701 pi->stopped_progs = 0; 1335 1702 1336 1703 /* Check if this is a simple builtin (not part of a pipe). … … 1338 1705 * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. 1339 1706 */ 1340 if (pi->num_progs == 1) child = & (pi->progs[0]); 1341 if (pi->num_progs == 1 && child->group && child->subshell == 0) { 1342 int squirrel[] = {-1, -1, -1}; 1343 int rcode; 1707 child = &(pi->progs[0]); 1708 if (single_fg && child->group && child->subshell == 0) { 1344 1709 debug_printf("non-subshell grouping\n"); 1345 1710 setup_redirects(child, squirrel); 1346 /* XXX could we merge code with following builtin case, 1347 * by creating a pseudo builtin that calls run_list_real? */ 1711 debug_printf_exec(": run_list_real\n"); 1348 1712 rcode = run_list_real(child->group); 1349 1713 restore_redirects(squirrel); 1350 return rcode; 1351 } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { 1352 for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } 1353 if (i!=0 && child->argv[i]==NULL) { 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) { 1354 1725 /* assignments, but no command: set the local environment */ 1355 for (i=0; child->argv[i]!=NULL; i++) { 1356 1357 /* Ok, this case is tricky. We have to decide if this is a 1358 * local variable, or an already exported variable. If it is 1359 * already exported, we have to export the new value. If it is 1360 * not exported, we need only set this as a local variable. 1361 * This junk is all to decide whether or not to export this 1362 * variable. */ 1363 int export_me=0; 1364 char *name, *value; 1365 name = bb_xstrdup(child->argv[i]); 1366 debug_printf("Local environment set: %s\n", name); 1367 value = strchr(name, '='); 1368 if (value) 1369 *value=0; 1370 if ( get_local_var(name)) { 1371 export_me=1; 1372 } 1373 free(name); 1374 p = insert_var_value(child->argv[i]); 1375 set_local_var(p, export_me); 1376 if (p != child->argv[i]) free(p); 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); 1377 1730 } 1378 1731 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1379 1732 } 1380 for (i = 0; is_assignment(child->argv[i]); i++) { 1381 p = insert_var_value(child->argv[i]); 1382 putenv(strdup(p)); 1383 if (p != child->argv[i]) { 1384 child->sp--; 1385 free(p); 1386 } 1387 } 1388 if (child->sp) { 1389 char * str = NULL; 1390 1391 str = make_string((child->argv + i)); 1392 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); 1393 free(str); 1394 return last_return_code; 1733 for (i = 0; is_assignment(argv[i]); i++) { 1734 p = expand_string_to_string(argv[i]); 1735 //sp: child->sp--; 1736 putenv(p); 1395 1737 } 1396 1738 for (x = bltins; x->cmd; x++) { 1397 if (strcmp(child->argv[i], x->cmd) == 0 ) { 1398 int squirrel[] = {-1, -1, -1}; 1399 int rcode; 1400 if (x->function == builtin_exec && child->argv[i+1]==NULL) { 1739 if (strcmp(argv[i], x->cmd) == 0) { 1740 if (x->function == builtin_exec && argv[i+1] == NULL) { 1401 1741 debug_printf("magic exec\n"); 1402 setup_redirects(child, NULL);1742 setup_redirects(child, NULL); 1403 1743 return EXIT_SUCCESS; 1404 1744 } 1405 debug_printf("builtin inline %s\n", child->argv[0]);1745 debug_printf("builtin inline %s\n", argv[0]); 1406 1746 /* XXX setup_redirects acts on file descriptors, not FILEs. 1407 1747 * This is perfect for work that comes after exec(). … … 1409 1749 * things seem to work with glibc. */ 1410 1750 setup_redirects(child, squirrel); 1411 child->argv+=i; /* XXX horrible hack */ 1412 rcode = x->function(child); 1413 child->argv-=i; /* XXX restore hack so free() can work right */ 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); 1414 1756 restore_redirects(squirrel); 1757 debug_printf_exec("run_pipe_real return %d\n", rcode); 1415 1758 return rcode; 1416 1759 } 1417 1760 } 1418 } 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); 1419 1787 1420 1788 for (i = 0; i < pi->num_progs; i++) { 1421 child = & (pi->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"); 1422 1794 1423 1795 /* pipes are inserted between pairs of commands */ 1424 1796 if ((i + 1) < pi->num_progs) { 1425 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");1797 pipe(pipefds); 1426 1798 nextout = pipefds[1]; 1427 1799 } else { 1428 nextout =1;1800 nextout = 1; 1429 1801 pipefds[0] = -1; 1430 1802 } 1431 1803 1432 1804 /* XXX test for failed fork()? */ 1433 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)1434 if (!(child->pid = fork()))1805 #if BB_MMU 1806 child->pid = fork(); 1435 1807 #else 1436 if (!(child->pid = vfork())) 1437 #endif 1438 { 1439 /* Set the handling for job control signals back to the default. */ 1440 signal(SIGINT, SIG_DFL); 1441 signal(SIGQUIT, SIG_DFL); 1442 signal(SIGTERM, SIG_DFL); 1443 signal(SIGTSTP, SIG_DFL); 1444 signal(SIGTTIN, SIG_DFL); 1445 signal(SIGTTOU, SIG_DFL); 1446 signal(SIGCHLD, SIG_DFL); 1447 1808 child->pid = vfork(); 1809 #endif 1810 if (!child->pid) { /* child */ 1811 /* 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) { 1820 /* We do it in *every* child, not just first, 1821 * to avoid races */ 1822 tcsetpgrp(interactive_fd, pi->pgrp); 1823 } 1824 } 1825 #endif 1826 /* in non-interactive case fatal sigs are already SIG_DFL */ 1448 1827 close_all(); 1449 1450 1828 if (nextin != 0) { 1451 1829 dup2(nextin, 0); … … 1456 1834 close(nextout); 1457 1835 } 1458 if (pipefds[0] !=-1) {1836 if (pipefds[0] != -1) { 1459 1837 close(pipefds[0]); /* opposite end of our output pipe */ 1460 1838 } 1461 1462 1839 /* Like bash, explicit redirects override pipes, 1463 1840 * and the pipe fd is available for dup'ing. */ 1464 setup_redirects(child,NULL); 1465 1466 if (interactive && pi->followup!=PIPE_BG) { 1467 /* If we (the child) win the race, put ourselves in the process 1468 * group whose leader is the first process in this pipe. */ 1469 if (pi->pgrp < 0) { 1470 pi->pgrp = getpid(); 1471 } 1472 if (setpgid(0, pi->pgrp) == 0) { 1473 tcsetpgrp(2, pi->pgrp); 1474 } 1475 } 1476 1841 setup_redirects(child, NULL); 1842 1843 /* Restore default handlers just prior to exec */ 1844 set_jobctrl_sighandler(SIG_DFL); 1845 set_misc_sighandler(SIG_DFL); 1846 signal(SIGCHLD, SIG_DFL); 1477 1847 pseudo_exec(child); 1478 1848 } 1479 1849 1480 1481 /* put our child in the process group whose leader is the 1482 first process in this pipe */ 1483 if (pi->pgrp < 0) { 1850 pi->running_progs++; 1851 1852 #if ENABLE_HUSH_JOB 1853 /* Second and next children need to know pid of first one */ 1854 if (pi->pgrp < 0) 1484 1855 pi->pgrp = child->pid; 1485 } 1486 /* Don't check for errors. The child may be dead already, 1487 * in which case setpgid returns error code EACCES. */ 1488 setpgid(child->pid, pi->pgrp); 1489 1856 #endif 1490 1857 if (nextin != 0) 1491 1858 close(nextin); … … 1497 1864 nextin = pipefds[0]; 1498 1865 } 1866 debug_printf_exec("run_pipe_real return -1\n"); 1499 1867 return -1; 1500 1868 } 1501 1869 1870 #ifndef debug_print_tree 1871 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_IF 1882 [RES_IF ] = "IF" , 1883 [RES_THEN ] = "THEN" , 1884 [RES_ELIF ] = "ELIF" , 1885 [RES_ELSE ] = "ELSE" , 1886 [RES_FI ] = "FI" , 1887 #endif 1888 #if ENABLE_HUSH_LOOPS 1889 [RES_FOR ] = "FOR" , 1890 [RES_WHILE] = "WHILE", 1891 [RES_UNTIL] = "UNTIL", 1892 [RES_DO ] = "DO" , 1893 [RES_DONE ] = "DONE" , 1894 [RES_IN ] = "IN" , 1895 #endif 1896 [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 #endif 1932 1933 /* NB: called by pseudo_exec, and therefore must not modify any 1934 * global data until exec/_exit (we can be a child after vfork!) */ 1502 1935 static int run_list_real(struct pipe *pi) 1503 1936 { 1504 char *save_name = NULL;1505 char **list = NULL;1506 char **save_list = NULL;1507 1937 struct pipe *rpipe; 1938 #if ENABLE_HUSH_LOOPS 1939 char *for_varname = NULL; 1940 char **for_lcur = NULL; 1941 char **for_list = NULL; 1508 1942 int flag_rep = 0; 1943 #endif 1509 1944 int save_num_progs; 1510 int rcode=0, flag_skip=1; 1945 int flag_skip = 1; 1946 int rcode = 0; /* probably for gcc only */ 1511 1947 int flag_restore = 0; 1512 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ 1513 reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; 1948 #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 1958 #if ENABLE_HUSH_LOOPS 1514 1959 /* check syntax for "for" */ 1515 1960 for (rpipe = pi; rpipe; rpipe = rpipe->next) { 1516 if ((rpipe->r_mode == RES_IN || 1517 rpipe->r_mode == RES_FOR) && 1518 (rpipe->next == NULL)) { 1519 syntax(); 1520 return 1; 1521 } 1522 if ((rpipe->r_mode == RES_IN && 1523 (rpipe->next->r_mode == RES_IN && 1524 rpipe->next->progs->argv != NULL))|| 1525 (rpipe->r_mode == RES_FOR && 1526 rpipe->next->r_mode != RES_IN)) { 1527 syntax(); 1528 return 1; 1529 } 1530 } 1531 for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { 1532 if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || 1533 pi->r_mode == RES_FOR) { 1534 flag_restore = 0; 1535 if (!rpipe) { 1536 flag_rep = 0; 1537 rpipe = pi; 1538 } 1539 } 1540 rmode = pi->r_mode; 1541 debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); 1542 if (rmode == skip_more_in_this_rmode && flag_skip) { 1543 if (pi->followup == PIPE_SEQ) flag_skip=0; 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 1981 #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); 2005 } 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_STANDALONE 2016 nofork_save.saved = 0; /* in case we will run a nofork later */ 2017 #endif 2018 signal_SA_RESTART(SIGTSTP, handler_ctrl_z); 2019 signal(SIGINT, handler_ctrl_c); 2020 } 2021 #endif 2022 2023 for (; pi; pi = flag_restore ? rpipe : pi->next) { 2024 rword = pi->res_word; 2025 #if ENABLE_HUSH_LOOPS 2026 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 #endif 2034 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; 1544 2039 continue; 1545 2040 } 1546 2041 flag_skip = 1; 1547 skip_more_in_this_rmode = RES_XXXX; 1548 if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; 1549 if (rmode == RES_THEN && if_code) continue; 1550 if (rmode == RES_ELSE && !if_code) continue; 1551 if (rmode == RES_ELIF && !if_code) break; 1552 if (rmode == RES_FOR && pi->num_progs) { 1553 if (!list) { 2042 skip_more_for_this_rword = RES_XXXX; 2043 #if ENABLE_HUSH_IF 2044 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 #endif 2053 #if ENABLE_HUSH_LOOPS 2054 if (rword == RES_FOR && pi->num_progs) { 2055 if (!for_lcur) { 1554 2056 /* if no variable values after "in" we skip "for" */ 1555 if (!pi->next->progs->argv) continue; 2057 if (!pi->next->progs->argv) 2058 continue; 1556 2059 /* create list of variable values */ 1557 list = make_list_in(pi->next->progs->argv, 1558 pi->progs->argv[0]); 1559 save_list = list; 1560 save_name = pi->progs->argv[0]; 2060 for_list = expand_strvec_to_strvec(pi->next->progs->argv); 2061 for_lcur = for_list; 2062 for_varname = pi->progs->argv[0]; 1561 2063 pi->progs->argv[0] = NULL; 1562 2064 flag_rep = 1; 1563 2065 } 1564 if (!(*list)) {1565 free(pi->progs->argv[0]);1566 free( save_list);1567 list= NULL;2066 free(pi->progs->argv[0]); 2067 if (!*for_lcur) { 2068 free(for_list); 2069 for_lcur = NULL; 1568 2070 flag_rep = 0; 1569 pi->progs->argv[0] = save_name; 1570 pi->progs->glob_result.gl_pathv[0] = 1571 pi->progs->argv[0]; 2071 pi->progs->argv[0] = for_varname; 2072 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; 1572 2073 continue; 1573 } else { 1574 /* insert new value from list for variable */ 1575 if (pi->progs->argv[0]) 1576 free(pi->progs->argv[0]); 1577 pi->progs->argv[0] = *list++; 1578 pi->progs->glob_result.gl_pathv[0] = 1579 pi->progs->argv[0]; 1580 } 1581 } 1582 if (rmode == RES_IN) continue; 1583 if (rmode == RES_DO) { 1584 if (!flag_rep) continue; 1585 } 1586 if ((rmode == RES_DONE)) { 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) { 1587 2087 if (flag_rep) { 1588 2088 flag_restore = 1; … … 1591 2091 } 1592 2092 } 1593 if (pi->num_progs == 0) continue; 2093 #endif 2094 if (pi->num_progs == 0) 2095 continue; 1594 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); 1595 2098 rcode = run_pipe_real(pi); 1596 debug_printf("run_pipe_real returned %d\n",rcode); 1597 if (rcode!=-1) { 2099 if (rcode != -1) { 1598 2100 /* We only ran a builtin: rcode was set by the return value 1599 2101 * of run_pipe_real(), and we don't need to wait for anything. */ 1600 } else if (pi->followup==PIPE_BG) { 1601 /* XXX check bash's behavior with nontrivial pipes */ 1602 /* XXX compute jobid */ 1603 /* XXX what does bash do with attempts to background builtins? */ 1604 insert_bg_job(pi); 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 #if ENABLE_HUSH_JOB 2108 if (run_list_level == 1) 2109 insert_bg_job(pi); 2110 #endif 1605 2111 rcode = EXIT_SUCCESS; 1606 2112 } else { 1607 if (interactive) { 1608 /* move the new process group into the foreground */ 1609 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) 1610 bb_perror_msg("tcsetpgrp-3"); 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 */ 1611 2122 rcode = checkjobs(pi); 1612 /* move the shell to the foreground */ 1613 if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) 1614 bb_perror_msg("tcsetpgrp-4"); 1615 } else { 1616 rcode = checkjobs(pi); 1617 } 1618 debug_printf("checkjobs returned %d\n",rcode); 1619 } 1620 last_return_code=rcode; 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; 1621 2128 pi->num_progs = save_num_progs; /* restore number of programs */ 1622 if ( rmode == RES_IF || rmode == RES_ELIF ) 1623 next_if_code=rcode; /* can be overwritten a number of times */ 1624 if (rmode == RES_WHILE) 2129 #if ENABLE_HUSH_IF 2130 if (rword == RES_IF || rword == RES_ELIF) 2131 next_if_code = rcode; /* can be overwritten a number of times */ 2132 #endif 2133 #if ENABLE_HUSH_LOOPS 2134 if (rword == RES_WHILE) 1625 2135 flag_rep = !last_return_code; 1626 if (r mode== RES_UNTIL)2136 if (rword == RES_UNTIL) 1627 2137 flag_rep = last_return_code; 1628 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || 1629 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) 1630 skip_more_in_this_rmode=rmode; 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 } 1631 2144 checkjobs(NULL); 1632 2145 } 2146 2147 #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); 1633 2160 return rcode; 1634 }1635 1636 /* broken, of course, but OK for testing */1637 static char *indenter(int i)1638 {1639 static char blanks[]=" ";1640 return &blanks[sizeof(blanks)-i-1];1641 2161 } 1642 2162 … … 1647 2167 struct child_prog *child; 1648 2168 struct redir_struct *r, *rnext; 1649 int a, i, ret_code=0; 1650 char *ind = indenter(indent); 2169 int a, i, ret_code = 0; 1651 2170 1652 2171 if (pi->stopped_progs > 0) 1653 2172 return ret_code; 1654 final_printf("%s run pipe: (pid %d)\n",ind,getpid());1655 for (i =0; i<pi->num_progs; i++) {2173 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); 2174 for (i = 0; i < pi->num_progs; i++) { 1656 2175 child = &pi->progs[i]; 1657 final_printf("%s command %d:\n",ind,i);2176 debug_printf_clean("%s command %d:\n", indenter(indent), i); 1658 2177 if (child->argv) { 1659 for (a =0,p=child->argv; *p; a++,p++) {1660 final_printf("%s argv[%d] = %s\n",ind,a,*p);2178 for (a = 0, p = child->argv; *p; a++, p++) { 2179 debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p); 1661 2180 } 1662 2181 globfree(&child->glob_result); 1663 child->argv =NULL;2182 child->argv = NULL; 1664 2183 } else if (child->group) { 1665 final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);1666 ret_code = free_pipe_list(child->group, indent+3);1667 final_printf("%s end group\n",ind);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)); 1668 2187 } else { 1669 final_printf("%s (nil)\n",ind);1670 } 1671 for (r =child->redirects; r; r=rnext) {1672 final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);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); 1673 2192 if (r->dup == -1) { 1674 2193 /* guard against the case >$FOO, where foo is unset or blank */ 1675 2194 if (r->word.gl_pathv) { 1676 final_printf(" %s\n", *r->word.gl_pathv);2195 debug_printf_clean(" %s\n", *r->word.gl_pathv); 1677 2196 globfree(&r->word); 1678 2197 } 1679 2198 } else { 1680 final_printf("&%d\n", r->dup);1681 } 1682 rnext =r->next;2199 debug_printf_clean("&%d\n", r->dup); 2200 } 2201 rnext = r->next; 1683 2202 free(r); 1684 2203 } 1685 child->redirects =NULL;2204 child->redirects = NULL; 1686 2205 } 1687 2206 free(pi->progs); /* children are an array, they get freed all at once */ 1688 pi->progs=NULL; 2207 pi->progs = NULL; 2208 #if ENABLE_HUSH_JOB 2209 free(pi->cmdtext); 2210 pi->cmdtext = NULL; 2211 #endif 1689 2212 return ret_code; 1690 2213 } … … 1692 2215 static int free_pipe_list(struct pipe *head, int indent) 1693 2216 { 1694 int rcode =0; /* if list has no members */2217 int rcode = 0; /* if list has no members */ 1695 2218 struct pipe *pi, *next; 1696 char *ind = indenter(indent); 1697 for (pi =head; pi; pi=next) {1698 final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);2219 2220 for (pi = head; pi; pi = next) { 2221 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); 1699 2222 rcode = free_pipe(pi, indent); 1700 final_printf("%s pipe followup code %d\n", ind, pi->followup);1701 next =pi->next;1702 pi->next=NULL;2223 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); 2224 next = pi->next; 2225 /*pi->next = NULL;*/ 1703 2226 free(pi); 1704 2227 } … … 1709 2232 static int run_list(struct pipe *pi) 1710 2233 { 1711 int rcode=0; 1712 if (fake_mode==0) { 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); 1713 2238 rcode = run_list_real(pi); 1714 2239 } 1715 /* free_pipe_list has the side effect of clearing memory 2240 /* free_pipe_list has the side effect of clearing memory. 1716 2241 * In the long run that function can be merged with run_list_real, 1717 2242 * but doing that now would hobble the debugging effort. */ 1718 free_pipe_list(pi,0); 2243 free_pipe_list(pi, 0); 2244 debug_printf_exec("run_list return %d\n", rcode); 1719 2245 return rcode; 1720 2246 } … … 1729 2255 static int globhack(const char *src, int flags, glob_t *pglob) 1730 2256 { 1731 int cnt =0, pathc;2257 int cnt = 0, pathc; 1732 2258 const char *s; 1733 2259 char *dest; 1734 for (cnt =1, s=src; s && *s; s++) {2260 for (cnt = 1, s = src; s && *s; s++) { 1735 2261 if (*s == '\\') s++; 1736 2262 cnt++; 1737 2263 } 1738 dest = malloc(cnt); 1739 if (!dest) return GLOB_NOSPACE; 2264 dest = xmalloc(cnt); 1740 2265 if (!(flags & GLOB_APPEND)) { 1741 pglob->gl_pathv =NULL;1742 pglob->gl_pathc =0;1743 pglob->gl_offs =0;1744 pglob->gl_offs =0;2266 pglob->gl_pathv = NULL; 2267 pglob->gl_pathc = 0; 2268 pglob->gl_offs = 0; 2269 pglob->gl_offs = 0; 1745 2270 } 1746 2271 pathc = ++pglob->gl_pathc; 1747 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); 1748 if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; 1749 pglob->gl_pathv[pathc-1]=dest; 1750 pglob->gl_pathv[pathc]=NULL; 1751 for (s=src; s && *s; s++, dest++) { 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++) { 1752 2276 if (*s == '\\') s++; 1753 2277 *dest = *s; 1754 2278 } 1755 *dest ='\0';2279 *dest = '\0'; 1756 2280 return 0; 1757 2281 } … … 1762 2286 for (; *s; s++) { 1763 2287 if (*s == '\\') s++; 1764 if (strchr("*[?", *s)) return 1;2288 if (strchr("*[?", *s)) return 1; 1765 2289 } 1766 2290 return 0; 1767 2291 } 1768 1769 #if 01770 static void globprint(glob_t *pglob)1771 {1772 int i;1773 debug_printf("glob_t at %p:\n", pglob);1774 debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n",1775 pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);1776 for (i=0; i<pglob->gl_pathc; i++)1777 debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,1778 pglob->gl_pathv[i], pglob->gl_pathv[i]);1779 }1780 #endif1781 2292 1782 2293 static int xglob(o_string *dest, int flags, glob_t *pglob) … … 1790 2301 /* bash man page calls this an "explicit" null */ 1791 2302 gr = globhack(dest->data, flags, pglob); 1792 debug_printf("globhack returned %d\n", gr);2303 debug_printf("globhack returned %d\n", gr); 1793 2304 } else { 1794 2305 return 0; … … 1796 2307 } else if (glob_needed(dest->data)) { 1797 2308 gr = glob(dest->data, flags, NULL, pglob); 1798 debug_printf("glob returned %d\n", gr);2309 debug_printf("glob returned %d\n", gr); 1799 2310 if (gr == GLOB_NOMATCH) { 1800 2311 /* quote removal, or more accurately, backslash removal */ 1801 2312 gr = globhack(dest->data, flags, pglob); 1802 debug_printf("globhack returned %d\n", gr);2313 debug_printf("globhack returned %d\n", gr); 1803 2314 } 1804 2315 } else { 1805 2316 gr = globhack(dest->data, flags, pglob); 1806 debug_printf("globhack returned %d\n", gr);2317 debug_printf("globhack returned %d\n", gr); 1807 2318 } 1808 2319 if (gr == GLOB_NOSPACE) 1809 2320 bb_error_msg_and_die("out of memory during glob"); 1810 2321 if (gr != 0) { /* GLOB_ABORTED ? */ 1811 bb_error_msg("glob(3) error %d", gr);2322 bb_error_msg("glob(3) error %d", gr); 1812 2323 } 1813 2324 /* globprint(glob_target); */ … … 1815 2326 } 1816 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 */ 2376 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 } 2385 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 1817 2662 /* This is used to get/check local shell variables */ 1818 static char *get_local_var(const char *s) 1819 { 1820 struct variables *cur; 1821 1822 if (!s) 2663 static struct variable *get_local_var(const char *name) 2664 { 2665 struct variable *cur; 2666 int len; 2667 2668 if (!name) 1823 2669 return NULL; 1824 for (cur = top_vars; cur; cur=cur->next) 1825 if(strcmp(cur->name, s)==0) 1826 return cur->value; 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 } 1827 2675 return NULL; 1828 2676 } 1829 2677 1830 /* This is used to set local shell variables 1831 flg_export==0 if only local (not exporting) variable 1832 flg_export==1 if "new" exporting environ 1833 flg_export>1 if current startup environ (not call putenv()) */ 1834 static int set_local_var(const char *s, int flg_export) 1835 { 1836 char *name, *value; 1837 int result=0; 1838 struct variables *cur; 1839 1840 name=strdup(s); 1841 1842 /* Assume when we enter this function that we are already in 1843 * NAME=VALUE format. So the first order of business is to 1844 * split 's' on the '=' into 'name' and 'value' */ 1845 value = strchr(name, '='); 1846 if (value==0 && ++value==0) { 1847 free(name); 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); 1848 2689 return -1; 1849 2690 } 1850 *value++ = 0; 1851 1852 for(cur = top_vars; cur; cur = cur->next) { 1853 if(strcmp(cur->name, name)==0) 1854 break; 1855 } 1856 1857 if(cur) { 1858 if(strcmp(cur->value, value)==0) { 1859 if(flg_export>0 && cur->flg_export==0) 1860 cur->flg_export=flg_export; 1861 else 1862 result++; 1863 } else { 1864 if(cur->flg_read_only) { 1865 bb_error_msg("%s: readonly variable", name); 1866 result = -1; 1867 } else { 1868 if(flg_export>0 || cur->flg_export>1) 1869 cur->flg_export=1; 1870 free(cur->value); 1871 1872 cur->value = strdup(value); 1873 } 1874 } 1875 } else { 1876 cur = malloc(sizeof(struct variables)); 1877 if(!cur) { 1878 result = -1; 1879 } else { 1880 cur->name = strdup(name); 1881 if(cur->name == 0) { 1882 free(cur); 1883 result = -1; 1884 } else { 1885 struct variables *bottom = top_vars; 1886 cur->value = strdup(value); 1887 cur->next = 0; 1888 cur->flg_export = flg_export; 1889 cur->flg_read_only = 0; 1890 while(bottom->next) bottom=bottom->next; 1891 bottom->next = cur; 1892 } 1893 } 1894 } 1895 1896 if(result==0 && cur->flg_export==1) { 1897 *(value-1) = '='; 1898 result = putenv(name); 1899 } else { 1900 free(name); 1901 if(result>0) /* equivalent to previous set */ 1902 result = 0; 1903 } 1904 return result; 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; 1905 2743 } 1906 2744 1907 2745 static void unset_local_var(const char *name) 1908 2746 { 1909 struct variables *cur; 1910 1911 if (name) { 1912 for (cur = top_vars; cur; cur=cur->next) { 1913 if(strcmp(cur->name, name)==0) 1914 break; 1915 } 1916 if(cur!=0) { 1917 struct variables *next = top_vars; 1918 if(cur->flg_read_only) { 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) { 1919 2758 bb_error_msg("%s: readonly variable", name); 1920 2759 return; 1921 } else { 1922 if(cur->flg_export) 1923 unsetenv(cur->name); 1924 free(cur->name); 1925 free(cur->value); 1926 while (next->next != cur) 1927 next = next->next; 1928 next->next = cur->next; 1929 } 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); 1930 2767 free(cur); 1931 } 2768 return; 2769 } 2770 prev = cur; 2771 cur = cur->next; 1932 2772 } 1933 2773 } … … 1935 2775 static int is_assignment(const char *s) 1936 2776 { 1937 if (s==NULL || !isalpha(*s)) return 0; 1938 ++s; 1939 while(isalnum(*s) || *s=='_') ++s; 1940 return *s=='='; 2777 if (!s || !isalpha(*s)) 2778 return 0; 2779 s++; 2780 while (isalnum(*s) || *s == '_') 2781 s++; 2782 return *s == '='; 1941 2783 } 1942 2784 … … 1948 2790 struct in_str *input) 1949 2791 { 1950 struct child_prog *child =ctx->child;2792 struct child_prog *child = ctx->child; 1951 2793 struct redir_struct *redir = child->redirects; 1952 struct redir_struct *last_redir =NULL;2794 struct redir_struct *last_redir = NULL; 1953 2795 1954 2796 /* Create a new redir_struct and drop it onto the end of the linked list */ 1955 while (redir) {1956 last_redir =redir;1957 redir =redir->next;2797 while (redir) { 2798 last_redir = redir; 2799 redir = redir->next; 1958 2800 } 1959 2801 redir = xmalloc(sizeof(struct redir_struct)); 1960 redir->next =NULL;1961 redir->word.gl_pathv =NULL;2802 redir->next = NULL; 2803 redir->word.gl_pathv = NULL; 1962 2804 if (last_redir) { 1963 last_redir->next =redir;2805 last_redir->next = redir; 1964 2806 } else { 1965 child->redirects =redir;1966 } 1967 1968 redir->type =style;1969 redir->fd = (fd==-1) ? redir_table[style].default_fd : fd;2807 child->redirects = redir; 2808 } 2809 2810 redir->type = style; 2811 redir->fd = (fd == -1) ? redir_table[style].default_fd : fd; 1970 2812 1971 2813 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); … … 1983 2825 * since we need to return and let src be expanded first. 1984 2826 * Set ctx->pending_redirect, so we know what to do at the 1985 * end of the next parsed word. 1986 */ 2827 * end of the next parsed word. */ 1987 2828 ctx->pending_redirect = redir; 1988 2829 } … … 1990 2831 } 1991 2832 1992 static struct pipe *new_pipe(void) { 2833 static struct pipe *new_pipe(void) 2834 { 1993 2835 struct pipe *pi; 1994 pi = xmalloc(sizeof(struct pipe)); 1995 pi->num_progs = 0; 1996 pi->progs = NULL; 1997 pi->next = NULL; 1998 pi->followup = 0; /* invalid */ 1999 pi->r_mode = RES_NONE; 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; 2000 2843 return pi; 2001 2844 } … … 2003 2846 static void initialize_context(struct p_context *ctx) 2004 2847 { 2005 ctx->pipe=NULL; 2006 ctx->pending_redirect=NULL; 2007 ctx->child=NULL; 2008 ctx->list_head=new_pipe(); 2009 ctx->pipe=ctx->list_head; 2010 ctx->w=RES_NONE; 2011 ctx->stack=NULL; 2012 ctx->old_flag=0; 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; 2013 2855 done_command(ctx); /* creates the memory for working child */ 2014 2856 } … … 2019 2861 * case, function, and select are obnoxious, save those for later. 2020 2862 */ 2863 #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS 2021 2864 static int reserved_word(o_string *dest, struct p_context *ctx) 2022 2865 { 2023 2866 struct reserved_combo { 2024 char *literal;2025 intcode;2026 longflag;2867 char literal[7]; 2868 unsigned char code; 2869 int flag; 2027 2870 }; 2028 2871 /* Mostly a list of accepted follow-up reserved words. … … 2031 2874 * FLAG_START means the word must start a new compound list. 2032 2875 */ 2033 static struct reserved_combo reserved_list[] = { 2876 static const struct reserved_combo reserved_list[] = { 2877 #if ENABLE_HUSH_IF 2034 2878 { "if", RES_IF, FLAG_THEN | FLAG_START }, 2035 2879 { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, … … 2037 2881 { "else", RES_ELSE, FLAG_FI }, 2038 2882 { "fi", RES_FI, FLAG_END }, 2883 #endif 2884 #if ENABLE_HUSH_LOOPS 2039 2885 { "for", RES_FOR, FLAG_IN | FLAG_START }, 2040 2886 { "while", RES_WHILE, FLAG_DO | FLAG_START }, … … 2043 2889 { "do", RES_DO, FLAG_DONE }, 2044 2890 { "done", RES_DONE, FLAG_END } 2891 #endif 2045 2892 }; 2046 struct reserved_combo *r; 2047 for (r=reserved_list; 2048 #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) 2049 r<reserved_list+NRES; r++) { 2050 if (strcmp(dest->data, r->literal) == 0) { 2051 debug_printf("found reserved word %s, code %d\n",r->literal,r->code); 2052 if (r->flag & FLAG_START) { 2053 struct p_context *new = xmalloc(sizeof(struct p_context)); 2054 debug_printf("push stack\n"); 2055 if (ctx->w == RES_IN || ctx->w == RES_FOR) { 2056 syntax(); 2057 free(new); 2058 ctx->w = RES_SNTX; 2059 b_reset(dest); 2060 return 1; 2061 } 2062 *new = *ctx; /* physical copy */ 2063 initialize_context(ctx); 2064 ctx->stack=new; 2065 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) { 2066 syntax(); 2067 ctx->w = RES_SNTX; 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; 2068 2907 b_reset(dest); 2069 2908 return 1; 2070 2909 } 2071 ctx->w=r->code; 2072 ctx->old_flag = r->flag; 2073 if (ctx->old_flag & FLAG_END) { 2074 struct p_context *old; 2075 debug_printf("pop stack\n"); 2076 done_pipe(ctx,PIPE_SEQ); 2077 old = ctx->stack; 2078 old->child->group = ctx->list_head; 2079 old->child->subshell = 0; 2080 *ctx = *old; /* physical copy */ 2081 free(old); 2082 } 2083 b_reset (dest); 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); 2084 2919 return 1; 2085 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; 2086 2935 } 2087 2936 return 0; 2088 2937 } 2089 2090 /* normal return is 0. 2938 #else 2939 #define reserved_word(dest, ctx) ((int)0) 2940 #endif 2941 2942 /* Normal return is 0. 2091 2943 * Syntax or xglob errors return 1. */ 2092 2944 static int done_word(o_string *dest, struct p_context *ctx) 2093 2945 { 2094 struct child_prog *child =ctx->child;2946 struct child_prog *child = ctx->child; 2095 2947 glob_t *glob_target; 2096 2948 int gr, flags = 0; 2097 2949 2098 debug_printf ("done_word: %s%p\n", dest->data, child);2950 debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child); 2099 2951 if (dest->length == 0 && !dest->nonnull) { 2100 debug_printf ("true null, ignored\n");2952 debug_printf_parse("done_word return 0: true null, ignored\n"); 2101 2953 return 0; 2102 2954 } … … 2105 2957 } else { 2106 2958 if (child->group) { 2107 syntax(); 2108 return 1; /* syntax error, groups and arglists don't mix */ 2109 } 2110 if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { 2111 debug_printf("checking %s for reserved-ness\n",dest->data); 2112 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; 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 } 2113 2969 } 2114 2970 glob_target = &child->glob_result; 2115 if (child->argv) flags |= GLOB_APPEND; 2971 if (child->argv) 2972 flags |= GLOB_APPEND; 2116 2973 } 2117 2974 gr = xglob(dest, flags, glob_target); 2118 if (gr != 0) return 1; 2975 if (gr != 0) { 2976 debug_printf_parse("done_word return 1: xglob returned %d\n", gr); 2977 return 1; 2978 } 2119 2979 2120 2980 b_reset(dest); 2121 2981 if (ctx->pending_redirect) { 2122 ctx->pending_redirect =NULL;2982 ctx->pending_redirect = NULL; 2123 2983 if (glob_target->gl_pathc != 1) { 2124 2984 bb_error_msg("ambiguous redirect"); 2985 debug_printf_parse("done_word return 1: ambiguous redirect\n"); 2125 2986 return 1; 2126 2987 } … … 2128 2989 child->argv = glob_target->gl_pathv; 2129 2990 } 2130 if (ctx->w == RES_FOR) { 2131 done_word(dest,ctx); 2132 done_pipe(ctx,PIPE_SEQ); 2133 } 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"); 2134 2998 return 0; 2135 2999 } … … 2140 3004 { 2141 3005 /* The child is really already in the pipe structure, so 2142 * advance the pipe counter and make a new, null child. 2143 * Only real trickiness here is that the uncommitted 2144 * child structure, to which ctx->child points, is not 2145 * counted in pi->num_progs. */ 2146 struct pipe *pi=ctx->pipe; 2147 struct child_prog *prog=ctx->child; 2148 2149 if (prog && prog->group == NULL 2150 && prog->argv == NULL 2151 && prog->redirects == NULL) { 2152 debug_printf("done_command: skipping null command\n"); 2153 return 0; 2154 } else if (prog) { 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 } 2155 3018 pi->num_progs++; 2156 debug_printf ("done_command: num_progs incremented to %d\n",pi->num_progs);3019 debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs); 2157 3020 } else { 2158 debug_printf("done_command: initializing\n"); 2159 } 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. */ 2160 3026 pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); 2161 2162 prog = pi->progs + pi->num_progs; 2163 prog->redirects = NULL; 2164 prog->argv = NULL; 2165 prog->is_stopped = 0; 2166 prog->group = NULL; 2167 prog->glob_result.gl_pathv = NULL; 2168 prog->family = pi; 2169 prog->sp = 0; 2170 ctx->child = prog; 2171 prog->type = ctx->type; 2172 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; 2173 3040 /* but ctx->pipe and ctx->list_head remain unchanged */ 2174 return 0; 3041 3042 return pi->num_progs; /* used only for 0/nonzero check */ 2175 3043 } 2176 3044 … … 2178 3046 { 2179 3047 struct pipe *new_p; 2180 done_command(ctx); /* implicit closure of previous command */ 2181 debug_printf("done_pipe, type %d\n", type); 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 */ 2182 3052 ctx->pipe->followup = type; 2183 ctx->pipe->r_mode = ctx->w; 2184 new_p=new_pipe(); 2185 ctx->pipe->next = new_p; 2186 ctx->pipe = new_p; 2187 ctx->child = NULL; 2188 done_command(ctx); /* set up new pipe to accept commands */ 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"); 2189 3065 return 0; 2190 3066 } … … 2196 3072 static int redirect_dup_num(struct in_str *input) 2197 3073 { 2198 int ch, d =0, ok=0;3074 int ch, d = 0, ok = 0; 2199 3075 ch = b_peek(input); 2200 3076 if (ch != '&') return -1; 2201 3077 2202 3078 b_getch(input); /* get the & */ 2203 ch =b_peek(input);3079 ch = b_peek(input); 2204 3080 if (ch == '-') { 2205 3081 b_getch(input); … … 2207 3083 } 2208 3084 while (isdigit(ch)) { 2209 d = d*10 +(ch-'0');2210 ok =1;3085 d = d*10 + (ch-'0'); 3086 ok = 1; 2211 3087 b_getch(input); 2212 3088 ch = b_peek(input); … … 2233 3109 int num; 2234 3110 2235 if (o->length==0) return -1; 2236 for(num=0; num<o->length; num++) { 2237 if (!isdigit(*(o->data+num))) { 3111 if (o->length == 0) 3112 return -1; 3113 for (num = 0; num < o->length; num++) { 3114 if (!isdigit(*(o->data + num))) { 2238 3115 return -1; 2239 3116 } 2240 3117 } 2241 3118 /* reuse num (and save an int) */ 2242 num =atoi(o->data);3119 num = atoi(o->data); 2243 3120 b_reset(o); 2244 3121 return num; 2245 3122 } 2246 3123 3124 #if ENABLE_HUSH_TICK 2247 3125 static FILE *generate_stream_from_list(struct pipe *head) 2248 3126 { 2249 3127 FILE *pf; 2250 #if 12251 3128 int pid, channel[2]; 2252 if (pipe(channel)<0) bb_perror_msg_and_die("pipe"); 2253 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__) 2254 pid=fork(); 3129 3130 xpipe(channel); 3131 #if BB_MMU 3132 pid = fork(); 2255 3133 #else 2256 pid =vfork();2257 #endif 2258 if (pid <0) {3134 pid = vfork(); 3135 #endif 3136 if (pid < 0) { 2259 3137 bb_perror_msg_and_die("fork"); 2260 } else if (pid ==0) {3138 } else if (pid == 0) { 2261 3139 close(channel[0]); 2262 3140 if (channel[1] != 1) { 2263 dup2(channel[1], 1);3141 dup2(channel[1], 1); 2264 3142 close(channel[1]); 2265 3143 } 2266 #if 0 2267 #define SURROGATE "surrogate response" 2268 write(1,SURROGATE,sizeof(SURROGATE)); 2269 _exit(run_list(head)); 2270 #else 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); 2271 3155 _exit(run_list_real(head)); /* leaks memory */ 2272 #endif 2273 } 2274 debug_printf("forked child %d\n",pid); 3156 } 2275 3157 close(channel[1]); 2276 pf = fdopen(channel[0],"r"); 2277 debug_printf("pipe on FILE *%p\n",pf); 2278 #else 2279 free_pipe_list(head,0); 2280 pf=popen("echo surrogate response","r"); 2281 debug_printf("started fake pipe on FILE *%p\n",pf); 2282 #endif 3158 pf = fdopen(channel[0], "r"); 2283 3159 return pf; 2284 3160 } 2285 3161 2286 /* this version hacked for testing purposes*/2287 /* return code is exit status of the process that is run. */ 2288 static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, intsubst_end)2289 { 2290 int retcode ;2291 o_string result =NULL_O_STRING;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; 2292 3168 struct p_context inner; 2293 3169 FILE *p; 2294 3170 struct in_str pipe_str; 3171 2295 3172 initialize_context(&inner); 2296 3173 2297 3174 /* recursion to generate command */ 2298 3175 retcode = parse_stream(&result, &inner, input, subst_end); 2299 if (retcode != 0) return retcode; /* syntax error or EOF */ 3176 if (retcode != 0) 3177 return retcode; /* syntax error or EOF */ 2300 3178 done_word(&result, &inner); 2301 3179 done_pipe(&inner, PIPE_SEQ); 2302 3180 b_free(&result); 2303 3181 2304 p =generate_stream_from_list(inner.list_head);2305 if (p ==NULL) return 1;3182 p = generate_stream_from_list(inner.list_head); 3183 if (p == NULL) return 1; 2306 3184 mark_open(fileno(p)); 2307 3185 setup_file_in_str(&pipe_str, p); 2308 3186 2309 3187 /* now send results of command back into original context */ 2310 retcode = parse_stream(dest, ctx, &pipe_str, '\0'); 2311 /* XXX In case of a syntax error, should we try to kill the child? 2312 * That would be tough to do right, so just read until EOF. */ 2313 if (retcode == 1) { 2314 while (b_getch(&pipe_str)!=EOF) { /* discard */ }; 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); 2315 3199 } 2316 3200 … … 2318 3202 /* This is the step that wait()s for the child. Should be pretty 2319 3203 * safe, since we just read an EOF from its stdout. We could try 2320 * to better, by using wait(), and keeping track of background jobs3204 * to do better, by using wait(), and keeping track of background jobs 2321 3205 * at the same time. That would be a lot of work, and contrary 2322 3206 * to the KISS philosophy of this program. */ 2323 3207 mark_closed(fileno(p)); 2324 retcode=pclose(p); 2325 free_pipe_list(inner.list_head,0); 2326 debug_printf("pclosed, retcode=%d\n",retcode); 2327 /* XXX this process fails to trim a single trailing newline */ 3208 retcode = fclose(p); 3209 free_pipe_list(inner.list_head, 0); 3210 debug_printf("closed FILE from child, retcode=%d\n", retcode); 2328 3211 return retcode; 2329 3212 } 3213 #endif 2330 3214 2331 3215 static int parse_group(o_string *dest, struct p_context *ctx, 2332 3216 struct in_str *input, int ch) 2333 3217 { 2334 int rcode, endch=0; 3218 int rcode; 3219 const char *endch = NULL; 2335 3220 struct p_context sub; 2336 3221 struct child_prog *child = ctx->child; 3222 3223 debug_printf_parse("parse_group entered\n"); 2337 3224 if (child->argv) { 2338 syntax(); 2339 return 1; /* syntax error, groups and arglists don't mix */ 3225 syntax(NULL); 3226 debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); 3227 return 1; 2340 3228 } 2341 3229 initialize_context(&sub); 2342 switch(ch) { 2343 case '(': endch=')'; child->subshell=1; break; 2344 case '{': endch='}'; break; 2345 default: syntax(); /* really logic error */ 2346 } 2347 rcode=parse_stream(dest,&sub,input,endch); 2348 done_word(dest,&sub); /* finish off the final word in the subcontext */ 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 */ 2349 3238 done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ 2350 3239 child->group = sub.list_head; 3240 3241 debug_printf_parse("parse_group return %d\n", rcode); 2351 3242 return rcode; 2352 3243 /* child remains "open", available for possible redirects */ 2353 3244 } 2354 3245 2355 /* basically useful version until someone wants to get fancier,3246 /* Basically useful version until someone wants to get fancier, 2356 3247 * see the bash man page under "Parameter Expansion" */ 2357 static char *lookup_param(char *src) 2358 { 2359 char *p=NULL; 2360 if (src) { 2361 p = getenv(src); 2362 if (!p) 2363 p = get_local_var(src); 2364 } 2365 return p; 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; 2366 3254 } 2367 3255 … … 2369 3257 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) 2370 3258 { 2371 int i, advance=0;2372 char sep[]=" ";2373 int ch = input->peek(input); /* first character after the $ */ 2374 debug_printf ("handle_dollar: ch=%c\n",ch);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); 2375 3263 if (isalpha(ch)) { 2376 3264 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2377 ctx->child->sp++; 2378 while(ch=b_peek(input),isalnum(ch) || ch=='_') { 3265 //sp: ctx->child->sp++; 3266 while (1) { 3267 debug_printf_parse(": '%c'\n", ch); 2379 3268 b_getch(input); 2380 b_addchr(dest,ch); 3269 b_addchr(dest, ch | quote_mask); 3270 quote_mask = 0; 3271 ch = b_peek(input); 3272 if (!isalnum(ch) && ch != '_') 3273 break; 2381 3274 } 2382 3275 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2383 3276 } else if (isdigit(ch)) { 2384 i = ch-'0'; /* XXX is $0 special? */ 2385 if (i<global_argc) { 2386 parse_string(dest, ctx, global_argv[i]); /* recursion */ 2387 } 2388 advance = 1; 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); 2389 3284 } else switch (ch) { 2390 case '$': 2391 b_adduint(dest,getpid()); 2392 advance = 1; 2393 break; 2394 case '!': 2395 if (last_bg_pid > 0) b_adduint(dest, last_bg_pid); 2396 advance = 1; 2397 break; 2398 case '?': 2399 b_adduint(dest,last_return_code); 2400 advance = 1; 2401 break; 2402 case '#': 2403 b_adduint(dest,global_argc ? global_argc-1 : 0); 2404 advance = 1; 2405 break; 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; 2406 3292 case '{': 2407 3293 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2408 ctx->child->sp++;3294 //sp: ctx->child->sp++; 2409 3295 b_getch(input); 2410 3296 /* XXX maybe someone will try to escape the '}' */ 2411 while(ch=b_getch(input),ch!=EOF && ch!='}') { 2412 b_addchr(dest,ch); 2413 } 2414 if (ch != '}') { 2415 syntax(); 2416 return 1; 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; 2417 3309 } 2418 3310 b_addchr(dest, SPECIAL_VAR_SYMBOL); 2419 3311 break; 3312 #if ENABLE_HUSH_TICK 2420 3313 case '(': 2421 3314 b_getch(input); 2422 process_command_subs(dest, ctx, input, ')');3315 process_command_subs(dest, ctx, input, ")"); 2423 3316 break; 2424 case '*': 2425 sep[0]=ifs[0]; 2426 for (i=1; i<global_argc; i++) { 2427 parse_string(dest, ctx, global_argv[i]); 2428 if (i+1 < global_argc) parse_string(dest, ctx, sep); 2429 } 2430 break; 2431 case '@': 3317 #endif 2432 3318 case '-': 2433 3319 case '_': 2434 3320 /* still unhandled, but should be eventually */ 2435 bb_error_msg("unhandled syntax: $%c", ch);3321 bb_error_msg("unhandled syntax: $%c", ch); 2436 3322 return 1; 2437 3323 break; 2438 3324 default: 2439 b_addqchr(dest,'$',dest->quote); 2440 } 2441 /* Eat the character if the flag was set. If the compiler 2442 * is smart enough, we could substitute "b_getch(input);" 2443 * for all the "advance = 1;" above, and also end up with 2444 * a nice size-optimized program. Hah! That'll be the day. 2445 */ 2446 if (advance) b_getch(input); 3325 b_addqchr(dest, '$', dest->quote); 3326 } 3327 debug_printf_parse("handle_dollar return 0\n"); 2447 3328 return 0; 2448 3329 } 2449 3330 2450 int parse_string(o_string *dest, struct p_context *ctx, const char *src)2451 {2452 struct in_str foo;2453 setup_string_in_str(&foo, src);2454 return parse_stream(dest, ctx, &foo, '\0');2455 }2456 2457 3331 /* return code is 0 for normal exit, 1 for syntax error */ 2458 int parse_stream(o_string *dest, struct p_context *ctx,2459 struct in_str *input, intend_trigger)3332 static int parse_stream(o_string *dest, struct p_context *ctx, 3333 struct in_str *input, const char *end_trigger) 2460 3334 { 2461 3335 int ch, m; … … 2468 3342 * found. When recursing, quote state is passed in via dest->quote. */ 2469 3343 2470 debug_printf("parse_stream, end_trigger=%d\n",end_trigger); 2471 while ((ch=b_getch(input))!=EOF) { 2472 m = map[ch]; 2473 next = (ch == '\n') ? 0 : b_peek(input); 2474 debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", 2475 ch,ch,m,dest->quote); 2476 if (m==0 || ((m==1 || m==2) && dest->quote)) { 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 } 2477 3365 b_addqchr(dest, ch, dest->quote); 2478 } else { 2479 if (m==2) { /* unquoted IFS */ 2480 if (done_word(dest, ctx)) { 2481 return 1; 2482 } 2483 /* If we aren't performing a substitution, treat a newline as a 2484 * command separator. */ 2485 if (end_trigger != '\0' && ch=='\n') 2486 done_pipe(ctx,PIPE_SEQ); 2487 } 2488 if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) { 2489 debug_printf("leaving parse_stream (triggered)\n"); 2490 return 0; 2491 } 2492 #if 0 2493 if (ch=='\n') { 2494 /* Yahoo! Time to run with it! */ 2495 done_pipe(ctx,PIPE_SEQ); 2496 run_list(ctx->list_head); 2497 initialize_context(ctx); 2498 } 2499 #endif 2500 if (m!=2) switch (ch) { 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) { 2501 3391 case '#': 2502 3392 if (dest->length == 0 && !dest->quote) { 2503 while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); } 3393 while (1) { 3394 ch = b_peek(input); 3395 if (ch == EOF || ch == '\n') 3396 break; 3397 b_getch(input); 3398 } 2504 3399 } else { 2505 3400 b_addqchr(dest, ch, dest->quote); … … 2508 3403 case '\\': 2509 3404 if (next == EOF) { 2510 syntax(); 3405 syntax("\\<eof>"); 3406 debug_printf_parse("parse_stream return 1: \\<eof>\n"); 2511 3407 return 1; 2512 3408 } … … 2515 3411 break; 2516 3412 case '$': 2517 if (handle_dollar(dest, ctx, input)!=0) return 1; 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 } 2518 3417 break; 2519 3418 case '\'': 2520 3419 dest->nonnull = 1; 2521 while(ch=b_getch(input),ch!=EOF && ch!='\'') { 2522 b_addchr(dest,ch); 2523 } 2524 if (ch==EOF) { 2525 syntax(); 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"); 2526 3429 return 1; 2527 3430 } … … 2531 3434 dest->quote = !dest->quote; 2532 3435 break; 3436 #if ENABLE_HUSH_TICK 2533 3437 case '`': 2534 process_command_subs(dest, ctx, input, '`');3438 process_command_subs(dest, ctx, input, "`"); 2535 3439 break; 3440 #endif 2536 3441 case '>': 2537 3442 redir_fd = redirect_opt_num(dest); 2538 3443 done_word(dest, ctx); 2539 redir_style =REDIRECT_OVERWRITE;3444 redir_style = REDIRECT_OVERWRITE; 2540 3445 if (next == '>') { 2541 redir_style =REDIRECT_APPEND;3446 redir_style = REDIRECT_APPEND; 2542 3447 b_getch(input); 2543 } else if (next == '(') { 2544 syntax(); /* until we support >(list) Process Substitution */ 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"); 2545 3453 return 1; 2546 3454 } 3455 #endif 2547 3456 setup_redirect(ctx, redir_fd, redir_style, input); 2548 3457 break; … … 2550 3459 redir_fd = redirect_opt_num(dest); 2551 3460 done_word(dest, ctx); 2552 redir_style =REDIRECT_INPUT;3461 redir_style = REDIRECT_INPUT; 2553 3462 if (next == '<') { 2554 redir_style =REDIRECT_HEREIS;3463 redir_style = REDIRECT_HEREIS; 2555 3464 b_getch(input); 2556 3465 } else if (next == '>') { 2557 redir_style =REDIRECT_IO;3466 redir_style = REDIRECT_IO; 2558 3467 b_getch(input); 2559 } else if (next == '(') { 2560 syntax(); /* until we support <(list) Process Substitution */ 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"); 2561 3473 return 1; 2562 3474 } 3475 #endif 2563 3476 setup_redirect(ctx, redir_fd, redir_style, input); 2564 3477 break; 2565 3478 case ';': 2566 3479 done_word(dest, ctx); 2567 done_pipe(ctx, PIPE_SEQ);3480 done_pipe(ctx, PIPE_SEQ); 2568 3481 break; 2569 3482 case '&': 2570 3483 done_word(dest, ctx); 2571 if (next =='&') {3484 if (next == '&') { 2572 3485 b_getch(input); 2573 done_pipe(ctx, PIPE_AND);3486 done_pipe(ctx, PIPE_AND); 2574 3487 } else { 2575 done_pipe(ctx, PIPE_BG);3488 done_pipe(ctx, PIPE_BG); 2576 3489 } 2577 3490 break; 2578 3491 case '|': 2579 3492 done_word(dest, ctx); 2580 if (next =='|') {3493 if (next == '|') { 2581 3494 b_getch(input); 2582 done_pipe(ctx, PIPE_OR);3495 done_pipe(ctx, PIPE_OR); 2583 3496 } else { 2584 3497 /* we could pick up a file descriptor choice here … … 2590 3503 case '(': 2591 3504 case '{': 2592 if (parse_group(dest, ctx, input, ch)!=0) return 1; 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 } 2593 3509 break; 2594 3510 case ')': 2595 3511 case '}': 2596 syntax(); /* Proper use of this character caught by end_trigger */ 3512 syntax("unexpected }"); /* Proper use of this character is caught by end_trigger */ 3513 debug_printf_parse("parse_stream return 1: unexpected '}'\n"); 2597 3514 return 1; 2598 break;2599 3515 default: 2600 syntax(); /* this is really an internal logic error */ 2601 return 1; 2602 } 2603 } 2604 } 2605 /* complain if quote? No, maybe we just finished a command substitution 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 2606 3521 * that was quoted. Example: 2607 3522 * $ echo "`cat foo` plus more" 2608 3523 * and we just got the EOF generated by the subshell that ran "cat foo" 2609 * The only real complaint is if we got an EOF when end_trigger != '\0',3524 * The only real complaint is if we got an EOF when end_trigger != NULL, 2610 3525 * that is, we were really supposed to get end_trigger, and never got 2611 3526 * one before the EOF. Can't use the standard "syntax error" return code, 2612 3527 * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ 2613 debug_printf("leaving parse_stream (EOF)\n"); 2614 if (end_trigger != '\0') return -1; 3528 debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); 3529 if (end_trigger) 3530 return -1; 2615 3531 return 0; 2616 3532 } 2617 3533 2618 static void mapset(const char *set, int code)2619 { 2620 const unsigned char *s;2621 for (s = (const unsigned char *)set; *s; s++) map[(int)*s] = code;2622 } 2623 2624 static void update_ ifs_map(void)2625 { 2626 /* char *ifs and char map[256] are both globals. */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. */ 2627 3543 ifs = getenv("IFS"); 2628 if (ifs == NULL) ifs=" \t\n"; 3544 if (ifs == NULL) 3545 ifs = " \t\n"; 2629 3546 /* Precompute a list of 'flow through' behavior so it can be treated 2630 3547 * quickly up front. Computation is necessary because of IFS. 2631 3548 * Special case handling of IFS == " \t\n" is not implemented. 2632 * The map[] array only really needs two bits each, and on most machines2633 * that would be faster because of the reduced L1 cache footprint.3549 * The charmap[] array only really needs two bits each, 3550 * and on most machines that would be faster (reduced L1 cache use). 2634 3551 */ 2635 memset(map,0,sizeof(map)); /* most characters flow through always */ 2636 mapset("\\$'\"`", 3); /* never flow through */ 2637 mapset("<>;&|(){}#", 1); /* flow through if quoted */ 2638 mapset(ifs, 2); /* also flow through if quoted */ 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 */ 2639 3560 } 2640 3561 2641 3562 /* most recursion does not come through here, the exception is 2642 * from builtin_source() */ 2643 int parse_stream_outer(struct in_str *inp, int flag) 2644 { 2645 3563 * from builtin_source() and builtin_eval() */ 3564 static int parse_and_run_stream(struct in_str *inp, int parse_flag) 3565 { 2646 3566 struct p_context ctx; 2647 o_string temp =NULL_O_STRING;3567 o_string temp = NULL_O_STRING; 2648 3568 int rcode; 2649 3569 do { 2650 ctx. type =flag;3570 ctx.parse_type = parse_flag; 2651 3571 initialize_context(&ctx); 2652 update_ifs_map(); 2653 if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0); 2654 inp->promptmode=1; 2655 rcode = parse_stream(&temp, &ctx, inp, '\n'); 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"); 2656 3582 if (rcode != 1 && ctx.old_flag != 0) { 2657 syntax( );3583 syntax(NULL); 2658 3584 } 2659 3585 if (rcode != 1 && ctx.old_flag == 0) { 2660 3586 done_word(&temp, &ctx); 2661 done_pipe(&ctx,PIPE_SEQ); 3587 done_pipe(&ctx, PIPE_SEQ); 3588 debug_print_tree(ctx.list_head, 0); 3589 debug_printf_exec("parse_stream_outer: run_list\n"); 2662 3590 run_list(ctx.list_head); 2663 3591 } else { … … 2669 3597 temp.quote = 0; 2670 3598 inp->p = NULL; 2671 free_pipe_list(ctx.list_head, 0);3599 free_pipe_list(ctx.list_head, 0); 2672 3600 } 2673 3601 b_free(&temp); 2674 } while (rcode != -1 && !( flag &FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */3602 } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ 2675 3603 return 0; 2676 3604 } 2677 3605 2678 static int parse_ string_outer(const char *s, intflag)3606 static int parse_and_run_string(const char *s, int parse_flag) 2679 3607 { 2680 3608 struct in_str input; 2681 3609 setup_string_in_str(&input, s); 2682 return parse_ stream_outer(&input,flag);2683 } 2684 2685 static int parse_ file_outer(FILE *f)3610 return parse_and_run_stream(&input, parse_flag); 3611 } 3612 3613 static int parse_and_run_file(FILE *f) 2686 3614 { 2687 3615 int rcode; 2688 3616 struct in_str input; 2689 3617 setup_file_in_str(&input, f); 2690 rcode = parse_ stream_outer(&input, FLAG_PARSE_SEMICOLON);3618 rcode = parse_and_run_stream(&input, PARSEFLAG_SEMICOLON); 2691 3619 return rcode; 2692 3620 } 2693 3621 3622 #if ENABLE_HUSH_JOB 2694 3623 /* Make sure we have a controlling tty. If we get started under a job 2695 3624 * aware app (like bash for example), make sure we are now in charge so … … 2697 3626 static void setup_job_control(void) 2698 3627 { 2699 static pid_t shell_pgrp; 2700 /* Loop until we are in the foreground. */ 2701 while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ())) 2702 kill (- shell_pgrp, SIGTTIN); 2703 2704 /* Ignore interactive and job-control signals. */ 2705 signal(SIGINT, SIG_IGN); 2706 signal(SIGQUIT, SIG_IGN); 2707 signal(SIGTERM, SIG_IGN); 2708 signal(SIGTSTP, SIG_IGN); 2709 signal(SIGTTIN, SIG_IGN); 2710 signal(SIGTTOU, SIG_IGN); 2711 signal(SIGCHLD, SIG_IGN); 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); 2712 3649 2713 3650 /* Put ourselves in our own process group. */ 2714 setsid(); 2715 shell_pgrp = getpid (); 2716 setpgid (shell_pgrp, shell_pgrp); 2717 3651 setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 2718 3652 /* Grab control of the terminal. */ 2719 tcsetpgrp(shell_terminal, shell_pgrp); 2720 } 2721 3653 tcsetpgrp(interactive_fd, getpid()); 3654 } 3655 #endif 3656 3657 int hush_main(int argc, char **argv); 2722 3658 int hush_main(int argc, char **argv) 2723 3659 { 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 2724 3669 int opt; 2725 3670 FILE *input; 2726 char **e = environ; 2727 3671 char **e; 3672 struct variable *cur_var; 3673 3674 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 3675 3676 /* Deal with HUSH_VERSION */ 3677 shell_ver = const_shell_ver; /* copying struct here */ 3678 top_var = &shell_ver; 3679 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; 3683 e = environ; 3684 if (e) while (*e) { 3685 char *value = strchr(*e, '='); 3686 if (value) { /* paranoia */ 3687 cur_var->next = xzalloc(sizeof(*cur_var)); 3688 cur_var = cur_var->next; 3689 cur_var->varstr = *e; 3690 cur_var->max_len = strlen(*e); 3691 cur_var->flg_export = 1; 3692 } 3693 e++; 3694 } 3695 putenv((char *)version_str); /* reinstate HUSH_VERSION */ 3696 3697 #if ENABLE_FEATURE_EDITING 3698 line_input_state = new_line_input_t(FOR_SHELL); 3699 #endif 2728 3700 /* XXX what should these be while sourcing /etc/profile? */ 2729 3701 global_argc = argc; 2730 3702 global_argv = argv; 2731 2732 /* (re?) initialize globals. Sometimes hush_main() ends up calling2733 * hush_main(), therefore we cannot rely on the BSS to zero out this2734 * stuff. Reset these to 0 every time. */2735 ifs = NULL;2736 /* map[] is taken care of with call to update_ifs_map() */2737 fake_mode = 0;2738 interactive = 0;2739 close_me_head = NULL;2740 last_bg_pid = 0;2741 job_list = NULL;2742 last_jobid = 0;2743 2744 3703 /* Initialize some more globals to non-zero values */ 2745 3704 set_cwd(); 2746 #ifdef CONFIG_FEATURE_COMMAND_EDITING 3705 #if ENABLE_HUSH_INTERACTIVE 3706 #if ENABLE_FEATURE_EDITING 2747 3707 cmdedit_set_initial_prompt(); 2748 #else2749 PS1 = NULL;2750 3708 #endif 2751 3709 PS2 = "> "; 2752 2753 /* initialize our shell local variables with the values 2754 * currently living in the environment */ 2755 if (e) { 2756 for (; *e; e++) 2757 set_local_var(*e, 2); /* without call putenv() */ 2758 } 2759 2760 last_return_code=EXIT_SUCCESS; 2761 3710 #endif 3711 3712 if (EXIT_SUCCESS) /* otherwise is already done */ 3713 last_return_code = EXIT_SUCCESS; 2762 3714 2763 3715 if (argv[0] && argv[0][0] == '-') { 2764 debug_printf("\nsourcing /etc/profile\n"); 2765 if ((input = fopen("/etc/profile", "r")) != NULL) { 3716 debug_printf("sourcing /etc/profile\n"); 3717 input = fopen("/etc/profile", "r"); 3718 if (input != NULL) { 2766 3719 mark_open(fileno(input)); 2767 parse_ file_outer(input);3720 parse_and_run_file(input); 2768 3721 mark_closed(fileno(input)); 2769 3722 fclose(input); 2770 3723 } 2771 3724 } 2772 input =stdin;3725 input = stdin; 2773 3726 2774 3727 while ((opt = getopt(argc, argv, "c:xif")) > 0) { 2775 3728 switch (opt) { 2776 case 'c': 2777 { 2778 global_argv = argv+optind; 2779 global_argc = argc-optind; 2780 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); 2781 goto final_return; 2782 } 2783 break; 2784 case 'i': 2785 interactive++; 2786 break; 2787 case 'f': 2788 fake_mode++; 2789 break; 2790 default: 3729 case 'c': 3730 global_argv = argv + optind; 3731 global_argc = argc - optind; 3732 opt = parse_and_run_string(optarg, PARSEFLAG_SEMICOLON); 3733 goto final_return; 3734 case 'i': 3735 /* Well, we cannot just declare interactiveness, 3736 * we have to have some stuff (ctty, etc) */ 3737 /* interactive_fd++; */ 3738 break; 3739 case 'f': 3740 fake_mode = 1; 3741 break; 3742 default: 2791 3743 #ifndef BB_VER 2792 2793 2794 3744 fprintf(stderr, "Usage: sh [FILE]...\n" 3745 " or: sh -c command [args]...\n\n"); 3746 exit(EXIT_FAILURE); 2795 3747 #else 2796 bb_show_usage(); 2797 #endif 2798 } 2799 } 2800 /* A shell is interactive if the `-i' flag was given, or if all of 3748 bb_show_usage(); 3749 #endif 3750 } 3751 } 3752 #if ENABLE_HUSH_JOB 3753 /* A shell is interactive if the '-i' flag was given, or if all of 2801 3754 * the following conditions are met: 2802 * 3755 * no -c command 2803 3756 * no arguments remaining or the -s flag given 2804 3757 * standard input is a terminal 2805 3758 * standard output is a terminal 2806 * Refer to Posix.2, the description of the `sh' utility. */ 2807 if (argv[optind]==NULL && input==stdin && 2808 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 2809 interactive++; 2810 } 2811 2812 debug_printf("\ninteractive=%d\n", interactive); 2813 if (interactive) { 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) { 2814 3781 /* Looks like they want an interactive shell */ 2815 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET2816 printf( "\n\n%s hush - the humble shell v0.01 (testing)\n",2817 BB_BANNER);2818 printf( "Enter 'help' for a list of built-in commands.\n\n");2819 #endif2820 3782 setup_job_control(); 2821 } 2822 2823 if (argv[optind]==NULL) { 2824 opt=parse_file_outer(stdin); 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 3794 } 3795 #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) { 3802 /* try to dup to any fd */ 3803 interactive_fd = dup(STDIN_FILENO); 3804 if (interactive_fd < 0) 3805 /* give up */ 3806 interactive_fd = 0; 3807 } 3808 } 3809 3810 #endif 3811 3812 if (argv[optind] == NULL) { 3813 opt = parse_and_run_file(stdin); 2825 3814 goto final_return; 2826 3815 } 2827 3816 2828 3817 debug_printf("\nrunning script '%s'\n", argv[optind]); 2829 global_argv = argv+optind; 2830 global_argc = argc-optind; 2831 input = bb_xfopen(argv[optind], "r"); 2832 opt = parse_file_outer(input); 2833 2834 #ifdef CONFIG_FEATURE_CLEAN_UP 3818 global_argv = argv + optind; 3819 global_argc = argc - optind; 3820 input = xfopen(argv[optind], "r"); 3821 opt = parse_and_run_file(input); 3822 3823 final_return: 3824 3825 #if ENABLE_FEATURE_CLEAN_UP 2835 3826 fclose(input); 2836 if (cwd && cwd!= bb_msg_unknown)3827 if (cwd != bb_msg_unknown) 2837 3828 free((char*)cwd); 2838 { 2839 struct variables *cur, *tmp; 2840 for(cur = top_vars; cur; cur = tmp) { 2841 tmp = cur->next; 2842 if (!cur->flg_read_only) { 2843 free(cur->name); 2844 free(cur->value); 2845 free(cur); 2846 } 2847 } 2848 } 2849 #endif 2850 2851 final_return: 2852 return(opt?opt:last_return_code); 2853 } 2854 2855 static char *insert_var_value(char *inp) 2856 { 2857 int res_str_len = 0; 2858 int len; 2859 int done = 0; 2860 char *p, *p1, *res_str = NULL; 2861 2862 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { 2863 if (p != inp) { 2864 len = p - inp; 2865 res_str = xrealloc(res_str, (res_str_len + len)); 2866 strncpy((res_str + res_str_len), inp, len); 2867 res_str_len += len; 2868 } 2869 inp = ++p; 2870 p = strchr(inp, SPECIAL_VAR_SYMBOL); 2871 *p = '\0'; 2872 if ((p1 = lookup_param(inp))) { 2873 len = res_str_len + strlen(p1); 2874 res_str = xrealloc(res_str, (1 + len)); 2875 strcpy((res_str + res_str_len), p1); 2876 res_str_len = len; 2877 } 2878 *p = SPECIAL_VAR_SYMBOL; 2879 inp = ++p; 2880 done = 1; 2881 } 2882 if (done) { 2883 res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp))); 2884 strcpy((res_str + res_str_len), inp); 2885 while ((p = strchr(res_str, '\n'))) { 2886 *p = ' '; 2887 } 2888 } 2889 return (res_str == NULL) ? inp : res_str; 2890 } 2891 2892 static char **make_list_in(char **inp, char *name) 2893 { 2894 int len, i; 2895 int name_len = strlen(name); 2896 int n = 0; 2897 char **list; 2898 char *p1, *p2, *p3; 2899 2900 /* create list of variable values */ 2901 list = xmalloc(sizeof(*list)); 2902 for (i = 0; inp[i]; i++) { 2903 p3 = insert_var_value(inp[i]); 2904 p1 = p3; 2905 while (*p1) { 2906 if ((*p1 == ' ')) { 2907 p1++; 2908 continue; 2909 } 2910 if ((p2 = strchr(p1, ' '))) { 2911 len = p2 - p1; 2912 } else { 2913 len = strlen(p1); 2914 p2 = p1 + len; 2915 } 2916 /* we use n + 2 in realloc for list,because we add 2917 * new element and then we will add NULL element */ 2918 list = xrealloc(list, sizeof(*list) * (n + 2)); 2919 list[n] = xmalloc(2 + name_len + len); 2920 strcpy(list[n], name); 2921 strcat(list[n], "="); 2922 strncat(list[n], p1, len); 2923 list[n++][name_len + len + 1] = '\0'; 2924 p1 = p2; 2925 } 2926 if (p3 != inp[i]) free(p3); 2927 } 2928 list[n] = NULL; 2929 return list; 2930 } 2931 2932 /* Make new string for parser */ 2933 static char * make_string(char ** inp) 2934 { 2935 char *p; 2936 char *str = NULL; 2937 int n; 2938 int len = 2; 2939 2940 for (n = 0; inp[n]; n++) { 2941 p = insert_var_value(inp[n]); 2942 str = xrealloc(str, (len + strlen(p))); 2943 if (n) { 2944 strcat(str, " "); 2945 } else { 2946 *str = '\0'; 2947 } 2948 strcat(str, p); 2949 len = strlen(str) + 3; 2950 if (p != inp[n]) free(p); 2951 } 2952 len = strlen(str); 2953 *(str + len) = '\n'; 2954 *(str + len + 1) = '\0'; 2955 return str; 2956 } 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 } -
branches/stable/mindi-busybox/shell/lash.c
r821 r1770 21 21 //#define DEBUG_SHELL 22 22 23 24 #include "busybox.h"25 #include <stdio.h>26 #include <stdlib.h>27 #include <ctype.h>28 #include <errno.h>29 #include <fcntl.h>30 #include <signal.h>31 #include <string.h>32 #include <sys/ioctl.h>33 #include <sys/wait.h>34 #include <unistd.h>35 23 #include <getopt.h> 36 #include <termios.h>37 #include "cmdedit.h"38 39 #ifdef CONFIG_LOCALE_SUPPORT40 #include <locale.h>41 #endif42 43 24 #include <glob.h> 25 26 #include "busybox.h" /* for struct bb_applet */ 27 44 28 #define expand_t glob_t 45 29 … … 47 31 #define CONFIG_LASH_PIPE_N_REDIRECTS 48 32 #define CONFIG_LASH_JOB_CONTROL 49 50 static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ 33 #define ENABLE_LASH_PIPE_N_REDIRECTS 1 34 #define ENABLE_LASH_JOB_CONTROL 1 35 36 37 enum { MAX_READ = 128 }; /* size of input buffer for 'read' builtin */ 51 38 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 52 39 53 40 54 #if def CONFIG_LASH_PIPE_N_REDIRECTS41 #if ENABLE_LASH_PIPE_N_REDIRECTS 55 42 enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, 56 43 REDIRECT_APPEND … … 66 53 }; 67 54 68 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS 55 #define LASH_OPT_DONE (1) 56 #define LASH_OPT_SAW_QUOTE (2) 57 58 #if ENABLE_LASH_PIPE_N_REDIRECTS 69 59 struct redir_struct { 70 60 enum redir_type type; /* type of redirection */ … … 80 70 int is_stopped; /* is the program currently running? */ 81 71 struct job *family; /* pointer back to the child's parent job */ 82 #if def CONFIG_LASH_PIPE_N_REDIRECTS72 #if ENABLE_LASH_PIPE_N_REDIRECTS 83 73 struct redir_struct *redirects; /* I/O redirects */ 84 74 #endif … … 105 95 106 96 struct built_in_command { 107 c har *cmd;/* name */108 c har *descr;/* description */97 const char *cmd; /* name */ 98 const char *descr; /* description */ 109 99 int (*function) (struct child_prog *); /* function ptr */ 110 100 }; … … 127 117 static void checkjobs(struct jobset *job_list); 128 118 static void remove_job(struct jobset *j_list, struct job *job); 129 static int get_command (FILE * source, char *command);119 static int get_command_bufsiz(FILE * source, char *command); 130 120 static int parse_command(char **command_ptr, struct job *job, int *inbg); 131 121 static int run_command(struct job *newjob, int inbg, int outpipe[2]); … … 137 127 * can change global variables in the parent shell process but they will not 138 128 * work with pipes and redirects; 'unset foo | whatever' will not work) */ 139 static struct built_in_command bltins[] = {140 {"bg" , "Resume a job in the background", builtin_fg_bg},141 {"cd" , "Change working directory", builtin_cd},142 {"exec" , "Exec command, replacing this shell with the exec'd process", builtin_exec},143 {"exit" , "Exit from shell()", builtin_exit},144 {"fg" , "Bring job into the foreground", builtin_fg_bg},145 {"jobs" , "Lists the active jobs", builtin_jobs},129 static const struct built_in_command bltins[] = { 130 {"bg" , "Resume a job in the background", builtin_fg_bg}, 131 {"cd" , "Change working directory", builtin_cd}, 132 {"exec" , "Exec command, replacing this shell with the exec'd process", builtin_exec}, 133 {"exit" , "Exit from shell()", builtin_exit}, 134 {"fg" , "Bring job into the foreground", builtin_fg_bg}, 135 {"jobs" , "Lists the active jobs", builtin_jobs}, 146 136 {"export", "Set environment variable", builtin_export}, 147 {"unset", "Unset environment variable", builtin_unset}, 148 {"read", "Input environment variable", builtin_read}, 149 {".", "Source-in and run commands in a file", builtin_source}, 137 {"unset" , "Unset environment variable", builtin_unset}, 138 {"read" , "Input environment variable", builtin_read}, 139 {"." , "Source-in and run commands in a file", builtin_source}, 140 /* These were "forked applets", but distinction was nuked */ 141 /* Original comment retained: */ 142 /* Table of forking built-in functions (things that fork cannot change global 143 * variables in the parent process, such as the current working directory) */ 144 {"pwd" , "Print current directory", builtin_pwd}, 145 {"help" , "List shell built-in commands", builtin_help}, 150 146 /* to do: add ulimit */ 151 {NULL, NULL, NULL}152 147 }; 153 148 154 /* Table of forking built-in functions (things that fork cannot change global 155 * variables in the parent process, such as the current working directory) */ 156 static struct built_in_command bltins_forking[] = { 157 {"pwd", "Print current directory", builtin_pwd}, 158 {"help", "List shell built-in commands", builtin_help}, 159 {NULL, NULL, NULL} 160 }; 149 150 #define VEC_LAST(v) v[ARRAY_SIZE(v)-1] 161 151 162 152 … … 165 155 166 156 /* Globals that are static to this file */ 167 static c onst char *cwd;168 static char *local_pending_command = NULL;157 static char *cwd; 158 static char *local_pending_command; 169 159 static struct jobset job_list = { NULL, NULL }; 170 160 static int argc; … … 175 165 static unsigned int last_jobid; 176 166 static int shell_terminal; 177 static c har *PS1;178 static c har *PS2 = "> ";167 static const char *PS1; 168 static const char *PS2 = "> "; 179 169 180 170 … … 188 178 } 189 179 #else 190 static inline void debug_printf(const char *format, ...) { }180 static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { } 191 181 #endif 192 182 … … 219 209 */ 220 210 211 212 static void update_cwd(void) 213 { 214 cwd = xrealloc_getcwd_or_warn(cwd); 215 if (!cwd) 216 cwd = xstrdup(bb_msg_unknown); 217 } 218 221 219 /* built-in 'cd <path>' handler */ 222 220 static int builtin_cd(struct child_prog *child) … … 232 230 return EXIT_FAILURE; 233 231 } 234 cwd = xgetcwd((char *)cwd); 235 if (!cwd) 236 cwd = bb_msg_unknown; 232 update_cwd(); 237 233 return EXIT_SUCCESS; 238 234 } … … 244 240 return EXIT_SUCCESS; /* Really? */ 245 241 child->argv++; 246 while(close_me_list) close((long)llist_pop(&close_me_list)); 242 while (close_me_list) 243 close((long)llist_pop(&close_me_list)); 247 244 pseudo_exec(child); 248 245 /* never returns */ … … 255 252 exit(EXIT_SUCCESS); 256 253 257 exit 254 exit(atoi(child->argv[1])); 258 255 } 259 256 … … 262 259 { 263 260 int i, jobnum; 264 struct job *job =NULL;261 struct job *job; 265 262 266 263 /* If they gave us no args, assume they want the last backgrounded task */ … … 268 265 for (job = child->family->job_list->head; job; job = job->next) { 269 266 if (job->jobid == last_jobid) { 270 break; 271 } 272 } 273 if (!job) { 274 bb_error_msg("%s: no current job", child->argv[0]); 275 return EXIT_FAILURE; 276 } 277 } else { 278 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { 279 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]); 280 return EXIT_FAILURE; 281 } 282 for (job = child->family->job_list->head; job; job = job->next) { 283 if (job->jobid == jobnum) { 284 break; 285 } 286 } 287 if (!job) { 288 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); 289 return EXIT_FAILURE; 290 } 291 } 292 267 goto found; 268 } 269 } 270 bb_error_msg("%s: no current job", child->argv[0]); 271 return EXIT_FAILURE; 272 } 273 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { 274 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]); 275 return EXIT_FAILURE; 276 } 277 for (job = child->family->job_list->head; job; job = job->next) { 278 if (job->jobid == jobnum) { 279 goto found; 280 } 281 } 282 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); 283 return EXIT_FAILURE; 284 found: 293 285 if (*child->argv[0] == 'f') { 294 286 /* Put the job into the foreground. */ … … 304 296 job->stopped_progs = 0; 305 297 306 if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { 307 if (i == ESRCH) { 298 i = kill(- job->pgrp, SIGCONT); 299 if (i < 0) { 300 if (errno == ESRCH) { 308 301 remove_job(&job_list, job); 309 302 } else { … … 316 309 317 310 /* built-in 'help' handler */ 318 static int builtin_help(struct child_prog *dummy)319 { 320 struct built_in_command *x;321 322 printf("\nBuilt-in commands:\n" );323 printf("-------------------\n");324 for (x = bltins; x ->cmd; x++) {325 if (x->descr ==NULL)311 static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy) 312 { 313 const struct built_in_command *x; 314 315 printf("\nBuilt-in commands:\n" 316 "-------------------\n"); 317 for (x = bltins; x <= &VEC_LAST(bltins); x++) { 318 if (x->descr == NULL) 326 319 continue; 327 320 printf("%s\t%s\n", x->cmd, x->descr); 328 321 } 329 for (x = bltins_forking; x->cmd; x++) { 330 if (x->descr==NULL) 331 continue; 332 printf("%s\t%s\n", x->cmd, x->descr); 333 } 334 printf("\n\n"); 322 putchar('\n'); 335 323 return EXIT_SUCCESS; 336 324 } … … 340 328 { 341 329 struct job *job; 342 c har *status_string;330 const char *status_string; 343 331 344 332 for (job = child->family->job_list->head; job; job = job->next) { … … 355 343 356 344 /* built-in 'pwd' handler */ 357 static int builtin_pwd(struct child_prog *dummy) 358 { 359 cwd = xgetcwd((char *)cwd); 360 if (!cwd) 361 cwd = bb_msg_unknown; 345 static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy) 346 { 347 update_cwd(); 362 348 puts(cwd); 363 349 return EXIT_SUCCESS; … … 380 366 if (res) 381 367 bb_perror_msg("export"); 382 #if def CONFIG_FEATURE_SH_FANCY_PROMPT383 if (strncmp(v, "PS1=", 4) ==0)368 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT 369 if (strncmp(v, "PS1=", 4) == 0) 384 370 PS1 = getenv("PS1"); 385 371 #endif 386 372 387 #ifdef CONFIG_LOCALE_SUPPORT 388 if(strncmp(v, "LC_ALL=", 7)==0) 373 #if ENABLE_LOCALE_SUPPORT 374 // TODO: why getenv? "" would be just as good... 375 if (strncmp(v, "LC_ALL=", 7) == 0) 389 376 setlocale(LC_ALL, getenv("LC_ALL")); 390 if (strncmp(v, "LC_CTYPE=", 9)==0)377 if (strncmp(v, "LC_CTYPE=", 9) == 0) 391 378 setlocale(LC_CTYPE, getenv("LC_CTYPE")); 392 379 #endif 393 380 394 return (res);381 return res; 395 382 } 396 383 … … 398 385 static int builtin_read(struct child_prog *child) 399 386 { 400 int res = 0, len , newlen;387 int res = 0, len; 401 388 char *s; 402 389 char string[MAX_READ]; … … 409 396 string[len] = '\0'; 410 397 fgets(&string[len], sizeof(string) - len, stdin); /* read string */ 411 newlen= strlen(string);412 if (newlen> len)413 string[-- newlen] = '\0'; /* chomp trailing newline */398 res = strlen(string); 399 if (res > len) 400 string[--res] = '\0'; /* chomp trailing newline */ 414 401 /* 415 402 ** string should now contain "VAR=<value>" … … 418 405 */ 419 406 res = -1; 420 if((s = strdup(string))) 407 s = strdup(string); 408 if (s) 421 409 res = putenv(s); 422 410 if (res) 423 411 bb_perror_msg("read"); 424 } 425 else 412 } else 426 413 fgets(string, sizeof(string), stdin); 427 414 428 return (res);415 return res; 429 416 } 430 417 … … 435 422 int status; 436 423 437 if (child->argv[1] == NULL) 438 return EXIT_FAILURE; 439 440 input = fopen(child->argv[1], "r"); 424 input = fopen_or_warn(child->argv[1], "r"); 441 425 if (!input) { 442 printf( "Couldn't open file '%s'\n", child->argv[1]);443 426 return EXIT_FAILURE; 444 427 } … … 449 432 fclose(input); 450 433 llist_pop(&close_me_list); 451 return (status);434 return status; 452 435 } 453 436 … … 463 446 } 464 447 465 #if def CONFIG_LASH_JOB_CONTROL448 #if ENABLE_LASH_JOB_CONTROL 466 449 /* free up all memory from a job */ 467 450 static void free_job(struct job *cmd) … … 472 455 for (i = 0; i < cmd->num_progs; i++) { 473 456 free(cmd->progs[i].argv); 474 #if def CONFIG_LASH_PIPE_N_REDIRECTS457 #if ENABLE_LASH_PIPE_N_REDIRECTS 475 458 if (cmd->progs[i].redirects) 476 459 free(cmd->progs[i].redirects); … … 527 510 528 511 /* This happens on backticked commands */ 529 if (job==NULL)512 if (job == NULL) 530 513 return; 531 514 … … 537 520 if (!job->running_progs) { 538 521 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); 539 last_jobid =0;522 last_jobid = 0; 540 523 remove_job(j_list, job); 541 524 } … … 544 527 job->stopped_progs++; 545 528 job->progs[prognum].is_stopped = 1; 546 547 #if 0548 /* Printing this stuff is a pain, since it tends to549 * overwrite the prompt an inconveinient moments. So550 * don't do that. */551 if (job->stopped_progs == job->num_progs) {552 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",553 job->text);554 }555 #endif556 529 } 557 530 } … … 572 545 #endif 573 546 574 #if def CONFIG_LASH_PIPE_N_REDIRECTS547 #if ENABLE_LASH_PIPE_N_REDIRECTS 575 548 /* squirrel != NULL means we squirrel away copies of stdin, stdout, 576 549 * and stderr if they are redirected. */ … … 595 568 } 596 569 597 openfd = open (redir->filename, mode, 0666);570 openfd = open3_or_warn(redir->filename, mode, 0666); 598 571 if (openfd < 0) { 599 572 /* this could get lost if stderr has been redirected, but 600 573 bash and ash both lose it as well (though zsh doesn't!) */ 601 bb_perror_msg("error opening %s", redir->filename);602 574 return 1; 603 575 } … … 606 578 if (squirrel && redir->fd < 3) { 607 579 squirrel[redir->fd] = dup(redir->fd); 608 fcntl 580 fcntl(squirrel[redir->fd], F_SETFD, FD_CLOEXEC); 609 581 } 610 582 dup2(openfd, redir->fd); … … 619 591 { 620 592 int i, fd; 621 for (i =0; i<3; i++) {593 for (i = 0; i < 3; i++) { 622 594 fd = squirrel[i]; 623 595 if (fd != -1) { … … 641 613 static inline void cmdedit_set_initial_prompt(void) 642 614 { 643 #if ndef CONFIG_FEATURE_SH_FANCY_PROMPT615 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 644 616 PS1 = NULL; 645 617 #else 646 618 PS1 = getenv("PS1"); 647 if (PS1==0)619 if (PS1 == 0) 648 620 PS1 = "\\w \\$ "; 649 621 #endif 650 622 } 651 623 652 static inline void setup_prompt_string(char **prompt_str)653 { 654 #if ndef CONFIG_FEATURE_SH_FANCY_PROMPT624 static inline const char* setup_prompt_string(void) 625 { 626 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 655 627 /* Set up the prompt */ 656 628 if (shell_context == 0) { 657 free(PS1); 658 PS1=xmalloc(strlen(cwd)+4); 659 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); 660 *prompt_str = PS1; 629 char *ns; 630 free((char*)PS1); 631 ns = xmalloc(strlen(cwd)+4); 632 sprintf(ns, "%s %c ", cwd, (geteuid() != 0) ? '$': '#'); 633 PS1 = ns; 634 return ns; 661 635 } else { 662 *prompt_str =PS2;636 return PS2; 663 637 } 664 638 #else 665 *prompt_str = (shell_context==0)? PS1 : PS2; 666 #endif 667 } 668 669 static int get_command(FILE * source, char *command) 670 { 671 char *prompt_str; 639 return (shell_context == 0)? PS1 : PS2; 640 #endif 641 } 642 643 #if ENABLE_FEATURE_EDITING 644 static line_input_t *line_input_state; 645 #endif 646 647 static int get_command_bufsiz(FILE * source, char *command) 648 { 649 const char *prompt_str; 672 650 673 651 if (source == NULL) { 674 652 if (local_pending_command) { 675 653 /* a command specified (-c option): return it & mark it done */ 676 strcpy(command, local_pending_command); 677 free(local_pending_command); 654 strncpy(command, local_pending_command, BUFSIZ); 678 655 local_pending_command = NULL; 679 656 return 0; … … 683 660 684 661 if (source == stdin) { 685 setup_prompt_string(&prompt_str);686 687 #if def CONFIG_FEATURE_COMMAND_EDITING662 prompt_str = setup_prompt_string(); 663 664 #if ENABLE_FEATURE_EDITING 688 665 /* 689 666 ** enable command line editing only while a command line … … 692 669 ** child processes (rob@sysgo.de) 693 670 */ 694 cmdedit_read_input(prompt_str, command);671 read_line_input(prompt_str, command, BUFSIZ, line_input_state); 695 672 return 0; 696 673 #else … … 701 678 if (!fgets(command, BUFSIZ - 2, source)) { 702 679 if (source == stdin) 703 p rintf("\n");680 puts(""); 704 681 return 1; 705 682 } … … 708 685 } 709 686 710 static char* itoa(register int i) 711 { 712 static char a[7]; /* Max 7 ints */ 713 register char *b = a + sizeof(a) - 1; 714 int sign = (i < 0); 715 716 if (sign) 717 i = -i; 718 *b = 0; 719 do 720 { 721 *--b = '0' + (i % 10); 722 i /= 10; 723 } 724 while (i); 725 if (sign) 726 *--b = '-'; 727 return b; 728 } 729 730 static char * strsep_space( char *string, int * ix) 731 { 732 char *token; 733 687 static char * strsep_space(char *string, int * ix) 688 { 734 689 /* Short circuit the trivial case */ 735 if ( 690 if (!string || ! string[*ix]) 736 691 return NULL; 737 692 738 693 /* Find the end of the token. */ 739 while (string[*ix] && !isspace(string[*ix]) ) {694 while (string[*ix] && !isspace(string[*ix]) ) { 740 695 (*ix)++; 741 696 } … … 743 698 /* Find the end of any whitespace trailing behind 744 699 * the token and let that be part of the token */ 745 while ( string[*ix] && isspace(string[*ix]) ) {700 while (string[*ix] && (isspace)(string[*ix]) ) { 746 701 (*ix)++; 747 702 } … … 752 707 } 753 708 754 token = bb_xstrndup(string, *ix); 755 756 return token; 709 return xstrndup(string, *ix); 757 710 } 758 711 759 712 static int expand_arguments(char *command) 760 713 { 761 int total_length=0, length, i, retval, ix = 0; 714 static const char out_of_space[] ALIGN1 = "out of space during expansion"; 715 716 int total_length = 0, length, i, retval, ix = 0; 762 717 expand_t expand_result; 763 718 char *tmpcmd, *cmd, *cmd_copy; 764 719 char *src, *dst, *var; 765 const char *out_of_space = "out of space during expansion";766 720 int flags = GLOB_NOCHECK 767 721 #ifdef GLOB_BRACE … … 777 731 778 732 /* Fix up escape sequences to be the Real Thing(tm) */ 779 while (command && command[ix]) {733 while (command && command[ix]) { 780 734 if (command[ix] == '\\') { 781 735 const char *tmp = command+ix+1; … … 793 747 /* We need a clean copy, so strsep can mess up the copy while 794 748 * we write stuff into the original (in a minute) */ 795 cmd = cmd_copy = bb_xstrdup(command);749 cmd = cmd_copy = xstrdup(command); 796 750 *command = '\0'; 797 751 for (ix = 0, tmpcmd = cmd; 798 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix =0) {752 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix = 0) { 799 753 if (*tmpcmd == '\0') 800 754 break; … … 805 759 if (retval == GLOB_NOSPACE) { 806 760 /* Mem may have been allocated... */ 807 globfree 761 globfree(&expand_result); 808 762 bb_error_msg(out_of_space); 809 763 return FALSE; … … 817 771 /* Convert from char** (one word per string) to a simple char*, 818 772 * but don't overflow command which is BUFSIZ in length */ 819 for (i =0; i < expand_result.gl_pathc; i++) {820 length =strlen(expand_result.gl_pathv[i]);773 for (i = 0; i < expand_result.gl_pathc; i++) { 774 length = strlen(expand_result.gl_pathv[i]); 821 775 if (total_length+length+1 >= BUFSIZ) { 822 776 bb_error_msg(out_of_space); … … 824 778 } 825 779 strcat(command+total_length, " "); 826 total_length +=1;780 total_length += 1; 827 781 strcat(command+total_length, expand_result.gl_pathv[i]); 828 total_length +=length;829 } 830 globfree 782 total_length += length; 783 } 784 globfree(&expand_result); 831 785 } 832 786 } … … 837 791 * wordexp can't do for us, namely $? and $! */ 838 792 src = command; 839 while ((dst = strchr(src,'$')) != NULL){793 while ((dst = strchr(src,'$')) != NULL) { 840 794 var = NULL; 841 switch (*(dst+1)) {795 switch (*(dst+1)) { 842 796 case '?': 843 797 var = itoa(last_return_code); 844 798 break; 845 799 case '!': 846 if (last_bg_pid ==-1)847 * (var)='\0';800 if (last_bg_pid == -1) 801 *var = '\0'; 848 802 else 849 803 var = itoa(last_bg_pid); … … 863 817 case '5':case '6':case '7':case '8':case '9': 864 818 { 865 int ixx =*(dst+1)-48+1;819 int ixx = *(dst+1)-48+1; 866 820 if (ixx >= argc) { 867 var ='\0';821 var = '\0'; 868 822 } else { 869 823 var = argv[ixx]; … … 876 830 /* a single character construction was found, and 877 831 * already handled in the case statement */ 878 src =dst+2;832 src = dst + 2; 879 833 } else { 880 834 /* Looks like an environment variable */ 881 835 char delim_hold; 882 int num_skip_chars =0;836 int num_skip_chars = 0; 883 837 int dstlen = strlen(dst); 884 838 /* Is this a ${foo} type variable? */ 885 if (dstlen >= 2 && *(dst+1) == '{') {886 src =strchr(dst+1, '}');887 num_skip_chars =1;839 if (dstlen >= 2 && *(dst+1) == '{') { 840 src = strchr(dst+1, '}'); 841 num_skip_chars = 1; 888 842 } else { 889 src =dst+1;890 while (isalnum(*src) || *src=='_') src++;843 src = dst + 1; 844 while ((isalnum)(*src) || *src == '_') src++; 891 845 } 892 846 if (src == NULL) { 893 847 src = dst+dstlen; 894 848 } 895 delim_hold =*src;896 *src ='\0'; /* temporary */849 delim_hold = *src; 850 *src = '\0'; /* temporary */ 897 851 var = getenv(dst + 1 + num_skip_chars); 898 *src =delim_hold;852 *src = delim_hold; 899 853 src += num_skip_chars; 900 854 } 901 855 if (var == NULL) { 902 856 /* Seems we got an un-expandable variable. So delete it. */ 903 var = "";857 var = (char*)""; 904 858 } 905 859 { … … 932 886 char *return_command = NULL; 933 887 char *src, *buf; 934 int argc_l = 0;935 int done = 0;888 int argc_l; 889 int flag; 936 890 int argv_alloced; 937 int saw_quote = 0;938 891 char quote = '\0'; 939 892 struct child_prog *prog; 940 #if def CONFIG_LASH_PIPE_N_REDIRECTS893 #if ENABLE_LASH_PIPE_N_REDIRECTS 941 894 int i; 942 895 char *chptr; … … 944 897 945 898 /* skip leading white space */ 946 while (**command_ptr && isspace(**command_ptr)) 947 (*command_ptr)++; 899 *command_ptr = skip_whitespace(*command_ptr); 948 900 949 901 /* this handles empty lines or leading '#' characters */ 950 902 if (!**command_ptr || (**command_ptr == '#')) { 951 job->num_progs =0;903 job->num_progs = 0; 952 904 return 0; 953 905 } … … 971 923 prog->is_stopped = 0; 972 924 prog->family = job; 973 #if def CONFIG_LASH_PIPE_N_REDIRECTS925 #if ENABLE_LASH_PIPE_N_REDIRECTS 974 926 prog->redirects = NULL; 975 927 #endif … … 979 931 prog->argv[0] = job->cmdbuf; 980 932 933 flag = argc_l = 0; 981 934 buf = command; 982 935 src = *command_ptr; 983 while (*src && ! done) {936 while (*src && !(flag & LASH_OPT_DONE)) { 984 937 if (quote == *src) { 985 938 quote = '\0'; … … 1002 955 *buf++ = *src; 1003 956 } else if (isspace(*src)) { 1004 if (*prog->argv[argc_l] || saw_quote) {957 if (*prog->argv[argc_l] || (flag & LASH_OPT_SAW_QUOTE)) { 1005 958 buf++, argc_l++; 1006 959 /* +1 here leaves room for the NULL which ends argv */ … … 1008 961 argv_alloced += 5; 1009 962 prog->argv = xrealloc(prog->argv, 1010 sizeof(*prog->argv) * 1011 argv_alloced); 963 sizeof(*prog->argv) * argv_alloced); 1012 964 } 1013 965 prog->argv[argc_l] = buf; 1014 saw_quote = 0;966 flag ^= LASH_OPT_SAW_QUOTE; 1015 967 } 1016 968 } else … … 1019 971 case '\'': 1020 972 quote = *src; 1021 saw_quote = 1;973 flag |= LASH_OPT_SAW_QUOTE; 1022 974 break; 1023 975 … … 1026 978 *buf++ = *src; 1027 979 else 1028 done = 1;980 flag |= LASH_OPT_DONE; 1029 981 break; 1030 982 1031 #if def CONFIG_LASH_PIPE_N_REDIRECTS983 #if ENABLE_LASH_PIPE_N_REDIRECTS 1032 984 case '>': /* redirects */ 1033 985 case '<': 1034 986 i = prog->num_redirects++; 1035 987 prog->redirects = xrealloc(prog->redirects, 1036 sizeof(*prog->redirects) * 1037 (i + 1)); 988 sizeof(*prog->redirects) * (i + 1)); 1038 989 1039 990 prog->redirects[i].fd = -1; … … 1069 1020 /* This isn't POSIX sh compliant. Oh well. */ 1070 1021 chptr = src; 1071 while (isspace(*chptr)) 1072 chptr++; 1022 chptr = skip_whitespace(chptr); 1073 1023 1074 1024 if (!*chptr) { 1075 1025 bb_error_msg("file name expected after %c", *(src-1)); 1076 1026 free_job(job); 1077 job->num_progs =0;1027 job->num_progs = 0; 1078 1028 return 1; 1079 1029 } … … 1089 1039 case '|': /* pipe */ 1090 1040 /* finish this command */ 1091 if (*prog->argv[argc_l] || saw_quote)1041 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) 1092 1042 argc_l++; 1093 1043 if (!argc_l) { 1094 bb_error_msg("empty command in pipe"); 1095 free_job(job); 1096 job->num_progs=0; 1097 return 1; 1044 goto empty_command_in_pipe; 1098 1045 } 1099 1046 prog->argv[argc_l] = NULL; … … 1102 1049 job->num_progs++; 1103 1050 job->progs = xrealloc(job->progs, 1104 1051 sizeof(*job->progs) * job->num_progs); 1105 1052 prog = job->progs + (job->num_progs - 1); 1106 1053 prog->num_redirects = 0; … … 1115 1062 1116 1063 src++; 1117 while (*src && isspace(*src)) 1118 src++; 1064 src = skip_whitespace(src); 1119 1065 1120 1066 if (!*src) { 1067 empty_command_in_pipe: 1121 1068 bb_error_msg("empty command in pipe"); 1122 1069 free_job(job); 1123 job->num_progs =0;1070 job->num_progs = 0; 1124 1071 return 1; 1125 1072 } … … 1129 1076 #endif 1130 1077 1131 #if def CONFIG_LASH_JOB_CONTROL1078 #if ENABLE_LASH_JOB_CONTROL 1132 1079 case '&': /* background */ 1133 1080 *inbg = 1; 1081 /* fallthrough */ 1134 1082 #endif 1135 1083 case ';': /* multiple commands */ 1136 done = 1;1084 flag |= LASH_OPT_DONE; 1137 1085 return_command = *command_ptr + (src - *command_ptr) + 1; 1138 1086 break; … … 1155 1103 } 1156 1104 1157 if (*prog->argv[argc_l] || saw_quote) {1105 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) { 1158 1106 argc_l++; 1159 1107 } … … 1165 1113 1166 1114 if (!return_command) { 1167 job->text = bb_xstrdup(*command_ptr);1115 job->text = xstrdup(*command_ptr); 1168 1116 } else { 1169 1117 /* This leaves any trailing spaces, which is a bit sloppy */ 1170 job->text = bb_xstrndup(*command_ptr, return_command - *command_ptr);1118 job->text = xstrndup(*command_ptr, return_command - *command_ptr); 1171 1119 } 1172 1120 … … 1180 1128 static int pseudo_exec(struct child_prog *child) 1181 1129 { 1182 struct built_in_command *x;1130 const struct built_in_command *x; 1183 1131 1184 1132 /* Check if the command matches any of the non-forking builtins. … … 1187 1135 * if this is one of those cases. 1188 1136 */ 1189 for (x = bltins; x->cmd; x++) { 1190 if (strcmp(child->argv[0], x->cmd) == 0 ) { 1137 /* Check if the command matches any of the forking builtins. */ 1138 for (x = bltins; x <= &VEC_LAST(bltins); x++) { 1139 if (strcmp(child->argv[0], x->cmd) == 0) { 1191 1140 _exit(x->function(child)); 1192 1141 } 1193 1142 } 1194 1143 1195 /* Check if the command matches any of the forking builtins. */1196 for (x = bltins_forking; x->cmd; x++) {1197 if (strcmp(child->argv[0], x->cmd) == 0) {1198 bb_applet_name=x->cmd;1199 _exit (x->function(child));1200 }1201 }1202 1144 1203 1145 /* Check if the command matches any busybox internal … … 1212 1154 * /bin/foo is a symlink to busybox. 1213 1155 */ 1214 1215 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) { 1216 char **argv_l = child->argv; 1217 int argc_l; 1218 1219 for(argc_l=0; *argv_l; argv_l++, argc_l++); 1220 optind = 1; 1221 run_applet_by_name(child->argv[0], argc_l, child->argv); 1156 if (ENABLE_FEATURE_SH_STANDALONE) { 1157 run_applet_and_exit(child->argv[0], child->argv); 1222 1158 } 1223 1159 … … 1233 1169 { 1234 1170 struct job *thejob; 1235 struct jobset *j_list =newjob->job_list;1171 struct jobset *j_list = newjob->job_list; 1236 1172 1237 1173 /* find the ID for thejob to use */ … … 1255 1191 thejob->stopped_progs = 0; 1256 1192 1257 #if def CONFIG_LASH_JOB_CONTROL1193 #if ENABLE_LASH_JOB_CONTROL 1258 1194 if (inbg) { 1259 1195 /* we don't wait for background thejobs to return -- append it … … 1262 1198 newjob->progs[newjob->num_progs - 1].pid); 1263 1199 last_jobid = newjob->jobid; 1264 last_bg_pid =newjob->progs[newjob->num_progs - 1].pid;1200 last_bg_pid = newjob->progs[newjob->num_progs - 1].pid; 1265 1201 } else { 1266 1202 newjob->job_list->fg = thejob; … … 1279 1215 int nextin, nextout; 1280 1216 int pipefds[2]; /* pipefd[0] is for reading */ 1281 struct built_in_command *x;1217 const struct built_in_command *x; 1282 1218 struct child_prog *child; 1283 1219 1284 nextin = 0 , nextout = 1;1220 nextin = 0; 1285 1221 for (i = 0; i < newjob->num_progs; i++) { 1286 child = & (newjob->progs[i]); 1287 1222 child = &(newjob->progs[i]); 1223 1224 nextout = 1; 1288 1225 if ((i + 1) < newjob->num_progs) { 1289 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");1226 xpipe(pipefds); 1290 1227 nextout = pipefds[1]; 1291 } else { 1292 if (outpipe[1]!=-1) { 1293 nextout = outpipe[1]; 1294 } else { 1295 nextout = 1; 1296 } 1297 } 1298 1228 } else if (outpipe[1] != -1) { 1229 nextout = outpipe[1]; 1230 } 1299 1231 1300 1232 /* Check if the command matches any non-forking builtins, … … 1305 1237 */ 1306 1238 if (newjob->num_progs == 1) { 1239 int rcode; 1240 int squirrel[] = {-1, -1, -1}; 1241 1307 1242 /* Check if the command sets an environment variable. */ 1308 1243 if (strchr(child->argv[0], '=') != NULL) { … … 1311 1246 } 1312 1247 1313 for (x = bltins; x->cmd; x++) { 1314 if (strcmp(child->argv[0], x->cmd) == 0 ) { 1315 int rcode; 1316 int squirrel[] = {-1, -1, -1}; 1248 for (x = bltins; x <= &VEC_LAST(bltins); x++) { 1249 if (strcmp(child->argv[0], x->cmd) == 0) { 1317 1250 setup_redirects(child, squirrel); 1318 1251 rcode = x->function(child); … … 1321 1254 } 1322 1255 } 1323 } 1324 1325 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__) 1326 if (!(child->pid = fork())) 1256 #if ENABLE_FEATURE_SH_STANDALONE 1257 { 1258 const struct bb_applet *a = find_applet_by_name(child->argv[i]); 1259 if (a && a->nofork) { 1260 setup_redirects(child, squirrel); 1261 rcode = run_nofork_applet(a, child->argv + i); 1262 restore_redirects(squirrel); 1263 return rcode; 1264 } 1265 } 1266 #endif 1267 } 1268 1269 #if BB_MMU 1270 child->pid = fork(); 1327 1271 #else 1328 if (!(child->pid = vfork()))1329 #endif 1330 {1272 child->pid = vfork(); 1273 #endif 1274 if (!child->pid) { 1331 1275 /* Set the handling for job control signals back to the default. */ 1332 1276 signal(SIGINT, SIG_DFL); … … 1337 1281 signal(SIGCHLD, SIG_DFL); 1338 1282 1339 // Close all open filehandles. 1340 while(close_me_list) close((long)llist_pop(&close_me_list)); 1341 1342 if (outpipe[1]!=-1) { 1283 /* Close all open filehandles. */ 1284 while (close_me_list) 1285 close((long)llist_pop(&close_me_list)); 1286 1287 if (outpipe[1] != -1) { 1343 1288 close(outpipe[0]); 1344 1289 } … … 1360 1305 pseudo_exec(child); 1361 1306 } 1362 if (outpipe[1] !=-1) {1307 if (outpipe[1] != -1) { 1363 1308 close(outpipe[1]); 1364 1309 } … … 1392 1337 int inbg = 0; 1393 1338 int status; 1394 #if def CONFIG_LASH_JOB_CONTROL1339 #if ENABLE_LASH_JOB_CONTROL 1395 1340 pid_t parent_pgrp; 1396 1341 /* save current owner of TTY so we can restore it on exit */ … … 1410 1355 1411 1356 if (!next_command) { 1412 if (get_command (input, command))1357 if (get_command_bufsiz(input, command)) 1413 1358 break; 1414 1359 next_command = command; 1415 1360 } 1416 1361 1417 if (! 1362 if (!expand_arguments(next_command)) { 1418 1363 free(command); 1419 1364 command = xzalloc(BUFSIZ); … … 1424 1369 if (!parse_command(&next_command, &newjob, &inbg) && 1425 1370 newjob.num_progs) { 1426 int pipefds[2] = { -1,-1};1427 debug_printf( 1371 int pipefds[2] = { -1, -1 }; 1372 debug_printf("job=%p fed to run_command by busy_loop()'\n", 1428 1373 &newjob); 1429 1374 run_command(&newjob, inbg, pipefds); … … 1431 1376 else { 1432 1377 free(command); 1433 command = (char *)xzalloc(BUFSIZ);1378 command = xzalloc(BUFSIZ); 1434 1379 next_command = NULL; 1435 1380 } … … 1440 1385 job_list.fg->progs[i].is_stopped == 1) i++; 1441 1386 1442 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED) <0) {1387 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED) < 0) { 1443 1388 if (errno != ECHILD) { 1444 bb_perror_msg_and_die("waitpid(%d)", job_list.fg->progs[i].pid);1389 bb_perror_msg_and_die("waitpid(%d)", job_list.fg->progs[i].pid); 1445 1390 } 1446 1391 } … … 1451 1396 job_list.fg->progs[i].pid = 0; 1452 1397 1453 last_return_code =WEXITSTATUS(status);1398 last_return_code = WEXITSTATUS(status); 1454 1399 1455 1400 if (!job_list.fg->running_progs) { … … 1459 1404 } 1460 1405 } 1461 #if def CONFIG_LASH_JOB_CONTROL1406 #if ENABLE_LASH_JOB_CONTROL 1462 1407 else { 1463 1408 /* the child was stopped */ … … 1483 1428 free(command); 1484 1429 1485 #if def CONFIG_LASH_JOB_CONTROL1430 #if ENABLE_LASH_JOB_CONTROL 1486 1431 /* return controlling TTY back to parent process group before exiting */ 1487 1432 if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY) … … 1496 1441 } 1497 1442 1498 #if def CONFIG_FEATURE_CLEAN_UP1443 #if ENABLE_FEATURE_CLEAN_UP 1499 1444 static void free_memory(void) 1500 1445 { 1501 if (cwd && cwd!=bb_msg_unknown) { 1502 free((char*)cwd); 1503 } 1504 if (local_pending_command) 1505 free(local_pending_command); 1446 free(cwd); 1506 1447 1507 1448 if (job_list.fg && !job_list.fg->running_progs) { … … 1513 1454 #endif 1514 1455 1515 #if def CONFIG_LASH_JOB_CONTROL1456 #if ENABLE_LASH_JOB_CONTROL 1516 1457 /* Make sure we have a controlling tty. If we get started under a job 1517 1458 * aware app (like bash for example), make sure we are now in charge so … … 1523 1464 1524 1465 /* Loop until we are in the foreground. */ 1525 while ((status = tcgetpgrp (shell_terminal)) >= 0) { 1526 if (status == (shell_pgrp = getpgrp ())) { 1466 while ((status = tcgetpgrp(shell_terminal)) >= 0) { 1467 shell_pgrp = getpgrp(); 1468 if (status == shell_pgrp) { 1527 1469 break; 1528 1470 } 1529 kill 1471 kill(- shell_pgrp, SIGTTIN); 1530 1472 } 1531 1473 … … 1540 1482 /* Put ourselves in our own process group. */ 1541 1483 setsid(); 1542 shell_pgrp = getpid 1484 shell_pgrp = getpid(); 1543 1485 setpgid(shell_pgrp, shell_pgrp); 1544 1486 … … 1552 1494 #endif 1553 1495 1496 int lash_main(int argc_l, char **argv_l); 1554 1497 int lash_main(int argc_l, char **argv_l) 1555 1498 { 1556 int opt, interactive=FALSE;1499 unsigned opt; 1557 1500 FILE *input = stdin; 1558 1501 argc = argc_l; 1559 1502 argv = argv_l; 1560 1503 1504 #if ENABLE_FEATURE_EDITING 1505 line_input_state = new_line_input_t(FOR_SHELL); 1506 #endif 1507 1561 1508 /* These variables need re-initializing when recursing */ 1562 1509 last_jobid = 0; 1563 local_pending_command = NULL;1564 1510 close_me_list = NULL; 1565 1511 job_list.head = NULL; 1566 1512 job_list.fg = NULL; 1567 last_return_code =1;1513 last_return_code = 1; 1568 1514 1569 1515 if (argv[0] && argv[0][0] == '-') { … … 1574 1520 /* Now run the file */ 1575 1521 busy_loop(prof_input); 1576 fclose (prof_input);1522 fclose_if_not_stdin(prof_input); 1577 1523 llist_pop(&close_me_list); 1578 1524 } 1579 1525 } 1580 1526 1581 while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) { 1582 switch (opt) { 1583 case 'c': 1584 input = NULL; 1585 if (local_pending_command != 0) 1586 bb_error_msg_and_die("multiple -c arguments"); 1587 local_pending_command = bb_xstrdup(argv[optind]); 1588 optind++; 1589 argv = argv+optind; 1590 break; 1591 case 'i': 1592 interactive++; 1593 break; 1594 default: 1595 bb_show_usage(); 1596 } 1527 opt = getopt32(argv_l, "+ic:", &local_pending_command); 1528 #define LASH_OPT_i (1<<0) 1529 #define LASH_OPT_c (1<<1) 1530 if (opt & LASH_OPT_c) { 1531 input = NULL; 1532 optind++; 1533 argv += optind; 1597 1534 } 1598 1535 /* A shell is interactive if the `-i' flag was given, or if all of … … 1603 1540 * standard output is a terminal 1604 1541 * Refer to Posix.2, the description of the `sh' utility. */ 1605 if (argv[optind] ==NULL && input==stdin &&1606 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))1607 {1608 interactive++;1542 if (argv[optind] == NULL && input == stdin 1543 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 1544 ) { 1545 opt |= LASH_OPT_i; 1609 1546 } 1610 1547 setup_job_control(); 1611 if ( interactive) {1548 if (opt & LASH_OPT_i) { 1612 1549 /* Looks like they want an interactive shell */ 1613 1550 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { 1614 printf( "\n\n%s Built-in shell (lash)\n", BB_BANNER); 1615 printf( "Enter 'help' for a list of built-in commands.\n\n"); 1551 printf("\n\n%s built-in shell (lash)\n" 1552 "Enter 'help' for a list of built-in commands.\n\n", 1553 bb_banner); 1616 1554 } 1617 1555 } else if (!local_pending_command && argv[optind]) { 1618 1556 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1619 input = bb_xfopen(argv[optind], "r");1557 input = xfopen(argv[optind], "r"); 1620 1558 /* be lazy, never mark this closed */ 1621 1559 llist_add_to(&close_me_list, (void *)(long)fileno(input)); … … 1623 1561 1624 1562 /* initialize the cwd -- this is never freed...*/ 1625 cwd = xgetcwd(0); 1626 if (!cwd) 1627 cwd = bb_msg_unknown; 1563 update_cwd(); 1628 1564 1629 1565 if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory); 1630 1566 1631 if (ENABLE_FEATURE_ COMMAND_EDITING) cmdedit_set_initial_prompt();1567 if (ENABLE_FEATURE_EDITING) cmdedit_set_initial_prompt(); 1632 1568 else PS1 = NULL; 1633 1569 1634 return (busy_loop(input));1635 } 1570 return busy_loop(input); 1571 } -
branches/stable/mindi-busybox/shell/msh.c
r902 r1770 11 11 * Erik Andersen <andersen@codepoet.org> 12 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 * 27 * Original copyright notice is retained at the end of this file. 28 */ 29 30 #include "busybox.h" 31 #include <ctype.h> 32 #include <dirent.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <limits.h> 13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 14 */ 15 16 #include <sys/times.h> 36 17 #include <setjmp.h> 37 #include <signal.h> 38 #include <stddef.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <time.h> 43 #include <unistd.h> 44 #include <sys/stat.h> 45 #include <sys/times.h> 46 #include <sys/types.h> 47 #include <sys/wait.h> 48 49 #include "cmdedit.h" 50 51 52 /* Conditional use of "register" keyword */ 53 #define REGISTER register 54 18 19 #ifdef STANDALONE 20 # ifndef _GNU_SOURCE 21 # define _GNU_SOURCE 22 # endif 23 # include <sys/types.h> 24 # include <sys/stat.h> 25 # include <sys/wait.h> 26 # include <signal.h> 27 # include <stdio.h> 28 # include <stdlib.h> 29 # include <unistd.h> 30 # include <string.h> 31 # include <errno.h> 32 # include <dirent.h> 33 # include <fcntl.h> 34 # include <ctype.h> 35 # include <assert.h> 36 # define bb_dev_null "/dev/null" 37 # define DEFAULT_SHELL "/proc/self/exe" 38 # define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe" 39 # define bb_banner "busybox standalone" 40 # define ENABLE_FEATURE_SH_STANDALONE 0 41 # define bb_msg_memory_exhausted "memory exhausted" 42 # define xmalloc(size) malloc(size) 43 # define msh_main(argc,argv) main(argc,argv) 44 # define safe_read(fd,buf,count) read(fd,buf,count) 45 # define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1]) 46 # define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1]) 47 # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) 48 static char *find_applet_by_name(const char *applet) 49 { 50 return NULL; 51 } 52 static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) 53 { 54 unsigned i, out, res; 55 assert(sizeof(unsigned) == 4); 56 if (buflen) { 57 out = 0; 58 for (i = 1000000000; i; i /= 10) { 59 res = n / i; 60 if (res || out || i == 1) { 61 if (!--buflen) break; 62 out++; 63 n -= res*i; 64 *buf++ = '0' + res; 65 } 66 } 67 } 68 return buf; 69 } 70 static char *itoa_to_buf(int n, char *buf, unsigned buflen) 71 { 72 if (buflen && n < 0) { 73 n = -n; 74 *buf++ = '-'; 75 buflen--; 76 } 77 return utoa_to_buf((unsigned)n, buf, buflen); 78 } 79 static char local_buf[12]; 80 static char *itoa(int n) 81 { 82 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; 83 return local_buf; 84 } 85 #else 86 # include "busybox.h" 87 extern char **environ; 88 #endif 55 89 56 90 /*#define MSHDEBUG 1*/ … … 59 93 int mshdbg = MSHDEBUG; 60 94 61 #define DBGPRINTF(x) if (mshdbg>0)printf x62 #define DBGPRINTF0(x) if (mshdbg>0)printf x63 #define DBGPRINTF1(x) if (mshdbg>1)printf x64 #define DBGPRINTF2(x) if (mshdbg>2)printf x65 #define DBGPRINTF3(x) if (mshdbg>3)printf x66 #define DBGPRINTF4(x) if (mshdbg>4)printf x67 #define DBGPRINTF5(x) if (mshdbg>5)printf x68 #define DBGPRINTF6(x) if (mshdbg>6)printf x69 #define DBGPRINTF7(x) if (mshdbg>7)printf x70 #define DBGPRINTF8(x) if (mshdbg>8)printf x71 #define DBGPRINTF9(x) if (mshdbg>9)printf x95 #define DBGPRINTF(x) if (mshdbg>0) printf x 96 #define DBGPRINTF0(x) if (mshdbg>0) printf x 97 #define DBGPRINTF1(x) if (mshdbg>1) printf x 98 #define DBGPRINTF2(x) if (mshdbg>2) printf x 99 #define DBGPRINTF3(x) if (mshdbg>3) printf x 100 #define DBGPRINTF4(x) if (mshdbg>4) printf x 101 #define DBGPRINTF5(x) if (mshdbg>5) printf x 102 #define DBGPRINTF6(x) if (mshdbg>6) printf x 103 #define DBGPRINTF7(x) if (mshdbg>7) printf x 104 #define DBGPRINTF8(x) if (mshdbg>8) printf x 105 #define DBGPRINTF9(x) if (mshdbg>9) printf x 72 106 73 107 int mshdbg_rc = 0; 74 108 75 #define RCPRINTF(x) if(mshdbg_rc)printf x109 #define RCPRINTF(x) if (mshdbg_rc) printf x 76 110 77 111 #else 78 112 79 113 #define DBGPRINTF(x) 80 #define DBGPRINTF0(x) 81 #define DBGPRINTF1(x) 82 #define DBGPRINTF2(x) 83 #define DBGPRINTF3(x) 84 #define DBGPRINTF4(x) 85 #define DBGPRINTF5(x) 86 #define DBGPRINTF6(x) 87 #define DBGPRINTF7(x) 88 #define DBGPRINTF8(x) 89 #define DBGPRINTF9(x) 90 91 #define RCPRINTF(x) 114 #define DBGPRINTF0(x) ((void)0) 115 #define DBGPRINTF1(x) ((void)0) 116 #define DBGPRINTF2(x) ((void)0) 117 #define DBGPRINTF3(x) ((void)0) 118 #define DBGPRINTF4(x) ((void)0) 119 #define DBGPRINTF5(x) ((void)0) 120 #define DBGPRINTF6(x) ((void)0) 121 #define DBGPRINTF7(x) ((void)0) 122 #define DBGPRINTF8(x) ((void)0) 123 #define DBGPRINTF9(x) ((void)0) 124 125 #define RCPRINTF(x) ((void)0) 92 126 93 127 #endif /* MSHDEBUG */ 94 128 95 129 96 #if def CONFIG_FEATURE_SH_FANCY_PROMPT130 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT 97 131 # define DEFAULT_ROOT_PROMPT "\\u:\\w> " 98 132 # define DEFAULT_USER_PROMPT "\\u:\\w$ " … … 119 153 * values returned by wait 120 154 */ 121 #define WAITSIG(s) ((s) &0177)122 #define WAITVAL(s) (((s) >>8)&0377)123 #define WAITCORE(s) (((s) &0200)!=0)155 #define WAITSIG(s) ((s) & 0177) 156 #define WAITVAL(s) (((s) >> 8) & 0377) 157 #define WAITCORE(s) (((s) & 0200) != 0) 124 158 125 159 /* … … 131 165 * shell components 132 166 */ 133 134 #define QUOTE 0200135 136 167 #define NOBLOCK ((struct op *)NULL) 137 168 #define NOWORD ((char *)NULL) 138 169 #define NOWORDS ((char **)NULL) 139 170 #define NOPIPE ((int *)NULL) 171 172 /* 173 * redirection 174 */ 175 struct ioword { 176 short io_unit; /* unit affected */ 177 short io_flag; /* action (below) */ 178 char *io_name; /* file name */ 179 }; 180 181 #define IOREAD 1 /* < */ 182 #define IOHERE 2 /* << (here file) */ 183 #define IOWRITE 4 /* > */ 184 #define IOCAT 8 /* >> */ 185 #define IOXHERE 16 /* ${}, ` in << */ 186 #define IODUP 32 /* >&digit */ 187 #define IOCLOSE 64 /* >&- */ 188 189 #define IODEFAULT (-1) /* token for default IO unit */ 190 140 191 141 192 /* … … 173 224 /* Strings for names to make debug easier */ 174 225 #ifdef MSHDEBUG 175 static c har *T_CMD_NAMES[] = {226 static const char *const T_CMD_NAMES[] = { 176 227 "PLACEHOLDER", 177 228 "TCOM", … … 198 249 * actions determining the environment of a process 199 250 */ 200 #define BIT(i) (1<<(i)) 201 #define FEXEC BIT(0) /* execute without forking */ 202 203 #if 0 /* Original value */ 204 #define AREASIZE (65000) 205 #else 206 #define AREASIZE (90000) 207 #endif 251 #define FEXEC 1 /* execute without forking */ 252 253 #define AREASIZE (90000) 208 254 209 255 /* 210 256 * flags to control evaluation of words 211 257 */ 212 #define DOSUB 1 /* interpret $, `, and quotes */ 213 #define DOBLANK 2 /* perform blank interpretation */ 214 #define DOGLOB 4 /* interpret [?* */ 215 #define DOKEY 8 /* move words with `=' to 2nd arg. list */ 216 #define DOTRIM 16 /* trim resulting string */ 217 218 #define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) 219 220 221 /* PROTOTYPES */ 222 static int newfile(char *s); 223 static char *findeq(char *cp); 224 static char *cclass(char *p, int sub); 225 static void initarea(void); 226 extern int msh_main(int argc, char **argv); 258 #define DOSUB 1 /* interpret $, `, and quotes */ 259 #define DOBLANK 2 /* perform blank interpretation */ 260 #define DOGLOB 4 /* interpret [?* */ 261 #define DOKEY 8 /* move words with `=' to 2nd arg. list */ 262 #define DOTRIM 16 /* trim resulting string */ 263 264 #define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) 227 265 228 266 … … 232 270 }; 233 271 234 235 /*236 * redirection237 */238 struct ioword {239 short io_unit; /* unit affected */240 short io_flag; /* action (below) */241 char *io_name; /* file name */242 };243 244 #define IOREAD 1 /* < */245 #define IOHERE 2 /* << (here file) */246 #define IOWRITE 4 /* > */247 #define IOCAT 8 /* >> */248 #define IOXHERE 16 /* ${}, ` in << */249 #define IODUP 32 /* >&digit */250 #define IOCLOSE 64 /* >&- */251 252 #define IODEFAULT (-1) /* token for default IO unit */253 254 255 256 /*257 * parsing & execution environment258 */259 static struct env {260 char *linep;261 struct io *iobase;262 struct io *iop;263 xint *errpt; /* void * */264 int iofd;265 struct env *oenv;266 } e;267 272 268 273 /* … … 276 281 * -u: unset variables net diagnostic 277 282 */ 278 static char *flag; 279 280 static char *null; /* null value for variable */ 281 static int intr; /* interrupt pending */ 282 283 static char *trap[_NSIG + 1]; 284 static char ourtrap[_NSIG + 1]; 283 static char flags['z' - 'a' + 1] ALIGN1; 284 /* this looks weird, but is OK ... we index FLAG with 'a'...'z' */ 285 #define FLAG (flags - 'a') 286 287 /* moved to G: static char *trap[_NSIG + 1]; */ 288 /* moved to G: static char ourtrap[_NSIG + 1]; */ 285 289 static int trapset; /* trap pending */ 286 290 287 static int heedint; /* heed interrupt signals */288 289 291 static int yynerrs; /* yacc */ 290 292 291 static char line[LINELIM]; 292 static char *elinep; 293 /* moved to G: static char line[LINELIM]; */ 294 295 #if ENABLE_FEATURE_EDITING 296 static char *current_prompt; 297 static line_input_t *line_input_state; 298 #endif 293 299 294 300 … … 296 302 * other functions 297 303 */ 298 static int (*inbuilt(char *s)) (struct op *); 299 300 static char *rexecve(char *c, char **v, char **envp); 301 static char *space(int n); 302 static char *strsave(char *s, int a); 304 static const char *rexecve(char *c, char **v, char **envp); 303 305 static char *evalstr(char *cp, int f); 304 306 static char *putn(int n); 305 static char *itoa(int n);306 307 static char *unquote(char *as); 307 static struct var *lookup(char *n);308 308 static int rlookup(char *n); 309 309 static struct wdblock *glob(char *cp, struct wdblock *wb); … … 319 319 static int newenv(int f); 320 320 static void quitenv(void); 321 static void err(char *s);322 static int anys(char *s1, char *s2);323 static int any(int c, char *s);324 321 static void next(int f); 325 322 static void setdash(void); 326 323 static void onecommand(void); 327 324 static void runtrap(int i); 328 static int gmatch(char *s, char *p);329 330 331 /*332 * error handling333 */334 static void leave(void); /* abort shell (or fail in subshell) */335 static void fail(void); /* fail but return to process next command */336 static void warn(char *s);337 static void sig(int i); /* default signal handler */338 339 325 340 326 341 327 /* -------- area stuff -------- */ 342 328 343 #define REGSIZEsizeof(struct region)344 #define GROWBY 345 /* #define SHRINKBY(64) */346 #undef 347 #define FREE 348 #define BUSY 349 #define ALIGN(sizeof(int)-1)329 #define REGSIZE sizeof(struct region) 330 #define GROWBY (256) 331 /* #define SHRINKBY (64) */ 332 #undef SHRINKBY 333 #define FREE (32767) 334 #define BUSY (0) 335 #define ALIGN (sizeof(int)-1) 350 336 351 337 … … 354 340 int area; 355 341 }; 356 357 342 358 343 … … 365 350 } YYSTYPE; 366 351 367 #define WORD256368 #define LOGAND257369 #define LOGOR258370 #define BREAK259371 #define IF260372 #define THEN261373 #define ELSE262374 #define ELIF263375 #define FI264376 #define CASE265377 #define ESAC266378 #define FOR267379 #define WHILE268380 #define UNTIL269381 #define DO270382 #define DONE271383 #define IN272352 #define WORD 256 353 #define LOGAND 257 354 #define LOGOR 258 355 #define BREAK 259 356 #define IF 260 357 #define THEN 261 358 #define ELSE 262 359 #define ELIF 263 360 #define FI 264 361 #define CASE 265 362 #define ESAC 266 363 #define FOR 267 364 #define WHILE 268 365 #define UNTIL 269 366 #define DO 270 367 #define DONE 271 368 #define IN 272 384 369 /* Added for "." file expansion */ 385 #define DOT273370 #define DOT 273 386 371 387 372 #define YYERRCODE 300 388 373 389 374 /* flags to yylex */ 390 #define CONTIN 01 /* skip new lines to complete command */ 391 392 #define SYNTAXERR zzerr() 375 #define CONTIN 01 /* skip new lines to complete command */ 393 376 394 377 static struct op *pipeline(int cf); … … 415 398 static struct ioword **copyio(void); 416 399 static struct ioword *io(int u, int f, char *cp); 417 static void zzerr(void);418 static void yyerror(char *s);419 400 static int yylex(int cf); 420 401 static int collect(int c, int c1); … … 438 419 439 420 static int yyparse(void); 440 static struct var *lookup(char *n);441 static void setval(struct var *vp, char *val);442 static void nameval(struct var *vp, char *val, char *name);443 static void export(struct var *vp);444 static void ronly(struct var *vp);445 static int isassign(char *s);446 static int checkname(char *cp);447 static int assign(char *s, int cf);448 static void putvlist(int f, int out);449 static int eqname(char *n1, char *n2);450 421 451 422 static int execute(struct op *t, int *pin, int *pout, int act); 423 424 425 #define AFID_NOBUF (~0) 426 #define AFID_ID 0 452 427 453 428 … … 455 430 /* io buffer */ 456 431 struct iobuf { 457 unsigned id; 458 char buf[512]; 459 char *bufp; 460 char *ebufp; 432 unsigned id; /* buffer id */ 433 char buf[512]; /* buffer */ 434 char *bufp; /* pointer into buffer */ 435 char *ebufp; /* pointer to end of buffer */ 461 436 }; 462 437 463 438 /* possible arguments to an IO function */ 464 439 struct ioarg { 465 c har *aword;440 const char *aword; 466 441 char **awordlist; 467 int afile; 468 unsigned afid; 469 long afpos; 470 struct iobuf *afbuf; 442 int afile; /* file descriptor */ 443 unsigned afid; /* buffer id */ 444 long afpos; /* file position */ 445 struct iobuf *afbuf; /* buffer for this file */ 471 446 }; 472 473 //static struct ioarg ioargstack[NPUSH];474 #define AFID_NOBUF (~0)475 #define AFID_ID 0476 447 477 448 /* an input generator's state */ … … 480 451 struct ioarg *argp; 481 452 int peekc; 482 char prev; 483 char nlcount; 484 char xchar; 485 char task; 453 char prev; /* previous character read by readc() */ 454 char nlcount; /* for `'s */ 455 char xchar; /* for `'s */ 456 char task; /* reason for pushed IO */ 486 457 }; 487 458 488 //static struct io iostack[NPUSH];489 459 #define XOTHER 0 /* none of the below */ 490 460 #define XDOLL 1 /* expanding ${} */ 491 461 #define XGRAVE 2 /* expanding `'s */ 492 #define XIO 3 462 #define XIO 3 /* file IO */ 493 463 494 464 /* in substitution */ 495 465 #define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL) 466 467 static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */ 468 /* moved to G: static struct ioarg ioargstack[NPUSH]; */ 469 static struct io iostack[NPUSH]; 470 /* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */ 471 /* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */ 472 static unsigned bufid = AFID_ID; /* buffer id counter */ 473 474 #define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) 496 475 497 476 … … 517 496 518 497 519 /*520 * IO functions521 */522 498 static int eofc(void); 523 499 static int readc(void); 524 500 static void unget(int c); 525 501 static void ioecho(char c); 526 static void prs(const char *s);527 static void prn(unsigned u);528 static void closef(int i);529 static void closeall(void);530 502 531 503 … … 534 506 */ 535 507 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *)); 508 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen))) 536 509 static int remap(int fd); 537 510 static int openpipe(int *pv); 538 511 static void closepipe(int *pv); 539 512 static struct io *setbase(struct io *ip); 540 541 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))542 #define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))543 513 544 514 /* -------- word.h -------- */ … … 557 527 static char **getwords(struct wdblock *wb); 558 528 559 /* -------- area.h -------- */560 561 /*562 * storage allocation563 */564 static char *getcell(unsigned nbytes);565 static void garbage(void);566 static void setarea(char *cp, int a);567 static int getarea(char *cp);568 static void freearea(int a);569 static void freecell(char *cp);570 static int areanum; /* current allocation area */571 572 #define NEW(type) (type *)getcell(sizeof(type))573 #define DELETE(obj) freecell((char *)obj)574 575 576 529 /* -------- misc stuff -------- */ 577 530 578 531 static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); 579 532 static int iosetup(struct ioword *iop, int pipein, int pipeout); 580 static void echo(char **wp);581 static struct op **find1case(struct op *t, char *w);582 static struct op *findcase(struct op *t, char *w);583 533 static void brkset(struct brkcon *bc); 584 534 static int dolabel(struct op *t); … … 608 558 static void varput(char *s, int out); 609 559 static int dotimes(struct op *t); 610 static int expand(c har *cp, struct wdblock **wbp, int f);560 static int expand(const char *cp, struct wdblock **wbp, int f); 611 561 static char *blank(int f); 612 562 static int dollar(int quoted); … … 616 566 static int anyspcl(struct wdblock *wb); 617 567 static int xstrcmp(char *p1, char *p2); 618 static void glob0(char *a0, unsigned inta1, int a2,568 static void glob0(char *a0, unsigned a1, int a2, 619 569 int (*a3) (char *, char *)); 620 static void glob1(char *base, char *lim);621 static void glob2(char *i, char *j);622 static void glob3(char *i, char *j, char *k);623 570 static void readhere(char **name, char *s, int ec); 624 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));625 571 static int xxchar(struct ioarg *ap); 626 572 … … 632 578 }; 633 579 634 static const char * 580 static const char *const signame[] = { 635 581 "Signal 0", 636 582 "Hangup", 637 (char *) NULL,/* interrupt */583 NULL, /* interrupt */ 638 584 "Quit", 639 585 "Illegal instruction", … … 646 592 "SIGSEGV", 647 593 "SIGUSR2", 648 (char *) NULL,/* broken pipe */594 NULL, /* broken pipe */ 649 595 "Alarm clock", 650 "Terminated" ,596 "Terminated" 651 597 }; 652 598 653 #define NSIGNAL (sizeof(signame)/sizeof(signame[0]))654 599 655 600 struct res { … … 658 603 }; 659 604 static const struct res restab[] = { 660 { "for", FOR},661 { "case", CASE},662 { "esac", ESAC},663 { "while", WHILE},664 { "do", DO},665 { "done", DONE},666 { "if", IF},667 { "in", IN},668 { "then", THEN},669 { "else", ELSE},670 { "elif", ELIF},671 { "until", UNTIL},672 { "fi", FI},673 { ";;", BREAK},674 { "||", LOGOR},675 { "&&", LOGAND},676 { "{", '{'},677 { "}", '}'},678 { ".", DOT},679 { 0, 0},605 { "for" , FOR }, 606 { "case" , CASE }, 607 { "esac" , ESAC }, 608 { "while", WHILE }, 609 { "do" , DO }, 610 { "done" , DONE }, 611 { "if" , IF }, 612 { "in" , IN }, 613 { "then" , THEN }, 614 { "else" , ELSE }, 615 { "elif" , ELIF }, 616 { "until", UNTIL }, 617 { "fi" , FI }, 618 { ";;" , BREAK }, 619 { "||" , LOGOR }, 620 { "&&" , LOGAND }, 621 { "{" , '{' }, 622 { "}" , '}' }, 623 { "." , DOT }, 624 { NULL , 0 }, 680 625 }; 681 682 626 683 627 struct builtincmd { 684 628 const char *name; 685 int (*builtinfunc) (struct op *t);629 int (*builtinfunc)(struct op *t); 686 630 }; 687 631 static const struct builtincmd builtincmds[] = { 688 { ".", dodot},689 { ":", dolabel},690 { "break", dobreak},691 { "cd", dochdir},692 { "continue", docontinue},693 { "eval", doeval},694 { "exec", doexec},695 { "exit", doexit},696 { "export", doexport},697 { "help", dohelp},698 { "login", dologin},699 { "newgrp", dologin},700 { "read", doread},701 { "readonly", doreadonly},702 { "set", doset},703 { "shift", doshift},704 { "times", dotimes},705 { "trap", dotrap},706 { "umask", doumask},707 { "wait", dowait},708 { 0, 0}632 { "." , dodot }, 633 { ":" , dolabel }, 634 { "break" , dobreak }, 635 { "cd" , dochdir }, 636 { "continue", docontinue }, 637 { "eval" , doeval }, 638 { "exec" , doexec }, 639 { "exit" , doexit }, 640 { "export" , doexport }, 641 { "help" , dohelp }, 642 { "login" , dologin }, 643 { "newgrp" , dologin }, 644 { "read" , doread }, 645 { "readonly", doreadonly }, 646 { "set" , doset }, 647 { "shift" , doshift }, 648 { "times" , dotimes }, 649 { "trap" , dotrap }, 650 { "umask" , doumask }, 651 { "wait" , dowait }, 652 { NULL , NULL }, 709 653 }; 710 654 … … 712 656 static struct op *dowholefile(int, int); 713 657 658 714 659 /* Globals */ 715 extern char **environ; /* environment pointer */716 717 660 static char **dolv; 718 661 static int dolc; … … 729 672 static struct wdblock *wdlist; 730 673 static struct wdblock *iolist; 731 static char *trap[_NSIG + 1];732 static char ourtrap[_NSIG + 1];733 static int trapset; /* trap pending */734 static int yynerrs; /* yacc */735 static char line[LINELIM];736 674 737 675 #ifdef MSHDEBUG … … 746 684 static struct var *ifs; /* field separators */ 747 685 748 static int areanum; 749 static int intr; 686 static int areanum; /* current allocation area */ 687 static int intr; /* interrupt pending */ 750 688 static int inparse; 751 static char flags['z' - 'a' + 1]; 752 static char *flag = flags - 'a'; 753 static char *null = ""; 754 static int heedint = 1; 755 static void (*qflag) (int) = SIG_IGN; 689 static char *null = (char*)""; /* null value for variable */ 690 static int heedint = 1; /* heed interrupt signals */ 691 static void (*qflag)(int) = SIG_IGN; 756 692 static int startl; 757 693 static int peeksym; … … 759 695 static int iounit = IODEFAULT; 760 696 static YYSTYPE yylval; 761 static char *elinep = line + sizeof(line) - 5; 762 763 static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */ 764 static struct ioarg ioargstack[NPUSH]; 765 static struct io iostack[NPUSH]; 766 static struct iobuf sharedbuf = { AFID_NOBUF }; 767 static struct iobuf mainbuf = { AFID_NOBUF }; 768 static unsigned bufid = AFID_ID; /* buffer id counter */ 769 770 static struct here *inhere; /* list of hear docs while parsing */ 771 static struct here *acthere; /* list of active here documents */ 772 static struct region *areabot; /* bottom of area */ 773 static struct region *areatop; /* top of area */ 774 static struct region *areanxt; /* starting point of scan */ 697 static char *elinep; /* done in main(): = line + sizeof(line) - 5 */ 698 699 static struct here *inhere; /* list of hear docs while parsing */ 700 static struct here *acthere; /* list of active here documents */ 701 static struct region *areabot; /* bottom of area */ 702 static struct region *areatop; /* top of area */ 703 static struct region *areanxt; /* starting point of scan */ 775 704 static void *brktop; 776 705 static void *brkaddr; 777 706 707 /* 708 * parsing & execution environment 709 */ 710 struct env { 711 char *linep; 712 struct io *iobase; 713 struct io *iop; 714 xint *errpt; /* void * */ 715 int iofd; 716 struct env *oenv; 717 }; 718 778 719 static struct env e = { 779 line,/* linep: char ptr */780 iostack, 781 iostack - 1, 782 (xint *) NULL, 783 FDBASE, 784 (struct env *) NULL 720 NULL /* set to line in main() */, /* linep: char ptr */ 721 iostack, /* iobase: struct io ptr */ 722 iostack - 1, /* iop: struct io ptr */ 723 (xint *) NULL, /* errpt: void ptr for errors? */ 724 FDBASE, /* iofd: file desc */ 725 (struct env *) NULL /* oenv: struct env ptr */ 785 726 }; 786 727 728 729 struct globals { 730 char ourtrap[_NSIG + 1]; 731 char *trap[_NSIG + 1]; 732 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */ 733 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */ 734 struct ioarg ioargstack[NPUSH]; 735 char filechar_cmdbuf[BUFSIZ]; 736 char line[LINELIM]; 737 char child_cmd[LINELIM]; 738 }; 739 740 #define G (*ptr_to_globals) 741 #define ourtrap (G.ourtrap ) 742 #define trap (G.trap ) 743 #define sharedbuf (G.sharedbuf ) 744 #define mainbuf (G.mainbuf ) 745 #define ioargstack (G.ioargstack ) 746 #define filechar_cmdbuf (G.filechar_cmdbuf) 747 #define line (G.line ) 748 #define child_cmd (G.child_cmd ) 749 750 787 751 #ifdef MSHDEBUG 788 void print_t(struct op *t);789 752 void print_t(struct op *t) 790 753 { … … 795 758 DBGPRINTF(("T: W1: %s", t->words[0])); 796 759 } 797 798 return; 799 } 800 801 void print_tree(struct op *head); 760 } 761 802 762 void print_tree(struct op *head) 803 763 { … … 815 775 if (head->right) 816 776 print_tree(head->right); 817 818 return; 819 } 820 #endif /* MSHDEBUG */ 821 822 823 #ifdef CONFIG_FEATURE_COMMAND_EDITING 824 static char *current_prompt; 777 } 778 #endif /* MSHDEBUG */ 779 780 781 /* 782 * IO functions 783 */ 784 static void prs(const char *s) 785 { 786 if (*s) 787 write(2, s, strlen(s)); 788 } 789 790 static void prn(unsigned u) 791 { 792 prs(itoa(u)); 793 } 794 795 static void echo(char **wp) 796 { 797 int i; 798 799 prs("+"); 800 for (i = 0; wp[i]; i++) { 801 if (i) 802 prs(" "); 803 prs(wp[i]); 804 } 805 prs("\n"); 806 } 807 808 static void closef(int i) 809 { 810 if (i > 2) 811 close(i); 812 } 813 814 static void closeall(void) 815 { 816 int u; 817 818 for (u = NUFILE; u < NOFILE;) 819 close(u++); 820 } 821 822 823 /* fail but return to process next command */ 824 static void fail(void) ATTRIBUTE_NORETURN; 825 static void fail(void) 826 { 827 longjmp(failpt, 1); 828 /* NOTREACHED */ 829 } 830 831 /* abort shell (or fail in subshell) */ 832 static void leave(void) ATTRIBUTE_NORETURN; 833 static void leave(void) 834 { 835 DBGPRINTF(("LEAVE: leave called!\n")); 836 837 if (execflg) 838 fail(); 839 scraphere(); 840 freehere(1); 841 runtrap(0); 842 _exit(exstat); 843 /* NOTREACHED */ 844 } 845 846 static void warn(const char *s) 847 { 848 if (*s) { 849 prs(s); 850 exstat = -1; 851 } 852 prs("\n"); 853 if (FLAG['e']) 854 leave(); 855 } 856 857 static void err(const char *s) 858 { 859 warn(s); 860 if (FLAG['n']) 861 return; 862 if (!interactive) 863 leave(); 864 if (e.errpt) 865 longjmp(e.errpt, 1); 866 closeall(); 867 e.iop = e.iobase = iostack; 868 } 869 870 871 /* -------- area.c -------- */ 872 873 /* 874 * All memory between (char *)areabot and (char *)(areatop+1) is 875 * exclusively administered by the area management routines. 876 * It is assumed that sbrk() and brk() manipulate the high end. 877 */ 878 879 #define sbrk(X) ({ \ 880 void * __q = (void *)-1; \ 881 if (brkaddr + (int)(X) < brktop) { \ 882 __q = brkaddr; \ 883 brkaddr += (int)(X); \ 884 } \ 885 __q; \ 886 }) 887 888 static void initarea(void) 889 { 890 brkaddr = xmalloc(AREASIZE); 891 brktop = brkaddr + AREASIZE; 892 893 while ((long) sbrk(0) & ALIGN) 894 sbrk(1); 895 areabot = (struct region *) sbrk(REGSIZE); 896 897 areabot->next = areabot; 898 areabot->area = BUSY; 899 areatop = areabot; 900 areanxt = areabot; 901 } 902 903 static char *getcell(unsigned nbytes) 904 { 905 int nregio; 906 struct region *p, *q; 907 int i; 908 909 if (nbytes == 0) { 910 puts("getcell(0)"); 911 abort(); 912 } 913 /* silly and defeats the algorithm */ 914 /* 915 * round upwards and add administration area 916 */ 917 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; 918 p = areanxt; 919 for (;;) { 920 if (p->area > areanum) { 921 /* 922 * merge free cells 923 */ 924 while ((q = p->next)->area > areanum && q != areanxt) 925 p->next = q->next; 926 /* 927 * exit loop if cell big enough 928 */ 929 if (q >= p + nregio) 930 goto found; 931 } 932 p = p->next; 933 if (p == areanxt) 934 break; 935 } 936 i = nregio >= GROWBY ? nregio : GROWBY; 937 p = (struct region *) sbrk(i * REGSIZE); 938 if (p == (struct region *) -1) 939 return NULL; 940 p--; 941 if (p != areatop) { 942 puts("not contig"); 943 abort(); /* allocated areas are contiguous */ 944 } 945 q = p + i; 946 p->next = q; 947 p->area = FREE; 948 q->next = areabot; 949 q->area = BUSY; 950 areatop = q; 951 found: 952 /* 953 * we found a FREE area big enough, pointed to by 'p', and up to 'q' 954 */ 955 areanxt = p + nregio; 956 if (areanxt < q) { 957 /* 958 * split into requested area and rest 959 */ 960 if (areanxt + 1 > q) { 961 puts("OOM"); 962 abort(); /* insufficient space left for admin */ 963 } 964 areanxt->next = q; 965 areanxt->area = FREE; 966 p->next = areanxt; 967 } 968 p->area = areanum; 969 return (char *) (p + 1); 970 } 971 972 static void freecell(char *cp) 973 { 974 struct region *p; 975 976 p = (struct region *) cp; 977 if (p != NULL) { 978 p--; 979 if (p < areanxt) 980 areanxt = p; 981 p->area = FREE; 982 } 983 } 984 #define DELETE(obj) freecell((char *)obj) 985 986 static void freearea(int a) 987 { 988 struct region *p, *top; 989 990 top = areatop; 991 for (p = areabot; p != top; p = p->next) 992 if (p->area >= a) 993 p->area = FREE; 994 } 995 996 static void setarea(char *cp, int a) 997 { 998 struct region *p; 999 1000 p = (struct region *) cp; 1001 if (p != NULL) 1002 (p - 1)->area = a; 1003 } 1004 1005 static int getarea(char *cp) 1006 { 1007 return ((struct region *) cp - 1)->area; 1008 } 1009 1010 static void garbage(void) 1011 { 1012 struct region *p, *q, *top; 1013 1014 top = areatop; 1015 for (p = areabot; p != top; p = p->next) { 1016 if (p->area > areanum) { 1017 while ((q = p->next)->area > areanum) 1018 p->next = q->next; 1019 areanxt = p; 1020 } 1021 } 1022 #ifdef SHRINKBY 1023 if (areatop >= q + SHRINKBY && q->area > areanum) { 1024 brk((char *) (q + 1)); 1025 q->next = areabot; 1026 q->area = BUSY; 1027 areatop = q; 1028 } 825 1029 #endif 826 827 /* -------- sh.c -------- */ 828 /* 829 * shell 830 */ 831 832 833 int msh_main(int argc, char **argv) 834 { 835 REGISTER int f; 836 REGISTER char *s; 837 int cflag; 838 char *name, **ap; 839 int (*iof) (struct ioarg *); 840 841 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); 842 843 initarea(); 844 if ((ap = environ) != NULL) { 845 while (*ap) 846 assign(*ap++, !COPYV); 847 for (ap = environ; *ap;) 848 export(lookup(*ap++)); 849 } 850 closeall(); 851 areanum = 1; 852 853 shell = lookup("SHELL"); 854 if (shell->value == null) 855 setval(shell, (char *)DEFAULT_SHELL); 856 export(shell); 857 858 homedir = lookup("HOME"); 859 if (homedir->value == null) 860 setval(homedir, "/"); 861 export(homedir); 862 863 setval(lookup("$"), putn(getpid())); 864 865 path = lookup("PATH"); 866 if (path->value == null) { 867 if (geteuid() == 0) 868 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin"); 869 else 870 setval(path, "/bin:/usr/bin"); 871 } 872 export(path); 873 874 ifs = lookup("IFS"); 875 if (ifs->value == null) 876 setval(ifs, " \t\n"); 877 878 #ifdef MSHDEBUG 879 mshdbg_var = lookup("MSHDEBUG"); 880 if (mshdbg_var->value == null) 881 setval(mshdbg_var, "0"); 882 #endif 883 884 prompt = lookup("PS1"); 885 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT 886 if (prompt->value == null) 887 #endif 888 setval(prompt, DEFAULT_USER_PROMPT); 889 if (geteuid() == 0) { 890 setval(prompt, DEFAULT_ROOT_PROMPT); 891 prompt->status &= ~EXPORT; 892 } 893 cprompt = lookup("PS2"); 894 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT 895 if (cprompt->value == null) 896 #endif 897 setval(cprompt, "> "); 898 899 iof = filechar; 900 cflag = 0; 901 name = *argv++; 902 if (--argc >= 1) { 903 if (argv[0][0] == '-' && argv[0][1] != '\0') { 904 for (s = argv[0] + 1; *s; s++) 905 switch (*s) { 906 case 'c': 907 prompt->status &= ~EXPORT; 908 cprompt->status &= ~EXPORT; 909 setval(prompt, ""); 910 setval(cprompt, ""); 911 cflag = 1; 912 if (--argc > 0) 913 PUSHIO(aword, *++argv, iof = nlchar); 914 break; 915 916 case 'q': 917 qflag = SIG_DFL; 918 break; 919 920 case 's': 921 /* standard input */ 922 break; 923 924 case 't': 925 prompt->status &= ~EXPORT; 926 setval(prompt, ""); 927 iof = linechar; 928 break; 929 930 case 'i': 931 interactive++; 932 default: 933 if (*s >= 'a' && *s <= 'z') 934 flag[(int) *s]++; 935 } 936 } else { 937 argv--; 938 argc++; 939 } 940 941 if (iof == filechar && --argc > 0) { 942 setval(prompt, ""); 943 setval(cprompt, ""); 944 prompt->status &= ~EXPORT; 945 cprompt->status &= ~EXPORT; 946 947 /* Shell is non-interactive, activate printf-based debug */ 948 #ifdef MSHDEBUG 949 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0'); 950 if (mshdbg < 0) 951 mshdbg = 0; 952 #endif 953 DBGPRINTF(("MSH_MAIN: calling newfile()\n")); 954 955 if (newfile(name = *++argv)) 956 exit(1); /* Exit on error */ 957 } 958 } 959 960 setdash(); 961 962 /* This won't be true if PUSHIO has been called, say from newfile() above */ 963 if (e.iop < iostack) { 964 PUSHIO(afile, 0, iof); 965 if (isatty(0) && isatty(1) && !cflag) { 966 interactive++; 967 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 968 #ifdef MSHDEBUG 969 printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER); 970 #else 971 printf("\n\n%s Built-in shell (msh)\n", BB_BANNER); 972 #endif 973 printf("Enter 'help' for a list of built-in commands.\n\n"); 974 #endif 975 } 976 } 977 978 signal(SIGQUIT, qflag); 979 if (name && name[0] == '-') { 980 interactive++; 981 if ((f = open(".profile", 0)) >= 0) 982 next(remap(f)); 983 if ((f = open("/etc/profile", 0)) >= 0) 984 next(remap(f)); 985 } 986 if (interactive) 987 signal(SIGTERM, sig); 988 989 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 990 signal(SIGINT, onintr); 991 dolv = argv; 992 dolc = argc; 993 dolv[0] = name; 994 if (dolc > 1) { 995 for (ap = ++argv; --argc > 0;) { 996 if (assign(*ap = *argv++, !COPYV)) { 997 dolc--; /* keyword */ 998 } else { 999 ap++; 1000 } 1001 } 1002 } 1003 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); 1004 1005 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack)); 1006 1007 for (;;) { 1008 if (interactive && e.iop <= iostack) { 1009 #ifdef CONFIG_FEATURE_COMMAND_EDITING 1010 current_prompt = prompt->value; 1011 #else 1012 prs(prompt->value); 1013 #endif 1014 } 1015 onecommand(); 1016 /* Ensure that getenv("PATH") stays current */ 1017 setenv("PATH", path->value, 1); 1018 } 1019 1020 DBGPRINTF(("MSH_MAIN: returning.\n")); 1021 } 1030 } 1031 1032 static char *space(int n) 1033 { 1034 char *cp; 1035 1036 cp = getcell(n); 1037 if (cp == NULL) 1038 err("out of string space"); 1039 return cp; 1040 } 1041 1042 static char *strsave(const char *s, int a) 1043 { 1044 char *cp; 1045 1046 cp = space(strlen(s) + 1); 1047 if (cp == NULL) { 1048 // FIXME: I highly doubt this is good. 1049 return (char*)""; 1050 } 1051 setarea(cp, a); 1052 strcpy(cp, s); 1053 return cp; 1054 } 1055 1056 1057 /* -------- var.c -------- */ 1058 1059 static int eqname(const char *n1, const char *n2) 1060 { 1061 for (; *n1 != '=' && *n1 != '\0'; n1++) 1062 if (*n2++ != *n1) 1063 return 0; 1064 return *n2 == '\0' || *n2 == '='; 1065 } 1066 1067 static const char *findeq(const char *cp) 1068 { 1069 while (*cp != '\0' && *cp != '=') 1070 cp++; 1071 return cp; 1072 } 1073 1074 /* 1075 * Find the given name in the dictionary 1076 * and return its value. If the name was 1077 * not previously there, enter it now and 1078 * return a null value. 1079 */ 1080 static struct var *lookup(const char *n) 1081 { 1082 // FIXME: dirty hack 1083 static struct var dummy; 1084 1085 struct var *vp; 1086 const char *cp; 1087 char *xp; 1088 int c; 1089 1090 if (isdigit(*n)) { 1091 dummy.name = (char*)n; 1092 for (c = 0; isdigit(*n) && c < 1000; n++) 1093 c = c * 10 + *n - '0'; 1094 dummy.status = RONLY; 1095 dummy.value = (c <= dolc ? dolv[c] : null); 1096 return &dummy; 1097 } 1098 1099 for (vp = vlist; vp; vp = vp->next) 1100 if (eqname(vp->name, n)) 1101 return vp; 1102 1103 cp = findeq(n); 1104 vp = (struct var *) space(sizeof(*vp)); 1105 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { 1106 dummy.name = dummy.value = (char*)""; 1107 return &dummy; 1108 } 1109 1110 xp = vp->name; 1111 while ((*xp = *n++) != '\0' && *xp != '=') 1112 xp++; 1113 *xp++ = '='; 1114 *xp = '\0'; 1115 setarea((char *) vp, 0); 1116 setarea((char *) vp->name, 0); 1117 vp->value = null; 1118 vp->next = vlist; 1119 vp->status = GETCELL; 1120 vlist = vp; 1121 return vp; 1122 } 1123 1124 /* 1125 * if name is not NULL, it must be 1126 * a prefix of the space `val', 1127 * and end with `='. 1128 * this is all so that exporting 1129 * values is reasonably painless. 1130 */ 1131 static void nameval(struct var *vp, const char *val, const char *name) 1132 { 1133 const char *cp; 1134 char *xp; 1135 int fl; 1136 1137 if (vp->status & RONLY) { 1138 xp = vp->name; 1139 while (*xp && *xp != '=') 1140 putc(*xp++, stderr); 1141 err(" is read-only"); 1142 return; 1143 } 1144 fl = 0; 1145 if (name == NULL) { 1146 xp = space(strlen(vp->name) + strlen(val) + 2); 1147 if (xp == NULL) 1148 return; 1149 /* make string: name=value */ 1150 setarea(xp, 0); 1151 name = xp; 1152 cp = vp->name; 1153 while ((*xp = *cp++) != '\0' && *xp != '=') 1154 xp++; 1155 *xp++ = '='; 1156 strcpy(xp, val); 1157 val = xp; 1158 fl = GETCELL; 1159 } 1160 if (vp->status & GETCELL) 1161 freecell(vp->name); /* form new string `name=value' */ 1162 vp->name = (char*)name; 1163 vp->value = (char*)val; 1164 vp->status |= fl; 1165 } 1166 1167 /* 1168 * give variable at `vp' the value `val'. 1169 */ 1170 static void setval(struct var *vp, const char *val) 1171 { 1172 nameval(vp, val, NULL); 1173 } 1174 1175 static void export(struct var *vp) 1176 { 1177 vp->status |= EXPORT; 1178 } 1179 1180 static void ronly(struct var *vp) 1181 { 1182 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ 1183 vp->status |= RONLY; 1184 } 1185 1186 static int isassign(const char *s) 1187 { 1188 unsigned char c; 1189 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s)); 1190 1191 c = *s; 1192 /* no isalpha() - we shouldn't use locale */ 1193 /* c | 0x20 - lowercase (Latin) letters */ 1194 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25) 1195 /* not letter */ 1196 return 0; 1197 1198 while (1) { 1199 c = *++s; 1200 if (c == '=') 1201 return 1; 1202 if (c == '\0') 1203 return 0; 1204 if (c != '_' 1205 && (unsigned)(c - '0') > 9 /* not number */ 1206 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */ 1207 ) { 1208 return 0; 1209 } 1210 } 1211 } 1212 1213 static int assign(const char *s, int cf) 1214 { 1215 const char *cp; 1216 struct var *vp; 1217 1218 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf)); 1219 1220 if (!isalpha(*s) && *s != '_') 1221 return 0; 1222 for (cp = s; *cp != '='; cp++) 1223 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_')) 1224 return 0; 1225 vp = lookup(s); 1226 nameval(vp, ++cp, cf == COPYV ? NULL : s); 1227 if (cf != COPYV) 1228 vp->status &= ~GETCELL; 1229 return 1; 1230 } 1231 1232 static int checkname(char *cp) 1233 { 1234 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp)); 1235 1236 if (!isalpha(*cp++) && *(cp - 1) != '_') 1237 return 0; 1238 while (*cp) 1239 if (!isalnum(*cp++) && *(cp - 1) != '_') 1240 return 0; 1241 return 1; 1242 } 1243 1244 static void putvlist(int f, int out) 1245 { 1246 struct var *vp; 1247 1248 for (vp = vlist; vp; vp = vp->next) { 1249 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { 1250 if (vp->status & EXPORT) 1251 write(out, "export ", 7); 1252 if (vp->status & RONLY) 1253 write(out, "readonly ", 9); 1254 write(out, vp->name, (int) (findeq(vp->name) - vp->name)); 1255 write(out, "\n", 1); 1256 } 1257 } 1258 } 1259 1260 1261 /* 1262 * trap handling 1263 */ 1264 static void sig(int i) 1265 { 1266 trapset = i; 1267 signal(i, sig); 1268 } 1269 1270 static void runtrap(int i) 1271 { 1272 char *trapstr; 1273 1274 trapstr = trap[i]; 1275 if (trapstr == NULL) 1276 return; 1277 1278 if (i == 0) 1279 trap[i] = NULL; 1280 1281 RUN(aword, trapstr, nlchar); 1282 } 1283 1022 1284 1023 1285 static void setdash(void) 1024 1286 { 1025 REGISTERchar *cp;1026 REGISTERint c;1287 char *cp; 1288 int c; 1027 1289 char m['z' - 'a' + 1]; 1028 1290 1029 1291 cp = m; 1030 1292 for (c = 'a'; c <= 'z'; c++) 1031 if ( flag[(int)c])1293 if (FLAG[c]) 1032 1294 *cp++ = c; 1033 *cp = 0;1295 *cp = '\0'; 1034 1296 setval(lookup("-"), m); 1035 1297 } 1036 1298 1037 static int newfile( REGISTERchar *s)1038 { 1039 REGISTERint f;1299 static int newfile(char *s) 1300 { 1301 int f; 1040 1302 1041 1303 DBGPRINTF7(("NEWFILE: opening %s\n", s)); 1042 1304 1043 if (strcmp(s, "-") != 0) { 1305 f = 0; 1306 if (NOT_LONE_DASH(s)) { 1044 1307 DBGPRINTF(("NEWFILE: s is %s\n", s)); 1045 f = open(s, 0);1308 f = open(s, O_RDONLY); 1046 1309 if (f < 0) { 1047 1310 prs(s); 1048 1311 err(": cannot open"); 1049 return (1); 1050 } 1051 } else 1052 f = 0; 1312 return 1; 1313 } 1314 } 1053 1315 1054 1316 next(remap(f)); 1055 return (0);1317 return 0; 1056 1318 } 1057 1319 … … 1062 1324 1063 1325 if (head == NULL) 1064 return (NULL);1326 return NULL; 1065 1327 1066 1328 if (head->left != NULL) { 1067 1329 dotnode = scantree(head->left); 1068 1330 if (dotnode) 1069 return (dotnode);1331 return dotnode; 1070 1332 } 1071 1333 … … 1073 1335 dotnode = scantree(head->right); 1074 1336 if (dotnode) 1075 return (dotnode);1337 return dotnode; 1076 1338 } 1077 1339 1078 1340 if (head->words == NULL) 1079 return (NULL);1341 return NULL; 1080 1342 1081 1343 DBGPRINTF5(("SCANTREE: checking node %p\n", head)); 1082 1344 1083 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {1345 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) { 1084 1346 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head)); 1085 return (head);1086 } 1087 1088 return (NULL);1347 return head; 1348 } 1349 1350 return NULL; 1089 1351 } 1090 1352 … … 1092 1354 static void onecommand(void) 1093 1355 { 1094 REGISTERint i;1356 int i; 1095 1357 jmp_buf m1; 1096 1358 … … 1114 1376 execflg = 0; 1115 1377 1116 setjmp(failpt = m1); /* Bruce Evans' fix */ 1117 if (setjmp(failpt = m1) || yyparse() || intr) { 1118 1378 failpt = m1; 1379 setjmp(failpt); /* Bruce Evans' fix */ 1380 failpt = m1; 1381 if (setjmp(failpt) || yyparse() || intr) { 1119 1382 DBGPRINTF(("ONECOMMAND: this is not good.\n")); 1120 1383 … … 1134 1397 execflg = 0; 1135 1398 1136 if (! flag['n']) {1399 if (!FLAG['n']) { 1137 1400 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n", 1138 1401 outtree)); … … 1145 1408 } 1146 1409 1147 if ((i = trapset) != 0) { 1410 i = trapset; 1411 if (i != 0) { 1148 1412 trapset = 0; 1149 1413 runtrap(i); … … 1151 1415 } 1152 1416 1153 static void fail(void)1154 {1155 longjmp(failpt, 1);1156 /* NOTREACHED */1157 }1158 1159 static void leave(void)1160 {1161 DBGPRINTF(("LEAVE: leave called!\n"));1162 1163 if (execflg)1164 fail();1165 scraphere();1166 freehere(1);1167 runtrap(0);1168 _exit(exstat);1169 /* NOTREACHED */1170 }1171 1172 static void warn(REGISTER char *s)1173 {1174 if (*s) {1175 prs(s);1176 exstat = -1;1177 }1178 prs("\n");1179 if (flag['e'])1180 leave();1181 }1182 1183 static void err(char *s)1184 {1185 warn(s);1186 if (flag['n'])1187 return;1188 if (!interactive)1189 leave();1190 if (e.errpt)1191 longjmp(e.errpt, 1);1192 closeall();1193 e.iop = e.iobase = iostack;1194 }1195 1196 1417 static int newenv(int f) 1197 1418 { 1198 REGISTERstruct env *ep;1419 struct env *ep; 1199 1420 1200 1421 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f)); … … 1202 1423 if (f) { 1203 1424 quitenv(); 1204 return (1);1425 return 1; 1205 1426 } 1206 1427 … … 1215 1436 e.errpt = errpt; 1216 1437 1217 return (0);1438 return 0; 1218 1439 } 1219 1440 1220 1441 static void quitenv(void) 1221 1442 { 1222 REGISTERstruct env *ep;1223 REGISTERint fd;1443 struct env *ep; 1444 int fd; 1224 1445 1225 1446 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv)); 1226 1447 1227 if ((ep = e.oenv) != NULL) { 1448 ep = e.oenv; 1449 if (ep != NULL) { 1228 1450 fd = e.iofd; 1229 1451 e = *ep; … … 1236 1458 1237 1459 /* 1460 * Is character c in s? 1461 */ 1462 static int any(int c, const char *s) 1463 { 1464 while (*s) 1465 if (*s++ == c) 1466 return 1; 1467 return 0; 1468 } 1469 1470 /* 1238 1471 * Is any character from s1 in s2? 1239 1472 */ 1240 static int anys( REGISTER char *s1, REGISTERchar *s2)1473 static int anys(const char *s1, const char *s2) 1241 1474 { 1242 1475 while (*s1) 1243 1476 if (any(*s1++, s2)) 1244 return (1); 1245 return (0); 1246 } 1247 1248 /* 1249 * Is character c in s? 1250 */ 1251 static int any(REGISTER int c, REGISTER char *s) 1252 { 1253 while (*s) 1254 if (*s++ == c) 1255 return (1); 1256 return (0); 1257 } 1258 1259 static char *putn(REGISTER int n) 1260 { 1261 return (itoa(n)); 1262 } 1263 1264 static char *itoa(REGISTER int n) 1265 { 1266 static char s[20]; 1267 1268 snprintf(s, sizeof(s), "%u", n); 1269 return (s); 1270 } 1271 1477 return 1; 1478 return 0; 1479 } 1480 1481 static char *putn(int n) 1482 { 1483 return itoa(n); 1484 } 1272 1485 1273 1486 static void next(int f) … … 1291 1504 } 1292 1505 1293 static char *space(int n)1294 {1295 REGISTER char *cp;1296 1297 if ((cp = getcell(n)) == 0)1298 err("out of string space");1299 return (cp);1300 }1301 1302 static char *strsave(REGISTER char *s, int a)1303 {1304 REGISTER char *cp, *xp;1305 1306 if ((cp = space(strlen(s) + 1)) != NULL) {1307 setarea((char *) cp, a);1308 for (xp = cp; (*xp++ = *s++) != '\0';);1309 return (cp);1310 }1311 return ("");1312 }1313 1314 /*1315 * trap handling1316 */1317 static void sig(REGISTER int i)1318 {1319 trapset = i;1320 signal(i, sig);1321 }1322 1323 static void runtrap(int i)1324 {1325 char *trapstr;1326 1327 if ((trapstr = trap[i]) == NULL)1328 return;1329 1330 if (i == 0)1331 trap[i] = 0;1332 1333 RUN(aword, trapstr, nlchar);1334 }1335 1336 /* -------- var.c -------- */1337 1338 /*1339 * Find the given name in the dictionary1340 * and return its value. If the name was1341 * not previously there, enter it now and1342 * return a null value.1343 */1344 static struct var *lookup(REGISTER char *n)1345 {1346 REGISTER struct var *vp;1347 REGISTER char *cp;1348 REGISTER int c;1349 static struct var dummy;1350 1351 if (isdigit(*n)) {1352 dummy.name = n;1353 for (c = 0; isdigit(*n) && c < 1000; n++)1354 c = c * 10 + *n - '0';1355 dummy.status = RONLY;1356 dummy.value = c <= dolc ? dolv[c] : null;1357 return (&dummy);1358 }1359 for (vp = vlist; vp; vp = vp->next)1360 if (eqname(vp->name, n))1361 return (vp);1362 cp = findeq(n);1363 vp = (struct var *) space(sizeof(*vp));1364 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {1365 dummy.name = dummy.value = "";1366 return (&dummy);1367 }1368 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);1369 if (*cp == 0)1370 *cp = '=';1371 *++cp = 0;1372 setarea((char *) vp, 0);1373 setarea((char *) vp->name, 0);1374 vp->value = null;1375 vp->next = vlist;1376 vp->status = GETCELL;1377 vlist = vp;1378 return (vp);1379 }1380 1381 /*1382 * give variable at `vp' the value `val'.1383 */1384 static void setval(struct var *vp, char *val)1385 {1386 nameval(vp, val, (char *) NULL);1387 }1388 1389 /*1390 * if name is not NULL, it must be1391 * a prefix of the space `val',1392 * and end with `='.1393 * this is all so that exporting1394 * values is reasonably painless.1395 */1396 static void nameval(REGISTER struct var *vp, char *val, char *name)1397 {1398 REGISTER char *cp, *xp;1399 char *nv;1400 int fl;1401 1402 if (vp->status & RONLY) {1403 for (xp = vp->name; *xp && *xp != '=';)1404 putc(*xp++, stderr);1405 err(" is read-only");1406 return;1407 }1408 fl = 0;1409 if (name == NULL) {1410 xp = space(strlen(vp->name) + strlen(val) + 2);1411 if (xp == 0)1412 return;1413 /* make string: name=value */1414 setarea((char *) xp, 0);1415 name = xp;1416 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);1417 if (*xp++ == 0)1418 xp[-1] = '=';1419 nv = xp;1420 for (cp = val; (*xp++ = *cp++) != '\0';);1421 val = nv;1422 fl = GETCELL;1423 }1424 if (vp->status & GETCELL)1425 freecell(vp->name); /* form new string `name=value' */1426 vp->name = name;1427 vp->value = val;1428 vp->status |= fl;1429 }1430 1431 static void export(struct var *vp)1432 {1433 vp->status |= EXPORT;1434 }1435 1436 static void ronly(struct var *vp)1437 {1438 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */1439 vp->status |= RONLY;1440 }1441 1442 static int isassign(REGISTER char *s)1443 {1444 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));1445 1446 if (!isalpha((int) *s) && *s != '_')1447 return (0);1448 for (; *s != '='; s++)1449 if (*s == 0 || (!isalnum(*s) && *s != '_'))1450 return (0);1451 1452 return (1);1453 }1454 1455 static int assign(REGISTER char *s, int cf)1456 {1457 REGISTER char *cp;1458 struct var *vp;1459 1460 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));1461 1462 if (!isalpha(*s) && *s != '_')1463 return (0);1464 for (cp = s; *cp != '='; cp++)1465 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))1466 return (0);1467 vp = lookup(s);1468 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);1469 if (cf != COPYV)1470 vp->status &= ~GETCELL;1471 return (1);1472 }1473 1474 static int checkname(REGISTER char *cp)1475 {1476 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));1477 1478 if (!isalpha(*cp++) && *(cp - 1) != '_')1479 return (0);1480 while (*cp)1481 if (!isalnum(*cp++) && *(cp - 1) != '_')1482 return (0);1483 return (1);1484 }1485 1486 static void putvlist(REGISTER int f, REGISTER int out)1487 {1488 REGISTER struct var *vp;1489 1490 for (vp = vlist; vp; vp = vp->next)1491 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {1492 if (vp->status & EXPORT)1493 write(out, "export ", 7);1494 if (vp->status & RONLY)1495 write(out, "readonly ", 9);1496 write(out, vp->name, (int) (findeq(vp->name) - vp->name));1497 write(out, "\n", 1);1498 }1499 }1500 1501 static int eqname(REGISTER char *n1, REGISTER char *n2)1502 {1503 for (; *n1 != '=' && *n1 != 0; n1++)1504 if (*n2++ != *n1)1505 return (0);1506 return (*n2 == 0 || *n2 == '=');1507 }1508 1509 static char *findeq(REGISTER char *cp)1510 {1511 while (*cp != '\0' && *cp != '=')1512 cp++;1513 return (cp);1514 }1515 1506 1516 1507 /* -------- gmatch.c -------- */ … … 1524 1515 #define CMASK 0377 1525 1516 #define QUOTE 0200 1526 #define QMASK (CMASK &~QUOTE)1517 #define QMASK (CMASK & ~QUOTE) 1527 1518 #define NOT '!' /* might use ^ */ 1528 1519 1529 static int gmatch(REGISTER char *s, REGISTER char *p) 1530 { 1531 REGISTER int sc, pc; 1532 1533 if (s == NULL || p == NULL) 1534 return (0); 1535 while ((pc = *p++ & CMASK) != '\0') { 1536 sc = *s++ & QMASK; 1537 switch (pc) { 1538 case '[': 1539 if ((p = cclass(p, sc)) == NULL) 1540 return (0); 1541 break; 1542 1543 case '?': 1544 if (sc == 0) 1545 return (0); 1546 break; 1547 1548 case '*': 1549 s--; 1550 do { 1551 if (*p == '\0' || gmatch(s, p)) 1552 return (1); 1553 } while (*s++ != '\0'); 1554 return (0); 1555 1556 default: 1557 if (sc != (pc & ~QUOTE)) 1558 return (0); 1559 } 1560 } 1561 return (*s == 0); 1562 } 1563 1564 static char *cclass(REGISTER char *p, REGISTER int sub) 1565 { 1566 REGISTER int c, d, not, found; 1567 1568 if ((not = *p == NOT) != 0) 1520 static const char *cclass(const char *p, int sub) 1521 { 1522 int c, d, not, found; 1523 1524 not = (*p == NOT); 1525 if (not != 0) 1569 1526 p++; 1570 1527 found = not; 1571 1528 do { 1572 1529 if (*p == '\0') 1573 return ((char *) NULL);1530 return NULL; 1574 1531 c = *p & CMASK; 1575 1532 if (p[1] == '-' && p[2] != ']') { … … 1581 1538 found = !not; 1582 1539 } while (*++p != ']'); 1583 return (found ? p + 1 : (char *) NULL); 1584 } 1585 1586 1587 /* -------- area.c -------- */ 1588 1589 /* 1590 * All memory between (char *)areabot and (char *)(areatop+1) is 1591 * exclusively administered by the area management routines. 1592 * It is assumed that sbrk() and brk() manipulate the high end. 1593 */ 1594 1595 #define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;}) 1596 1597 static void initarea(void) 1598 { 1599 brkaddr = xmalloc(AREASIZE); 1600 brktop = brkaddr + AREASIZE; 1601 1602 while ((long) sbrk(0) & ALIGN) 1603 sbrk(1); 1604 areabot = (struct region *) sbrk(REGSIZE); 1605 1606 areabot->next = areabot; 1607 areabot->area = BUSY; 1608 areatop = areabot; 1609 areanxt = areabot; 1610 } 1611 1612 char *getcell(unsigned nbytes) 1613 { 1614 REGISTER int nregio; 1615 REGISTER struct region *p, *q; 1616 REGISTER int i; 1617 1618 if (nbytes == 0) { 1619 puts("getcell(0)"); 1620 abort(); 1621 } 1622 /* silly and defeats the algorithm */ 1623 /* 1624 * round upwards and add administration area 1625 */ 1626 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; 1627 for (p = areanxt;;) { 1628 if (p->area > areanum) { 1629 /* 1630 * merge free cells 1631 */ 1632 while ((q = p->next)->area > areanum && q != areanxt) 1633 p->next = q->next; 1634 /* 1635 * exit loop if cell big enough 1636 */ 1637 if (q >= p + nregio) 1638 goto found; 1639 } 1640 p = p->next; 1641 if (p == areanxt) 1540 return found ? p + 1 : NULL; 1541 } 1542 1543 static int gmatch(const char *s, const char *p) 1544 { 1545 int sc, pc; 1546 1547 if (s == NULL || p == NULL) 1548 return 0; 1549 1550 while ((pc = *p++ & CMASK) != '\0') { 1551 sc = *s++ & QMASK; 1552 switch (pc) { 1553 case '[': 1554 p = cclass(p, sc); 1555 if (p == NULL) 1556 return 0; 1642 1557 break; 1643 } 1644 i = nregio >= GROWBY ? nregio : GROWBY; 1645 p = (struct region *) sbrk(i * REGSIZE); 1646 if (p == (struct region *) -1) 1647 return ((char *) NULL); 1648 p--; 1649 if (p != areatop) { 1650 puts("not contig"); 1651 abort(); /* allocated areas are contiguous */ 1652 } 1653 q = p + i; 1654 p->next = q; 1655 p->area = FREE; 1656 q->next = areabot; 1657 q->area = BUSY; 1658 areatop = q; 1659 found: 1660 /* 1661 * we found a FREE area big enough, pointed to by 'p', and up to 'q' 1662 */ 1663 areanxt = p + nregio; 1664 if (areanxt < q) { 1665 /* 1666 * split into requested area and rest 1667 */ 1668 if (areanxt + 1 > q) { 1669 puts("OOM"); 1670 abort(); /* insufficient space left for admin */ 1671 } 1672 areanxt->next = q; 1673 areanxt->area = FREE; 1674 p->next = areanxt; 1675 } 1676 p->area = areanum; 1677 return ((char *) (p + 1)); 1678 } 1679 1680 static void freecell(char *cp) 1681 { 1682 REGISTER struct region *p; 1683 1684 if ((p = (struct region *) cp) != NULL) { 1685 p--; 1686 if (p < areanxt) 1687 areanxt = p; 1688 p->area = FREE; 1689 } 1690 } 1691 1692 static void freearea(REGISTER int a) 1693 { 1694 REGISTER struct region *p, *top; 1695 1696 top = areatop; 1697 for (p = areabot; p != top; p = p->next) 1698 if (p->area >= a) 1699 p->area = FREE; 1700 } 1701 1702 static void setarea(char *cp, int a) 1703 { 1704 REGISTER struct region *p; 1705 1706 if ((p = (struct region *) cp) != NULL) 1707 (p - 1)->area = a; 1708 } 1709 1710 int getarea(char *cp) 1711 { 1712 return ((struct region *) cp - 1)->area; 1713 } 1714 1715 static void garbage(void) 1716 { 1717 REGISTER struct region *p, *q, *top; 1718 1719 top = areatop; 1720 for (p = areabot; p != top; p = p->next) { 1721 if (p->area > areanum) { 1722 while ((q = p->next)->area > areanum) 1723 p->next = q->next; 1724 areanxt = p; 1725 } 1726 } 1727 #ifdef SHRINKBY 1728 if (areatop >= q + SHRINKBY && q->area > areanum) { 1729 brk((char *) (q + 1)); 1730 q->next = areabot; 1731 q->area = BUSY; 1732 areatop = q; 1733 } 1734 #endif 1735 } 1558 1559 case '?': 1560 if (sc == 0) 1561 return 0; 1562 break; 1563 1564 case '*': 1565 s--; 1566 do { 1567 if (*p == '\0' || gmatch(s, p)) 1568 return 1; 1569 } while (*s++ != '\0'); 1570 return 0; 1571 1572 default: 1573 if (sc != (pc & ~QUOTE)) 1574 return 0; 1575 } 1576 } 1577 return *s == '\0'; 1578 } 1579 1736 1580 1737 1581 /* -------- csyn.c -------- */ … … 1739 1583 * shell: syntax (C version) 1740 1584 */ 1585 1586 static void yyerror(const char *s) ATTRIBUTE_NORETURN; 1587 static void yyerror(const char *s) 1588 { 1589 yynerrs++; 1590 if (interactive && e.iop <= iostack) { 1591 multiline = 0; 1592 while (eofc() == 0 && yylex(0) != '\n'); 1593 } 1594 err(s); 1595 fail(); 1596 } 1597 1598 static void zzerr(void) ATTRIBUTE_NORETURN; 1599 static void zzerr(void) 1600 { 1601 yyerror("syntax error"); 1602 } 1741 1603 1742 1604 int yyparse(void) … … 1754 1616 static struct op *pipeline(int cf) 1755 1617 { 1756 REGISTERstruct op *t, *p;1757 REGISTERint c;1618 struct op *t, *p; 1619 int c; 1758 1620 1759 1621 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf)); … … 1765 1627 if (t != NULL) { 1766 1628 while ((c = yylex(0)) == '|') { 1767 if ((p = command(CONTIN)) == NULL) { 1629 p = command(CONTIN); 1630 if (p == NULL) { 1768 1631 DBGPRINTF8(("PIPELINE: error!\n")); 1769 SYNTAXERR;1632 zzerr(); 1770 1633 } 1771 1634 … … 1781 1644 1782 1645 DBGPRINTF7(("PIPELINE: returning t=%p\n", t)); 1783 return (t);1646 return t; 1784 1647 } 1785 1648 1786 1649 static struct op *andor(void) 1787 1650 { 1788 REGISTERstruct op *t, *p;1789 REGISTERint c;1651 struct op *t, *p; 1652 int c; 1790 1653 1791 1654 DBGPRINTF7(("ANDOR: enter...\n")); … … 1797 1660 if (t != NULL) { 1798 1661 while ((c = yylex(0)) == LOGAND || c == LOGOR) { 1799 if ((p = pipeline(CONTIN)) == NULL) { 1662 p = pipeline(CONTIN); 1663 if (p == NULL) { 1800 1664 DBGPRINTF8(("ANDOR: error!\n")); 1801 SYNTAXERR;1665 zzerr(); 1802 1666 } 1803 1667 … … 1809 1673 1810 1674 DBGPRINTF7(("ANDOR: returning t=%p\n", t)); 1811 return (t);1675 return t; 1812 1676 } 1813 1677 1814 1678 static struct op *c_list(void) 1815 1679 { 1816 REGISTERstruct op *t, *p;1817 REGISTERint c;1680 struct op *t, *p; 1681 int c; 1818 1682 1819 1683 DBGPRINTF7(("C_LIST: enter...\n")); … … 1822 1686 1823 1687 if (t != NULL) { 1824 if ((peeksym = yylex(0)) == '&') 1688 peeksym = yylex(0); 1689 if (peeksym == '&') 1825 1690 t = block(TASYNC, t, NOBLOCK, NOWORDS); 1826 1691 … … 1828 1693 || (multiline && c == '\n')) { 1829 1694 1830 if ((p = andor()) == NULL) 1831 return (t); 1832 1833 if ((peeksym = yylex(0)) == '&') 1695 p = andor(); 1696 if (p== NULL) 1697 return t; 1698 1699 peeksym = yylex(0); 1700 if (peeksym == '&') 1834 1701 p = block(TASYNC, p, NOBLOCK, NOWORDS); 1835 1702 … … 1841 1708 /* IF */ 1842 1709 DBGPRINTF7(("C_LIST: returning t=%p\n", t)); 1843 return (t);1710 return t; 1844 1711 } 1845 1712 1846 1713 static int synio(int cf) 1847 1714 { 1848 REGISTERstruct ioword *iop;1849 REGISTERint i;1850 REGISTERint c;1715 struct ioword *iop; 1716 int i; 1717 int c; 1851 1718 1852 1719 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf)); 1853 1720 1854 if ((c = yylex(cf)) != '<' && c != '>') { 1721 c = yylex(cf); 1722 if (c != '<' && c != '>') { 1855 1723 peeksym = c; 1856 return (0);1724 return 0; 1857 1725 } 1858 1726 … … 1866 1734 1867 1735 DBGPRINTF7(("SYNIO: returning 1\n")); 1868 return (1);1736 return 1; 1869 1737 } 1870 1738 1871 1739 static void musthave(int c, int cf) 1872 1740 { 1873 if ((peeksym = yylex(cf)) != c) { 1741 peeksym = yylex(cf); 1742 if (peeksym != c) { 1874 1743 DBGPRINTF7(("MUSTHAVE: error!\n")); 1875 SYNTAXERR;1744 zzerr(); 1876 1745 } 1877 1746 … … 1881 1750 static struct op *simple(void) 1882 1751 { 1883 REGISTERstruct op *t;1752 struct op *t; 1884 1753 1885 1754 t = NULL; … … 1901 1770 1902 1771 default: 1903 return (t);1772 return t; 1904 1773 } 1905 1774 } … … 1908 1777 static struct op *nested(int type, int mark) 1909 1778 { 1910 REGISTERstruct op *t;1779 struct op *t; 1911 1780 1912 1781 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark)); … … 1916 1785 musthave(mark, 0); 1917 1786 multiline--; 1918 return (block(type, t, NOBLOCK, NOWORDS));1787 return block(type, t, NOBLOCK, NOWORDS); 1919 1788 } 1920 1789 1921 1790 static struct op *command(int cf) 1922 1791 { 1923 REGISTERstruct op *t;1792 struct op *t; 1924 1793 struct wdblock *iosave; 1925 REGISTERint c;1794 int c; 1926 1795 1927 1796 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf)); … … 1941 1810 default: 1942 1811 peeksym = c; 1943 if ((t = simple()) == NULL) { 1812 t = simple(); 1813 if (t == NULL) { 1944 1814 if (iolist == NULL) 1945 return ((struct op *) NULL);1815 return NULL; 1946 1816 t = newtp(); 1947 1817 t->type = TCOM; … … 1965 1835 multiline++; 1966 1836 t->words = wordlist(); 1967 if ((c = yylex(0)) != '\n' && c != ';') 1837 c = yylex(0); 1838 if (c != '\n' && c != ';') 1968 1839 peeksym = c; 1969 1840 t->left = dogroup(0); … … 2029 1900 DBGPRINTF(("COMMAND: returning %p\n", t)); 2030 1901 2031 return (t);1902 return t; 2032 1903 } 2033 1904 2034 1905 static struct op *dowholefile(int type, int mark) 2035 1906 { 2036 REGISTERstruct op *t;1907 struct op *t; 2037 1908 2038 1909 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark)); … … 2043 1914 t = block(type, t, NOBLOCK, NOWORDS); 2044 1915 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t)); 2045 return (t);1916 return t; 2046 1917 } 2047 1918 2048 1919 static struct op *dogroup(int onlydone) 2049 1920 { 2050 REGISTERint c;2051 REGISTERstruct op *mylist;1921 int c; 1922 struct op *mylist; 2052 1923 2053 1924 c = yylex(CONTIN); 2054 1925 if (c == DONE && onlydone) 2055 return ((struct op *) NULL);1926 return NULL; 2056 1927 if (c != DO) 2057 SYNTAXERR;1928 zzerr(); 2058 1929 mylist = c_list(); 2059 1930 musthave(DONE, 0); 2060 return (mylist);1931 return mylist; 2061 1932 } 2062 1933 2063 1934 static struct op *thenpart(void) 2064 1935 { 2065 REGISTER int c; 2066 REGISTER struct op *t; 2067 2068 if ((c = yylex(0)) != THEN) { 1936 int c; 1937 struct op *t; 1938 1939 c = yylex(0); 1940 if (c != THEN) { 2069 1941 peeksym = c; 2070 return ((struct op *) NULL);1942 return NULL; 2071 1943 } 2072 1944 t = newtp(); … … 2074 1946 t->left = c_list(); 2075 1947 if (t->left == NULL) 2076 SYNTAXERR;1948 zzerr(); 2077 1949 t->right = elsepart(); 2078 return (t);1950 return t; 2079 1951 } 2080 1952 2081 1953 static struct op *elsepart(void) 2082 1954 { 2083 REGISTERint c;2084 REGISTERstruct op *t;1955 int c; 1956 struct op *t; 2085 1957 2086 1958 switch (c = yylex(0)) { 2087 1959 case ELSE: 2088 if ((t = c_list()) == NULL) 2089 SYNTAXERR; 2090 return (t); 1960 t = c_list(); 1961 if (t == NULL) 1962 zzerr(); 1963 return t; 2091 1964 2092 1965 case ELIF: … … 2095 1968 t->left = c_list(); 2096 1969 t->right = thenpart(); 2097 return (t);1970 return t; 2098 1971 2099 1972 default: 2100 1973 peeksym = c; 2101 return ((struct op *) NULL);1974 return NULL; 2102 1975 } 2103 1976 } … … 2105 1978 static struct op *caselist(void) 2106 1979 { 2107 REGISTERstruct op *t;1980 struct op *t; 2108 1981 2109 1982 t = NULL; … … 2114 1987 2115 1988 DBGPRINTF(("CASELIST, returning t=%p\n", t)); 2116 return (t);1989 return t; 2117 1990 } 2118 1991 2119 1992 static struct op *casepart(void) 2120 1993 { 2121 REGISTERstruct op *t;1994 struct op *t; 2122 1995 2123 1996 DBGPRINTF7(("CASEPART: enter...\n")); … … 2128 2001 musthave(')', 0); 2129 2002 t->left = c_list(); 2130 if ((peeksym = yylex(CONTIN)) != ESAC) 2003 peeksym = yylex(CONTIN); 2004 if (peeksym != ESAC) 2131 2005 musthave(BREAK, CONTIN); 2132 2006 2133 2007 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t)); 2134 2008 2135 return (t);2009 return t; 2136 2010 } 2137 2011 2138 2012 static char **pattern(void) 2139 2013 { 2140 REGISTERint c, cf;2014 int c, cf; 2141 2015 2142 2016 cf = CONTIN; … … 2145 2019 word(yylval.cp); 2146 2020 cf = 0; 2147 } while ((c = yylex(0)) == '|'); 2021 c = yylex(0); 2022 } while (c == '|'); 2148 2023 peeksym = c; 2149 2024 word(NOWORD); 2150 2025 2151 return (copyw());2026 return copyw(); 2152 2027 } 2153 2028 2154 2029 static char **wordlist(void) 2155 2030 { 2156 REGISTER int c; 2157 2158 if ((c = yylex(0)) != IN) { 2031 int c; 2032 2033 c = yylex(0); 2034 if (c != IN) { 2159 2035 peeksym = c; 2160 return ((char **) NULL);2036 return NULL; 2161 2037 } 2162 2038 startl = 0; … … 2165 2041 word(NOWORD); 2166 2042 peeksym = c; 2167 return (copyw());2043 return copyw(); 2168 2044 } 2169 2045 … … 2171 2047 * supporting functions 2172 2048 */ 2173 static struct op *list( REGISTER struct op *t1, REGISTERstruct op *t2)2049 static struct op *list(struct op *t1, struct op *t2) 2174 2050 { 2175 2051 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2)); 2176 2052 2177 2053 if (t1 == NULL) 2178 return (t2);2054 return t2; 2179 2055 if (t2 == NULL) 2180 return (t1);2181 2182 return (block(TLIST, t1, t2, NOWORDS));2056 return t1; 2057 2058 return block(TLIST, t1, t2, NOWORDS); 2183 2059 } 2184 2060 2185 2061 static struct op *block(int type, struct op *t1, struct op *t2, char **wp) 2186 2062 { 2187 REGISTERstruct op *t;2063 struct op *t; 2188 2064 2189 2065 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type])); … … 2198 2074 t2)); 2199 2075 2200 return (t);2076 return t; 2201 2077 } 2202 2078 2203 2079 /* See if given string is a shell multiline (FOR, IF, etc) */ 2204 static int rlookup( REGISTERchar *n)2205 { 2206 REGISTERconst struct res *rp;2080 static int rlookup(char *n) 2081 { 2082 const struct res *rp; 2207 2083 2208 2084 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n)); … … 2211 2087 if (strcmp(rp->r_name, n) == 0) { 2212 2088 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val)); 2213 return (rp->r_val); /* Return numeric code for shell multiline */2089 return rp->r_val; /* Return numeric code for shell multiline */ 2214 2090 } 2215 2091 2216 2092 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n")); 2217 return (0); /* Not a shell multiline */2093 return 0; /* Not a shell multiline */ 2218 2094 } 2219 2095 2220 2096 static struct op *newtp(void) 2221 2097 { 2222 REGISTERstruct op *t;2098 struct op *t; 2223 2099 2224 2100 t = (struct op *) tree(sizeof(*t)); … … 2232 2108 DBGPRINTF3(("NEWTP: allocated %p\n", t)); 2233 2109 2234 return (t); 2235 } 2236 2237 static struct op *namelist(REGISTER struct op *t) 2238 { 2239 2110 return t; 2111 } 2112 2113 static struct op *namelist(struct op *t) 2114 { 2240 2115 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t, 2241 2116 T_CMD_NAMES[t->type], iolist)); … … 2253 2128 t->left->ioact = NULL; 2254 2129 } 2255 return (t);2130 return t; 2256 2131 } 2257 2132 … … 2259 2134 t->words = copyw(); 2260 2135 2261 2262 return (t); 2136 return t; 2263 2137 } 2264 2138 2265 2139 static char **copyw(void) 2266 2140 { 2267 REGISTERchar **wd;2141 char **wd; 2268 2142 2269 2143 wd = getwords(wdlist); 2270 2144 wdlist = 0; 2271 return (wd);2145 return wd; 2272 2146 } 2273 2147 … … 2279 2153 static struct ioword **copyio(void) 2280 2154 { 2281 REGISTERstruct ioword **iop;2155 struct ioword **iop; 2282 2156 2283 2157 iop = (struct ioword **) getwords(iolist); 2284 2158 iolist = 0; 2285 return (iop);2159 return iop; 2286 2160 } 2287 2161 2288 2162 static struct ioword *io(int u, int f, char *cp) 2289 2163 { 2290 REGISTERstruct ioword *iop;2164 struct ioword *iop; 2291 2165 2292 2166 iop = (struct ioword *) tree(sizeof(*iop)); … … 2295 2169 iop->io_name = cp; 2296 2170 iolist = addword((char *) iop, iolist); 2297 return (iop); 2298 } 2299 2300 static void zzerr(void) 2301 { 2302 yyerror("syntax error"); 2303 } 2304 2305 static void yyerror(char *s) 2306 { 2307 yynerrs++; 2308 if (interactive && e.iop <= iostack) { 2309 multiline = 0; 2310 while (eofc() == 0 && yylex(0) != '\n'); 2311 } 2312 err(s); 2313 fail(); 2171 return iop; 2314 2172 } 2315 2173 2316 2174 static int yylex(int cf) 2317 2175 { 2318 REGISTERint c, c1;2176 int c, c1; 2319 2177 int atstart; 2320 2178 2321 if ((c = peeksym) > 0) { 2179 c = peeksym; 2180 if (c > 0) { 2322 2181 peeksym = 0; 2323 2182 if (c == '\n') 2324 2183 startl = 1; 2325 return (c); 2326 } 2327 2184 return c; 2185 } 2328 2186 2329 2187 nlseen = 0; … … 2336 2194 line[LINELIM - 1] = '\0'; 2337 2195 2338 2196 loop: 2339 2197 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */ 2340 2198 ; … … 2343 2201 default: 2344 2202 if (any(c, "0123456789")) { 2345 unget(c1 = my_getc(0)); 2203 c1 = my_getc(0); 2204 unget(c1); 2346 2205 if (c1 == '<' || c1 == '>') { 2347 2206 iounit = c - '0'; … … 2354 2213 2355 2214 case '#': /* Comment, skip to next newline or End-of-string */ 2356 while ((c = my_getc(0)) != 0&& c != '\n');2215 while ((c = my_getc(0)) != '\0' && c != '\n'); 2357 2216 unget(c); 2358 2217 goto loop; … … 2360 2219 case 0: 2361 2220 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c)); 2362 return (c);2221 return c; 2363 2222 2364 2223 case '$': 2365 2224 DBGPRINTF9(("YYLEX: found $\n")); 2366 2225 *e.linep++ = c; 2367 if ((c = my_getc(0)) == '{') { 2368 if ((c = collect(c, '}')) != '\0') 2369 return (c); 2226 c = my_getc(0); 2227 if (c == '{') { 2228 c = collect(c, '}'); 2229 if (c != '\0') 2230 return c; 2370 2231 goto pack; 2371 2232 } … … 2375 2236 case '\'': 2376 2237 case '"': 2377 if ((c = collect(c, c)) != '\0') 2378 return (c); 2238 c = collect(c, c); 2239 if (c != '\0') 2240 return c; 2379 2241 goto pack; 2380 2242 … … 2384 2246 startl = 1; 2385 2247 /* If more chars process them, else return NULL char */ 2386 if ((c1 = dual(c)) != '\0')2387 return (c1);2388 else2389 return (c);2248 c1 = dual(c); 2249 if (c1 != '\0') 2250 return c1; 2251 return c; 2390 2252 2391 2253 case '^': 2392 2254 startl = 1; 2393 return ('|');2255 return '|'; 2394 2256 case '>': 2395 2257 case '<': 2396 2258 diag(c); 2397 return (c);2259 return c; 2398 2260 2399 2261 case '\n': … … 2403 2265 if (multiline || cf & CONTIN) { 2404 2266 if (interactive && e.iop <= iostack) { 2405 #if def CONFIG_FEATURE_COMMAND_EDITING2267 #if ENABLE_FEATURE_EDITING 2406 2268 current_prompt = cprompt->value; 2407 2269 #else … … 2412 2274 goto loop; 2413 2275 } 2414 return (c);2276 return c; 2415 2277 2416 2278 case '(': 2417 2279 case ')': 2418 2280 startl = 1; 2419 return (c);2281 return c; 2420 2282 } 2421 2283 2422 2284 unget(c); 2423 2285 2424 2425 while ((c = my_getc(0)) != 0&& !any(c, "`$ '\"\t;&<>()|^\n")) {2286 pack: 2287 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) { 2426 2288 if (e.linep >= elinep) 2427 2289 err("word too long"); … … 2437 2299 *e.linep++ = '\0'; 2438 2300 2439 if (atstart && (c = rlookup(line)) != 0) { 2440 startl = 1; 2441 return (c); 2301 if (atstart) { 2302 c = rlookup(line); 2303 if (c != 0) { 2304 startl = 1; 2305 return c; 2306 } 2442 2307 } 2443 2308 2444 2309 yylval.cp = strsave(line, areanum); 2445 return (WORD);2446 } 2447 2448 2449 static int collect( REGISTER int c, REGISTERint c1)2310 return WORD; 2311 } 2312 2313 2314 static int collect(int c, int c1) 2450 2315 { 2451 2316 char s[2]; … … 2461 2326 prs("no closing "); 2462 2327 yyerror(s); 2463 return (YYERRCODE);2328 return YYERRCODE; 2464 2329 } 2465 2330 if (interactive && c == '\n' && e.iop <= iostack) { 2466 #if def CONFIG_FEATURE_COMMAND_EDITING2331 #if ENABLE_FEATURE_EDITING 2467 2332 current_prompt = cprompt->value; 2468 2333 #else … … 2477 2342 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line)); 2478 2343 2479 return (0);2344 return 0; 2480 2345 } 2481 2346 2482 2347 /* "multiline commands" helper func */ 2483 2348 /* see if next 2 chars form a shell multiline */ 2484 static int dual( REGISTERint c)2349 static int dual(int c) 2485 2350 { 2486 2351 char s[3]; 2487 REGISTERchar *cp = s;2352 char *cp = s; 2488 2353 2489 2354 DBGPRINTF8(("DUAL: enter, c=%d\n", c)); 2490 2355 2491 *cp++ = c; 2492 *cp++ = my_getc(0); 2493 *cp = 0;/* add EOS marker */2494 2495 c = rlookup(s); 2356 *cp++ = c; /* c is the given "peek" char */ 2357 *cp++ = my_getc(0); /* get next char of input */ 2358 *cp = '\0'; /* add EOS marker */ 2359 2360 c = rlookup(s); /* see if 2 chars form a shell multiline */ 2496 2361 if (c == 0) 2497 unget(*--cp); 2498 2499 return (c);/* String is multiline, return numeric multiline (restab) code */2500 } 2501 2502 static void diag( REGISTERint ec)2503 { 2504 REGISTERint c;2362 unget(*--cp); /* String is not a shell multiline, put peek char back */ 2363 2364 return c; /* String is multiline, return numeric multiline (restab) code */ 2365 } 2366 2367 static void diag(int ec) 2368 { 2369 int c; 2505 2370 2506 2371 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec)); … … 2510 2375 if (c != ec) 2511 2376 zzerr(); 2512 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;2377 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE); 2513 2378 c = my_getc(0); 2514 2379 } else 2515 yylval.i = ec == '>' ? IOWRITE : IOREAD;2380 yylval.i = (ec == '>' ? IOWRITE : IOREAD); 2516 2381 if (c != '&' || yylval.i == IOHERE) 2517 2382 unget(c); … … 2522 2387 static char *tree(unsigned size) 2523 2388 { 2524 REGISTER char *t; 2525 2526 if ((t = getcell(size)) == NULL) { 2389 char *t; 2390 2391 t = getcell(size); 2392 if (t == NULL) { 2527 2393 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size)); 2528 2394 prs("command line too complicated\n"); … … 2530 2396 /* NOTREACHED */ 2531 2397 } 2532 return (t); 2533 } 2398 return t; 2399 } 2400 2534 2401 2535 2402 /* VARARGS1 */ … … 2538 2405 /* -------- exec.c -------- */ 2539 2406 2407 static struct op **find1case(struct op *t, const char *w) 2408 { 2409 struct op *t1; 2410 struct op **tp; 2411 char **wp; 2412 char *cp; 2413 2414 if (t == NULL) { 2415 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n")); 2416 return NULL; 2417 } 2418 2419 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type, 2420 T_CMD_NAMES[t->type])); 2421 2422 if (t->type == TLIST) { 2423 tp = find1case(t->left, w); 2424 if (tp != NULL) { 2425 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp)); 2426 return tp; 2427 } 2428 t1 = t->right; /* TPAT */ 2429 } else 2430 t1 = t; 2431 2432 for (wp = t1->words; *wp;) { 2433 cp = evalstr(*wp++, DOSUB); 2434 if (cp && gmatch(w, cp)) { 2435 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n", 2436 &t1->left)); 2437 return &t1->left; 2438 } 2439 } 2440 2441 DBGPRINTF(("FIND1CASE: returning NULL\n")); 2442 return NULL; 2443 } 2444 2445 static struct op *findcase(struct op *t, const char *w) 2446 { 2447 struct op **tp; 2448 2449 tp = find1case(t, w); 2450 return tp != NULL ? *tp : NULL; 2451 } 2452 2540 2453 /* 2541 2454 * execute tree 2542 2455 */ 2543 2456 2544 2545 static int execute(REGISTER struct op *t, int *pin, int *pout, int act) 2546 { 2547 REGISTER struct op *t1; 2457 static int execute(struct op *t, int *pin, int *pout, int act) 2458 { 2459 struct op *t1; 2548 2460 volatile int i, rv, a; 2549 char *cp, **wp, **wp2; 2461 const char *cp; 2462 char **wp, **wp2; 2550 2463 struct var *vp; 2551 2464 struct op *outtree_save; … … 2559 2472 if (t == NULL) { 2560 2473 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n")); 2561 return (0);2474 return 0; 2562 2475 } 2563 2476 … … 2572 2485 : NULL; 2573 2486 2574 /* Hard to know how many words there are, be careful of garbage pointer values */2575 /* They are likely to cause "PCI bus fault" errors */2576 #if 02577 DBGPRINTF(("EXECUTE: t->left=%p, t->right=%p, t->words[1] is %s\n",2578 t->left, t->right,2579 ((t->words[1] == NULL) ? "NULL" : t->words[1])));2580 DBGPRINTF7(("EXECUTE: t->words[2] is %s, t->words[3] is %s\n",2581 ((t->words[2] == NULL) ? "NULL" : t->words[2]),2582 ((t->words[3] == NULL) ? "NULL" : t->words[3])));2583 #endif2584 2585 2586 2487 switch (t->type) { 2587 2488 case TDOT: … … 2608 2509 2609 2510 case TCOM: 2610 { 2611 rv = forkexec(t, pin, pout, act, wp); 2612 } 2511 rv = forkexec(t, pin, pout, act, wp); 2613 2512 break; 2614 2513 … … 2617 2516 int pv[2]; 2618 2517 2619 if ((rv = openpipe(pv)) < 0) 2518 rv = openpipe(pv); 2519 if (rv < 0) 2620 2520 break; 2621 2521 pv[0] = remap(pv[0]); … … 2638 2538 2639 2539 i = vfork(); 2640 if (i != 0) { 2641 interactive = hinteractive; 2642 if (i != -1) { 2643 setval(lookup("!"), putn(i)); 2644 if (pin != NULL) 2645 closepipe(pin); 2646 if (interactive) { 2647 prs(putn(i)); 2648 prs("\n"); 2649 } 2650 } else 2651 rv = -1; 2652 setstatus(rv); 2653 } else { 2540 if (i == 0) { /* child */ 2654 2541 signal(SIGINT, SIG_IGN); 2655 2542 signal(SIGQUIT, SIG_IGN); … … 2659 2546 if (pin == NULL) { 2660 2547 close(0); 2661 open(bb_dev_null, 0);2548 xopen(bb_dev_null, O_RDONLY); 2662 2549 } 2663 2550 _exit(execute(t->left, pin, pout, FEXEC)); 2664 2551 } 2552 interactive = hinteractive; 2553 if (i != -1) { 2554 setval(lookup("!"), putn(i)); 2555 if (pin != NULL) 2556 closepipe(pin); 2557 if (interactive) { 2558 prs(putn(i)); 2559 prs("\n"); 2560 } 2561 } else 2562 rv = -1; 2563 setstatus(rv); 2665 2564 } 2666 2565 break; … … 2669 2568 case TAND: 2670 2569 rv = execute(t->left, pin, pout, 0); 2671 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND)) 2570 t1 = t->right; 2571 if (t1 != NULL && (rv == 0) == (t->type == TAND)) 2672 2572 rv = execute(t1, pin, pout, 0); 2673 2573 break; … … 2676 2576 if (wp == NULL) { 2677 2577 wp = dolv + 1; 2678 if ((i = dolc) < 0) 2578 i = dolc; 2579 if (i < 0) 2679 2580 i = 0; 2680 2581 } else { … … 2716 2617 2717 2618 case TCASE: 2718 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0) 2619 cp = evalstr(t->str, DOSUB | DOTRIM); 2620 if (cp == NULL) 2719 2621 cp = ""; 2720 2622 … … 2723 2625 ((cp == NULL) ? "NULL" : cp))); 2724 2626 2725 if ((t1 = findcase(t->left, cp)) != NULL) { 2627 t1 = findcase(t->left, cp); 2628 if (t1 != NULL) { 2726 2629 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1)); 2727 2630 rv = execute(t1, pin, pout, 0); … … 2732 2635 case TBRACE: 2733 2636 /* 2734 if (iopp = t->ioact) 2637 iopp = t->ioact; 2638 if (i) 2735 2639 while (*iopp) 2736 2640 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { … … 2739 2643 } 2740 2644 */ 2741 if (rv >= 0 && (t1 = t->left)) 2742 rv = execute(t1, pin, pout, 0); 2645 if (rv >= 0) { 2646 t1 = t->left; 2647 if (t1) { 2648 rv = execute(t1, pin, pout, 0); 2649 } 2650 } 2743 2651 break; 2744 2652 2745 2653 }; 2746 2654 2747 2655 broken: 2748 2656 t->words = wp2; 2749 2657 isbreak = 0; … … 2756 2664 } 2757 2665 2758 if ((i = trapset) != 0) { 2666 i = trapset; 2667 if (i != 0) { 2759 2668 trapset = 0; 2760 2669 runtrap(i); … … 2762 2671 2763 2672 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv)); 2764 return (rv); 2765 } 2766 2767 static int 2768 forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp) 2673 return rv; 2674 } 2675 2676 typedef int (*builtin_func_ptr)(struct op *); 2677 2678 static builtin_func_ptr inbuilt(const char *s) 2679 { 2680 const struct builtincmd *bp; 2681 2682 for (bp = builtincmds; bp->name; bp++) 2683 if (strcmp(bp->name, s) == 0) 2684 return bp->builtinfunc; 2685 return NULL; 2686 } 2687 2688 static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) 2769 2689 { 2770 2690 pid_t newpid; 2771 2691 int i, rv; 2772 int (*shcom) (struct op *)= NULL;2773 REGISTERint f;2774 c har *cp = NULL;2692 builtin_func_ptr shcom = NULL; 2693 int f; 2694 const char *cp = NULL; 2775 2695 struct ioword **iopp; 2776 2696 int resetsig; … … 2802 2722 ((t->words == NULL) ? "NULL" : t->words[0]))); 2803 2723 2804 /* Hard to know how many words there are, be careful of garbage pointer values */2805 /* They are likely to cause "PCI bus fault" errors */2806 #if 02807 DBGPRINTF7(("FORKEXEC: t->words is %s, t->words[1] is %s\n",2808 ((t->words == NULL) ? "NULL" : t->words[0]),2809 ((t->words == NULL) ? "NULL" : t->words[1])));2810 DBGPRINTF7(("FORKEXEC: wp is %s, wp[1] is %s\n",2811 ((wp == NULL) ? "NULL" : wp[0]),2812 ((wp[1] == NULL) ? "NULL" : wp[1])));2813 DBGPRINTF7(("FORKEXEC: wp2 is %s, wp[3] is %s\n",2814 ((wp[2] == NULL) ? "NULL" : wp[2]),2815 ((wp[3] == NULL) ? "NULL" : wp[3])));2816 #endif2817 2818 2819 2724 owp = wp; 2820 2725 resetsig = 0; 2821 2726 rv = -1; /* system-detected error */ 2822 2727 if (t->type == TCOM) { 2823 while ((cp = *wp++) != NULL); 2728 while (*wp++ != NULL) 2729 continue; 2824 2730 cp = *wp; 2825 2731 2826 2732 /* strip all initial assignments */ 2827 2733 /* not correct wrt PATH=yyy command etc */ 2828 if ( flag['x']) {2734 if (FLAG['x']) { 2829 2735 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n", 2830 2736 cp, wp, owp)); 2831 2737 echo(cp ? wp : owp); 2832 2738 } 2833 #if 02834 DBGPRINTF9(("FORKEXEC: t->words is %s, t->words[1] is %s\n",2835 ((t->words == NULL) ? "NULL" : t->words[0]),2836 ((t->words == NULL) ? "NULL" : t->words[1])));2837 DBGPRINTF9(("FORKEXEC: wp is %s, wp[1] is %s\n",2838 ((wp == NULL) ? "NULL" : wp[0]),2839 ((wp == NULL) ? "NULL" : wp[1])));2840 #endif2841 2739 2842 2740 if (cp == NULL && t->ioact == NULL) { 2843 while ((cp = *owp++) != NULL && assign(cp, COPYV)); 2741 while ((cp = *owp++) != NULL && assign(cp, COPYV)) 2742 continue; 2844 2743 DBGPRINTF(("FORKEXEC: returning setstatus()\n")); 2845 return (setstatus(0)); 2846 } else if (cp != NULL) { 2744 return setstatus(0); 2745 } 2746 if (cp != NULL) { 2847 2747 shcom = inbuilt(cp); 2848 2748 } … … 2852 2752 f = act; 2853 2753 2854 #if 02855 DBGPRINTF3(("FORKEXEC: t->words is %s, t->words[1] is %s\n",2856 ((t->words == NULL) ? "NULL" : t->words[0]),2857 ((t->words == NULL) ? "NULL" : t->words[1])));2858 #endif2859 2754 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom, 2860 2755 f & FEXEC, owp)); … … 2875 2770 2876 2771 if (newpid == -1) { 2877 DBGPRINTF(("FORKEXEC: ERROR, unable to vfork()!\n")); 2878 return (-1); 2879 } 2880 2881 2882 if (newpid > 0) { /* Parent */ 2883 2772 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n")); 2773 return -1; 2774 } 2775 2776 if (newpid > 0) { /* Parent */ 2884 2777 /* Restore values */ 2885 2778 pin = hpin; … … 2890 2783 brklist = hbrklist; 2891 2784 execflg = hexecflg; 2892 2893 2785 /* moved up 2894 2786 if (i == -1) 2895 return (rv);2787 return rv; 2896 2788 */ 2897 2898 2789 if (pin != NULL) 2899 2790 closepipe(pin); … … 2917 2808 } 2918 2809 2919 2920 2810 if (owp != NULL) 2921 2811 while ((cp = *owp++) != NULL && assign(cp, COPYV)) … … 2928 2818 if (forked) 2929 2819 _exit(-1); 2930 return (-1);2820 return -1; 2931 2821 } 2932 2822 #endif 2933 2823 2934 2824 if (pin != NULL) { 2935 dup2(pin[0], 0);2936 closepipe(pin);2825 xmove_fd(pin[0], 0); 2826 if (pin[1] != 0) close(pin[1]); 2937 2827 } 2938 2828 if (pout != NULL) { 2939 dup2(pout[1], 1); 2940 closepipe(pout); 2941 } 2942 2943 if ((iopp = t->ioact) != NULL) { 2829 xmove_fd(pout[1], 1); 2830 if (pout[1] != 1) close(pout[0]); 2831 } 2832 2833 iopp = t->ioact; 2834 if (iopp != NULL) { 2944 2835 if (shcom != NULL && shcom != doexec) { 2945 2836 prs(cp); … … 2947 2838 if (forked) 2948 2839 _exit(-1); 2949 return (-1);2840 return -1; 2950 2841 } 2951 2842 while (*iopp) … … 2953 2844 if (forked) 2954 2845 _exit(rv); 2955 return (rv);2846 return rv; 2956 2847 } 2957 2848 } … … 2962 2853 _exit(i); 2963 2854 DBGPRINTF(("FORKEXEC: returning i=%d\n", i)); 2964 return (i);2855 return i; 2965 2856 } 2966 2857 … … 2996 2887 * within pipelines. 2997 2888 */ 2998 static int iosetup(REGISTER struct ioword *iop, int pipein, int pipeout) 2999 { 3000 REGISTER int u = -1; 3001 char *cp = NULL, *msg; 2889 static int iosetup(struct ioword *iop, int pipein, int pipeout) 2890 { 2891 int u = -1; 2892 char *cp = NULL; 2893 const char *msg; 3002 2894 3003 2895 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop, … … 3008 2900 3009 2901 if (pipein && iop->io_unit == 0) 3010 return (0);2902 return 0; 3011 2903 3012 2904 if (pipeout && iop->io_unit == 1) 3013 return (0);2905 return 0; 3014 2906 3015 2907 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create"; 3016 2908 if ((iop->io_flag & IOHERE) == 0) { 3017 cp = iop->io_name; 3018 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL) 3019 return (1); 2909 cp = iop->io_name; /* huh?? */ 2910 cp = evalstr(cp, DOSUB | DOTRIM); 2911 if (cp == NULL) 2912 return 1; 3020 2913 } 3021 2914 … … 3024 2917 prs(cp); 3025 2918 err(": illegal >& argument"); 3026 return (1);2919 return 1; 3027 2920 } 3028 2921 if (*cp == '-') … … 3032 2925 switch (iop->io_flag) { 3033 2926 case IOREAD: 3034 u = open(cp, 0);2927 u = open(cp, O_RDONLY); 3035 2928 break; 3036 2929 … … 3038 2931 case IOHERE | IOXHERE: 3039 2932 u = herein(iop->io_name, iop->io_flag & IOXHERE); 3040 cp = "here file";2933 cp = (char*)"here file"; 3041 2934 break; 3042 2935 3043 2936 case IOWRITE | IOCAT: 3044 if ((u = open(cp, 1)) >= 0) { 3045 lseek(u, (long) 0, 2); 2937 u = open(cp, O_WRONLY); 2938 if (u >= 0) { 2939 lseek(u, (long) 0, SEEK_END); 3046 2940 break; 3047 2941 } … … 3056 2950 case IOCLOSE: 3057 2951 close(iop->io_unit); 3058 return (0);2952 return 0; 3059 2953 } 3060 2954 if (u < 0) { … … 3062 2956 prs(": cannot "); 3063 2957 warn(msg); 3064 return (1); 3065 } else { 3066 if (u != iop->io_unit) { 3067 dup2(u, iop->io_unit); 3068 close(u); 3069 } 3070 } 3071 return (0); 3072 } 3073 3074 static void echo(REGISTER char **wp) 3075 { 3076 REGISTER int i; 3077 3078 prs("+"); 3079 for (i = 0; wp[i]; i++) { 3080 if (i) 3081 prs(" "); 3082 prs(wp[i]); 3083 } 3084 prs("\n"); 3085 } 3086 3087 static struct op **find1case(struct op *t, char *w) 3088 { 3089 REGISTER struct op *t1; 3090 struct op **tp; 3091 REGISTER char **wp, *cp; 3092 3093 3094 if (t == NULL) { 3095 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n")); 3096 return ((struct op **) NULL); 3097 } 3098 3099 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type, 3100 T_CMD_NAMES[t->type])); 3101 3102 if (t->type == TLIST) { 3103 if ((tp = find1case(t->left, w)) != NULL) { 3104 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp)); 3105 return (tp); 3106 } 3107 t1 = t->right; /* TPAT */ 3108 } else 3109 t1 = t; 3110 3111 for (wp = t1->words; *wp;) 3112 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) { 3113 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n", 3114 &t1->left)); 3115 return (&t1->left); 3116 } 3117 3118 DBGPRINTF(("FIND1CASE: returning NULL\n")); 3119 return ((struct op **) NULL); 3120 } 3121 3122 static struct op *findcase(struct op *t, char *w) 3123 { 3124 REGISTER struct op **tp; 3125 3126 return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL); 2958 return 1; 2959 } 2960 if (u != iop->io_unit) { 2961 dup2(u, iop->io_unit); 2962 close(u); 2963 } 2964 return 0; 3127 2965 } 3128 2966 … … 3143 2981 * unless `canintr' is true. 3144 2982 */ 3145 static int waitfor( REGISTERint lastpid, int canintr)3146 { 3147 REGISTERint pid, rv;2983 static int waitfor(int lastpid, int canintr) 2984 { 2985 int pid, rv; 3148 2986 int s; 3149 2987 int oheedint = heedint; … … 3157 2995 break; 3158 2996 } else { 3159 if ((rv = WAITSIG(s)) != 0) { 3160 if (rv < NSIGNAL) { 2997 rv = WAITSIG(s); 2998 if (rv != 0) { 2999 if (rv < ARRAY_SIZE(signame)) { 3161 3000 if (signame[rv] != NULL) { 3162 3001 if (pid != lastpid) { … … 3177 3016 if (WAITCORE(s)) 3178 3017 prs(" - core dumped"); 3179 if (rv >= NSIGNAL|| signame[rv])3018 if (rv >= ARRAY_SIZE(signame) || signame[rv]) 3180 3019 prs("\n"); 3181 3020 rv = -1; … … 3195 3034 } 3196 3035 } 3197 return (rv);3198 } 3199 3200 static int setstatus( REGISTERint s)3036 return rv; 3037 } 3038 3039 static int setstatus(int s) 3201 3040 { 3202 3041 exstat = s; 3203 3042 setval(lookup("?"), putn(s)); 3204 return (s);3043 return s; 3205 3044 } 3206 3045 … … 3210 3049 * execvp might be used. 3211 3050 */ 3212 static char *rexecve(char *c, char **v, char **envp) 3213 { 3214 REGISTER int i; 3215 REGISTER char *sp, *tp; 3051 static const char *rexecve(char *c, char **v, char **envp) 3052 { 3053 int i; 3054 const char *sp; 3055 char *tp; 3216 3056 int eacces = 0, asis = 0; 3217 3057 char *name = c; 3218 3058 3219 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) { 3220 optind = 1; 3059 if (ENABLE_FEATURE_SH_STANDALONE) { 3221 3060 if (find_applet_by_name(name)) { 3222 3061 /* We have to exec here since we vforked. Running 3223 * run_applet_ by_name() won't work and bad things3062 * run_applet_and_exit() won't work and bad things 3224 3063 * will happen. */ 3225 execve( CONFIG_BUSYBOX_EXEC_PATH, v, envp);3064 execve(bb_busybox_exec_path, v, envp); 3226 3065 } 3227 3066 } … … 3230 3069 3231 3070 sp = any('/', c) ? "" : path->value; 3232 asis = *sp == '\0';3071 asis = (*sp == '\0'); 3233 3072 while (asis || *sp != '\0') { 3234 3073 asis = 0; 3235 3074 tp = e.linep; 3236 for (; *sp != '\0'; tp++) 3237 if ((*tp = *sp++) == ':') { 3238 asis = *sp == '\0'; 3075 for (; *sp != '\0'; tp++) { 3076 *tp = *sp++; 3077 if (*tp == ':') { 3078 asis = (*sp == '\0'); 3239 3079 break; 3240 3080 } 3081 } 3241 3082 if (tp != e.linep) 3242 3083 *tp++ = '/'; … … 3254 3095 execve(DEFAULT_SHELL, v, envp); 3255 3096 *v = tp; 3256 return ("no Shell");3097 return "no Shell"; 3257 3098 3258 3099 case ENOMEM: 3259 return ( (char *) bb_msg_memory_exhausted);3100 return (char *) bb_msg_memory_exhausted; 3260 3101 3261 3102 case E2BIG: 3262 return ("argument list too long");3103 return "argument list too long"; 3263 3104 3264 3105 case EACCES: … … 3267 3108 } 3268 3109 } 3269 return (errno == ENOENT ? "not found" : "cannot execute");3110 return errno == ENOENT ? "not found" : "cannot execute"; 3270 3111 } 3271 3112 … … 3298 3139 rv = -1; 3299 3140 3300 if (newenv(setjmp(errpt = ev)) == 0) { 3141 errpt = ev; 3142 if (newenv(setjmp(errpt)) == 0) { 3301 3143 wdlist = 0; 3302 3144 iolist = 0; … … 3304 3146 e.iobase = e.iop; 3305 3147 yynerrs = 0; 3306 if (setjmp(failpt = rt) == 0 && yyparse() == 0) 3148 failpt = rt; 3149 if (setjmp(failpt) == 0 && yyparse() == 0) 3307 3150 rv = execute(outtree, NOPIPE, NOPIPE, 0); 3308 3151 quitenv(); … … 3317 3160 freearea(areanum--); 3318 3161 3319 return (rv);3162 return rv; 3320 3163 } 3321 3164 … … 3331 3174 const struct builtincmd *x; 3332 3175 3333 p rintf("\nBuilt-in commands:\n");3334 printf("-------------------\n");3335 3336 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {3337 if (!x->name)3338 continue;3339 col += printf("% s%s", ((col == 0) ? "\t" : " "), x->name);3176 puts("\nBuilt-in commands:\n" 3177 "-------------------"); 3178 3179 col = 0; 3180 x = builtincmds; 3181 while (x->name) { 3182 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name); 3340 3183 if (col > 60) { 3341 p rintf("\n");3184 puts(""); 3342 3185 col = 0; 3343 3186 } 3344 } 3345 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3187 x++; 3188 } 3189 #if ENABLE_FEATURE_SH_STANDALONE 3346 3190 { 3347 int i; 3348 const struct BB_applet *applet; 3349 extern const struct BB_applet applets[]; 3350 extern const size_t NUM_APPLETS; 3351 3352 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) { 3353 if (!applet->name) 3354 continue; 3355 3356 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name); 3191 const struct bb_applet *applet = applets; 3192 3193 while (applet->name) { 3194 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name); 3357 3195 if (col > 60) { 3358 p rintf("\n");3196 puts(""); 3359 3197 col = 0; 3360 3198 } 3199 applet++; 3361 3200 } 3362 3201 } 3363 3202 #endif 3364 p rintf("\n\n");3203 puts("\n"); 3365 3204 return EXIT_SUCCESS; 3366 3205 } 3367 3206 3368 3369 3370 3207 static int dolabel(struct op *t) 3371 3208 { 3372 return (0); 3373 } 3374 3375 static int dochdir(REGISTER struct op *t) 3376 { 3377 REGISTER char *cp, *er; 3378 3379 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) 3209 return 0; 3210 } 3211 3212 static int dochdir(struct op *t) 3213 { 3214 const char *cp, *er; 3215 3216 cp = t->words[1]; 3217 if (cp == NULL) { 3218 cp = homedir->value; 3219 if (cp != NULL) 3220 goto do_cd; 3380 3221 er = ": no home directory"; 3381 else if (chdir(cp) < 0) 3222 } else { 3223 do_cd: 3224 if (chdir(cp) >= 0) 3225 return 0; 3382 3226 er = ": bad directory"; 3383 else 3384 return (0); 3227 } 3385 3228 prs(cp != NULL ? cp : "cd"); 3386 3229 err(er); 3387 return (1);3388 } 3389 3390 static int doshift( REGISTERstruct op *t)3391 { 3392 REGISTERint n;3230 return 1; 3231 } 3232 3233 static int doshift(struct op *t) 3234 { 3235 int n; 3393 3236 3394 3237 n = t->words[1] ? getn(t->words[1]) : 1; 3395 3238 if (dolc < n) { 3396 3239 err("nothing to shift"); 3397 return (1);3240 return 1; 3398 3241 } 3399 3242 dolv[n] = dolv[0]; … … 3401 3244 dolc -= n; 3402 3245 setval(lookup("#"), putn(dolc)); 3403 return (0);3246 return 0; 3404 3247 } 3405 3248 … … 3409 3252 static int dologin(struct op *t) 3410 3253 { 3411 REGISTERchar *cp;3254 const char *cp; 3412 3255 3413 3256 if (interactive) { … … 3419 3262 prs(": "); 3420 3263 err(cp); 3421 return (1); 3422 } 3423 3424 static int doumask(REGISTER struct op *t) 3425 { 3426 REGISTER int i, n; 3427 REGISTER char *cp; 3428 3429 if ((cp = t->words[1]) == NULL) { 3264 return 1; 3265 } 3266 3267 static int doumask(struct op *t) 3268 { 3269 int i, n; 3270 char *cp; 3271 3272 cp = t->words[1]; 3273 if (cp == NULL) { 3430 3274 i = umask(0); 3431 3275 umask(i); … … 3434 3278 putc('\n', stderr); 3435 3279 } else { 3280 /* huh??? '8','9' are not allowed! */ 3436 3281 for (n = 0; *cp >= '0' && *cp <= '9'; cp++) 3437 3282 n = n * 8 + (*cp - '0'); 3438 3283 umask(n); 3439 3284 } 3440 return (0);3441 } 3442 3443 static int doexec( REGISTERstruct op *t)3444 { 3445 REGISTERint i;3285 return 0; 3286 } 3287 3288 static int doexec(struct op *t) 3289 { 3290 int i; 3446 3291 jmp_buf ex; 3447 3292 xint *ofail; … … 3450 3295 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++); 3451 3296 if (i == 0) 3452 return (1);3297 return 1; 3453 3298 execflg = 1; 3454 3299 ofail = failpt; 3455 if (setjmp(failpt = ex) == 0) 3300 failpt = ex; 3301 if (setjmp(failpt) == 0) 3456 3302 execute(t, NOPIPE, NOPIPE, FEXEC); 3457 3303 failpt = ofail; 3458 3304 execflg = 0; 3459 return (1);3305 return 1; 3460 3306 } 3461 3307 3462 3308 static int dodot(struct op *t) 3463 3309 { 3464 REGISTER int i; 3465 REGISTER char *sp, *tp; 3310 int i; 3311 const char *sp; 3312 char *tp; 3466 3313 char *cp; 3467 3314 int maltmp; … … 3469 3316 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep))); 3470 3317 3471 if ((cp = t->words[1]) == NULL) { 3318 cp = t->words[1]; 3319 if (cp == NULL) { 3472 3320 DBGPRINTF(("DODOT: bad args, ret 0\n")); 3473 return (0); 3474 } else { 3475 DBGPRINTF(("DODOT: cp is %s\n", cp)); 3476 } 3321 return 0; 3322 } 3323 DBGPRINTF(("DODOT: cp is %s\n", cp)); 3477 3324 3478 3325 sp = any('/', cp) ? ":" : path->value; … … 3492 3339 3493 3340 /* Original code */ 3494 if ((i = open(e.linep, 0)) >= 0) { 3341 i = open(e.linep, O_RDONLY); 3342 if (i >= 0) { 3495 3343 exstat = 0; 3496 3344 maltmp = remap(i); … … 3501 3349 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat)); 3502 3350 3503 return (exstat); 3504 } 3505 3506 } /* While */ 3351 return exstat; 3352 } 3353 } /* while */ 3507 3354 3508 3355 prs(cp); 3509 3356 err(": not found"); 3510 3357 3511 return (-1);3358 return -1; 3512 3359 } 3513 3360 3514 3361 static int dowait(struct op *t) 3515 3362 { 3516 REGISTER int i; 3517 REGISTER char *cp; 3518 3519 if ((cp = t->words[1]) != NULL) { 3363 int i; 3364 char *cp; 3365 3366 cp = t->words[1]; 3367 if (cp != NULL) { 3520 3368 i = getn(cp); 3521 3369 if (i == 0) 3522 return (0);3370 return 0; 3523 3371 } else 3524 3372 i = -1; 3525 3373 setstatus(waitfor(i, 1)); 3526 return (0);3374 return 0; 3527 3375 } 3528 3376 3529 3377 static int doread(struct op *t) 3530 3378 { 3531 REGISTERchar *cp, **wp;3532 REGISTERint nb = 0;3533 REGISTERint nl = 0;3379 char *cp, **wp; 3380 int nb = 0; 3381 int nl = 0; 3534 3382 3535 3383 if (t->words[1] == NULL) { 3536 3384 err("Usage: read name ..."); 3537 return (1);3385 return 1; 3538 3386 } 3539 3387 for (wp = t->words + 1; *wp; wp++) { 3540 for (cp = e.linep; !nl && cp < elinep - 1; cp++) 3541 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||3542 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))3388 for (cp = e.linep; !nl && cp < elinep - 1; cp++) { 3389 nb = read(0, cp, sizeof(*cp)); 3390 if (nb != sizeof(*cp)) 3543 3391 break; 3544 *cp = 0; 3392 nl = (*cp == '\n'); 3393 if (nl || (wp[1] && any(*cp, ifs->value))) 3394 break; 3395 } 3396 *cp = '\0'; 3545 3397 if (nb <= 0) 3546 3398 break; 3547 3399 setval(lookup(*wp), e.linep); 3548 3400 } 3549 return (nb <= 0);3550 } 3551 3552 static int doeval( REGISTERstruct op *t)3553 { 3554 return (RUN(awordlist, t->words + 1, wdchar));3555 } 3556 3557 static int dotrap( REGISTERstruct op *t)3558 { 3559 REGISTERint n, i;3560 REGISTERint resetsig;3401 return nb <= 0; 3402 } 3403 3404 static int doeval(struct op *t) 3405 { 3406 return RUN(awordlist, t->words + 1, wdchar); 3407 } 3408 3409 static int dotrap(struct op *t) 3410 { 3411 int n, i; 3412 int resetsig; 3561 3413 3562 3414 if (t->words[1] == NULL) { … … 3568 3420 prs("\n"); 3569 3421 } 3570 return (0);3422 return 0; 3571 3423 } 3572 3424 resetsig = isdigit(*t->words[1]); … … 3582 3434 setsig(n, SIG_IGN); 3583 3435 } else { 3584 if (interactive) 3436 if (interactive) { 3585 3437 if (n == SIGINT) 3586 3438 setsig(n, onintr); 3587 3439 else 3588 3440 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); 3589 else3441 } else 3590 3442 setsig(n, SIG_DFL); 3591 3443 } 3592 3444 } 3593 return (0);3445 return 0; 3594 3446 } 3595 3447 3596 3448 static int getsig(char *s) 3597 3449 { 3598 REGISTER int n; 3599 3600 if ((n = getn(s)) < 0 || n > _NSIG) { 3450 int n; 3451 3452 n = getn(s); 3453 if (n < 0 || n > _NSIG) { 3601 3454 err("trap: bad signal number"); 3602 3455 n = 0; 3603 3456 } 3604 return (n);3605 } 3606 3607 static void setsig( REGISTERint n, sighandler_t f)3457 return n; 3458 } 3459 3460 static void setsig(int n, sighandler_t f) 3608 3461 { 3609 3462 if (n == 0) … … 3617 3470 static int getn(char *as) 3618 3471 { 3619 REGISTERchar *s;3620 REGISTERint n, m;3472 char *s; 3473 int n, m; 3621 3474 3622 3475 s = as; … … 3632 3485 err(": bad number"); 3633 3486 } 3634 return (n * m);3487 return n * m; 3635 3488 } 3636 3489 3637 3490 static int dobreak(struct op *t) 3638 3491 { 3639 return (brkcontin(t->words[1], 1));3492 return brkcontin(t->words[1], 1); 3640 3493 } 3641 3494 3642 3495 static int docontinue(struct op *t) 3643 3496 { 3644 return (brkcontin(t->words[1], 0));3645 } 3646 3647 static int brkcontin( REGISTERchar *cp, int val)3648 { 3649 REGISTERstruct brkcon *bc;3650 REGISTERint nl;3497 return brkcontin(t->words[1], 0); 3498 } 3499 3500 static int brkcontin(char *cp, int val) 3501 { 3502 struct brkcon *bc; 3503 int nl; 3651 3504 3652 3505 nl = cp == NULL ? 1 : getn(cp); … … 3654 3507 nl = 999; 3655 3508 do { 3656 if ((bc = brklist) == NULL) 3509 bc = brklist; 3510 if (bc == NULL) 3657 3511 break; 3658 3512 brklist = bc->nextlev; … … 3660 3514 if (nl) { 3661 3515 err("bad break/continue level"); 3662 return (1);3516 return 1; 3663 3517 } 3664 3518 isbreak = val; … … 3669 3523 static int doexit(struct op *t) 3670 3524 { 3671 REGISTERchar *cp;3525 char *cp; 3672 3526 3673 3527 execflg = 0; 3674 if ((cp = t->words[1]) != NULL) 3528 cp = t->words[1]; 3529 if (cp != NULL) 3675 3530 setstatus(getn(cp)); 3676 3531 … … 3679 3534 leave(); 3680 3535 /* NOTREACHED */ 3681 return (0);3536 return 0; 3682 3537 } 3683 3538 … … 3685 3540 { 3686 3541 rdexp(t->words + 1, export, EXPORT); 3687 return (0);3542 return 0; 3688 3543 } 3689 3544 … … 3691 3546 { 3692 3547 rdexp(t->words + 1, ronly, RONLY); 3693 return (0);3548 return 0; 3694 3549 } 3695 3550 … … 3717 3572 } 3718 3573 3719 static void badid( REGISTERchar *s)3574 static void badid(char *s) 3720 3575 { 3721 3576 prs(s); … … 3723 3578 } 3724 3579 3725 static int doset(REGISTER struct op *t) 3726 { 3727 REGISTER struct var *vp; 3728 REGISTER char *cp; 3729 REGISTER int n; 3730 3731 if ((cp = t->words[1]) == NULL) { 3580 static int doset(struct op *t) 3581 { 3582 struct var *vp; 3583 char *cp; 3584 int n; 3585 3586 cp = t->words[1]; 3587 if (cp == NULL) { 3732 3588 for (vp = vlist; vp; vp = vp->next) 3733 3589 varput(vp->name, 1); 3734 return (0);3590 return 0; 3735 3591 } 3736 3592 if (*cp == '-') { … … 3738 3594 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++); 3739 3595 if (*++cp == 0) 3740 flag['x'] = flag['v'] = 0;3741 else 3742 for (; *cp; cp++) 3596 FLAG['x'] = FLAG['v'] = 0; 3597 else { 3598 for (; *cp; cp++) { 3743 3599 switch (*cp) { 3744 3600 case 'e': 3745 3601 if (!interactive) 3746 flag['e']++;3602 FLAG['e']++; 3747 3603 break; 3748 3604 3749 3605 default: 3750 3606 if (*cp >= 'a' && *cp <= 'z') 3751 flag[(int) *cp]++;3607 FLAG[(int) *cp]++; 3752 3608 break; 3753 3609 } 3610 } 3611 } 3754 3612 setdash(); 3755 3613 } … … 3763 3621 setarea((char *) (dolv - 1), 0); 3764 3622 } 3765 return (0);3766 } 3767 3768 static void varput( REGISTERchar *s, int out)3623 return 0; 3624 } 3625 3626 static void varput(char *s, int out) 3769 3627 { 3770 3628 if (isalnum(*s) || *s == '_') { … … 3782 3640 { 3783 3641 struct tms buf; 3784 long intclk_tck = sysconf(_SC_CLK_TCK);3642 long clk_tck = sysconf(_SC_CLK_TCK); 3785 3643 3786 3644 times(&buf); … … 3798 3656 3799 3657 3800 static int (*inbuilt(char *s)) (struct op *) {3801 const struct builtincmd *bp;3802 3803 for (bp = builtincmds; bp->name != NULL; bp++)3804 if (strcmp(bp->name, s) == 0)3805 return (bp->builtinfunc);3806 3807 return (NULL);3808 }3809 3810 3658 /* -------- eval.c -------- */ 3811 3659 … … 3836 3684 wb = NULL; 3837 3685 wf = NULL; 3838 if (newenv(setjmp(errpt = ev)) == 0) { 3686 errpt = ev; 3687 if (newenv(setjmp(errpt)) == 0) { 3839 3688 while (*ap && isassign(*ap)) 3840 3689 expand(*ap++, &wb, f & ~DOGLOB); 3841 if ( flag['k']) {3690 if (FLAG['k']) { 3842 3691 for (wf = ap; *wf; wf++) { 3843 3692 if (isassign(*wf)) … … 3846 3695 } 3847 3696 for (wb = addword((char *) 0, wb); *ap; ap++) { 3848 if (! flag['k'] || !isassign(*ap))3697 if (!FLAG['k'] || !isassign(*ap)) 3849 3698 expand(*ap, &wb, f & ~DOKEY); 3850 3699 } … … 3855 3704 gflg = 1; 3856 3705 3857 return (gflg ? (char **) NULL : wp); 3858 } 3706 return gflg ? (char **) NULL : wp; 3707 } 3708 3859 3709 3860 3710 /* … … 3865 3715 static char **makenv(int all, struct wdblock *wb) 3866 3716 { 3867 REGISTERstruct var *vp;3717 struct var *vp; 3868 3718 3869 3719 DBGPRINTF5(("MAKENV: enter, all=%d\n", all)); … … 3873 3723 wb = addword(vp->name, wb); 3874 3724 wb = addword((char *) 0, wb); 3875 return (getwords(wb)); 3876 } 3877 3878 static char *evalstr(REGISTER char *cp, int f) 3879 { 3880 struct wdblock *wb; 3881 3882 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f)); 3883 3884 wb = NULL; 3885 if (expand(cp, &wb, f)) { 3886 if (wb == NULL || wb->w_nword == 0 3887 || (cp = wb->w_words[0]) == NULL) 3888 cp = ""; 3889 DELETE(wb); 3890 } else 3891 cp = NULL; 3892 return (cp); 3893 } 3894 3895 static int expand(char *cp, REGISTER struct wdblock **wbp, int f) 3725 return getwords(wb); 3726 } 3727 3728 static int expand(const char *cp, struct wdblock **wbp, int f) 3896 3729 { 3897 3730 jmp_buf ev; 3731 char *xp; 3898 3732 3899 3733 #if __GNUC__ … … 3907 3741 3908 3742 if (cp == NULL) 3909 return (0); 3910 3911 if (!anys("$`'\"", cp) && 3912 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) { 3913 cp = strsave(cp, areanum); 3743 return 0; 3744 3745 if (!anys("$`'\"", cp) && !anys(ifs->value, cp) 3746 && ((f & DOGLOB) == 0 || !anys("[*?", cp)) 3747 ) { 3748 xp = strsave(cp, areanum); 3914 3749 if (f & DOTRIM) 3915 unquote(cp); 3916 *wbp = addword(cp, *wbp); 3917 return (1); 3918 } 3919 if (newenv(setjmp(errpt = ev)) == 0) { 3750 unquote(xp); 3751 *wbp = addword(xp, *wbp); 3752 return 1; 3753 } 3754 errpt = ev; 3755 if (newenv(setjmp(errpt)) == 0) { 3920 3756 PUSHIO(aword, cp, strchar); 3921 3757 e.iobase = e.iop; 3922 while (( cp = blank(f)) && gflg == 0) {3923 e.linep = cp;3924 cp = strsave(cp, areanum);3758 while ((xp = blank(f)) && gflg == 0) { 3759 e.linep = xp; 3760 xp = strsave(xp, areanum); 3925 3761 if ((f & DOGLOB) == 0) { 3926 3762 if (f & DOTRIM) 3927 unquote( cp);3928 *wbp = addword( cp, *wbp);3763 unquote(xp); 3764 *wbp = addword(xp, *wbp); 3929 3765 } else 3930 *wbp = glob( cp, *wbp);3766 *wbp = glob(xp, *wbp); 3931 3767 } 3932 3768 quitenv(); 3933 3769 } else 3934 3770 gflg = 1; 3935 return (gflg == 0); 3936 } 3771 return gflg == 0; 3772 } 3773 3774 static char *evalstr(char *cp, int f) 3775 { 3776 struct wdblock *wb; 3777 3778 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f)); 3779 3780 wb = NULL; 3781 if (expand(cp, &wb, f)) { 3782 if (wb == NULL || wb->w_nword == 0 3783 || (cp = wb->w_words[0]) == NULL 3784 ) { 3785 // TODO: I suspect that 3786 // char *evalstr(char *cp, int f) is actually 3787 // const char *evalstr(const char *cp, int f)! 3788 cp = (char*)""; 3789 } 3790 DELETE(wb); 3791 } else 3792 cp = NULL; 3793 return cp; 3794 } 3795 3937 3796 3938 3797 /* … … 3941 3800 static char *blank(int f) 3942 3801 { 3943 REGISTERint c, c1;3944 REGISTERchar *sp;3802 int c, c1; 3803 char *sp; 3945 3804 int scanequals, foundequals; 3946 3805 … … 3951 3810 foundequals = 0; 3952 3811 3953 loop: 3954 switch (c = subgetc('"', foundequals)) { 3812 loop: 3813 c = subgetc('"', foundequals); 3814 switch (c) { 3955 3815 case 0: 3956 3816 if (sp == e.linep) 3957 return (0);3817 return 0; 3958 3818 *e.linep++ = 0; 3959 return (sp);3819 return sp; 3960 3820 3961 3821 default: … … 4002 3862 } 4003 3863 *e.linep++ = 0; 4004 return (sp);3864 return sp; 4005 3865 } 4006 3866 … … 4008 3868 * Get characters, substituting for ` and $ 4009 3869 */ 4010 static int subgetc( REGISTERchar ec, int quoted)4011 { 4012 REGISTERchar c;3870 static int subgetc(char ec, int quoted) 3871 { 3872 char c; 4013 3873 4014 3874 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted)); 4015 3875 4016 3876 again: 4017 3877 c = my_getc(ec); 4018 3878 if (!INSUB() && ec != '\'') { 4019 3879 if (c == '`') { 4020 3880 if (grave(quoted) == 0) 4021 return (0);3881 return 0; 4022 3882 e.iop->task = XGRAVE; 4023 3883 goto again; 4024 3884 } 4025 if (c == '$' && (c = dollar(quoted)) == 0) { 4026 e.iop->task = XDOLL; 4027 goto again; 4028 } 4029 } 4030 return (c); 3885 if (c == '$') { 3886 c = dollar(quoted); 3887 if (c == 0) { 3888 e.iop->task = XDOLL; 3889 goto again; 3890 } 3891 } 3892 } 3893 return c; 4031 3894 } 4032 3895 … … 4039 3902 struct io *oiop; 4040 3903 char *dolp; 4041 REGISTERchar *s, c, *cp = NULL;3904 char *s, c, *cp = NULL; 4042 3905 struct var *vp; 4043 3906 … … 4068 3931 err("unclosed ${"); 4069 3932 gflg++; 4070 return (c);3933 return c; 4071 3934 } 4072 3935 } … … 4090 3953 e.linep = s; 4091 3954 PUSHIO(awordlist, dolv + 1, dolchar); 4092 return (0);3955 return 0; 4093 3956 } else { /* trap the nasty ${=} */ 4094 3957 s[0] = '1'; 4095 s[1] = 0;3958 s[1] = '\0'; 4096 3959 } 4097 3960 } 4098 3961 vp = lookup(s); 4099 if ((dolp = vp->value) == null) { 3962 dolp = vp->value; 3963 if (dolp == null) { 4100 3964 switch (c) { 4101 3965 case '=': … … 4124 3988 } else if (c == '+') 4125 3989 dolp = strsave(cp, areanum); 4126 if ( flag['u'] && dolp == null) {3990 if (FLAG['u'] && dolp == null) { 4127 3991 prs("unset variable: "); 4128 3992 err(s); … … 4131 3995 e.linep = s; 4132 3996 PUSHIO(aword, dolp, quoted ? qstrchar : strchar); 4133 return (0);3997 return 0; 4134 3998 } 4135 3999 … … 4140 4004 static int grave(int quoted) 4141 4005 { 4142 char *cp; 4143 REGISTER int i; 4006 /* moved to G: static char child_cmd[LINELIM]; */ 4007 4008 const char *cp; 4009 int i; 4144 4010 int j; 4145 4011 int pf[2]; 4146 static char child_cmd[LINELIM]; 4147 char *src; 4012 const char *src; 4148 4013 char *dest; 4149 4014 int count; … … 4158 4023 #endif 4159 4024 4160 for (cp = e.iop->argp->aword; *cp != '`'; cp++) 4025 for (cp = e.iop->argp->aword; *cp != '`'; cp++) { 4161 4026 if (*cp == 0) { 4162 4027 err("no closing `"); 4163 return (0); 4164 } 4028 return 0; 4029 } 4030 } 4165 4031 4166 4032 /* string copy with dollar expansion */ … … 4208 4074 default: 4209 4075 err("unclosed ${\n"); 4210 return (0);4076 return 0; 4211 4077 } 4212 4078 if (operator) { … … 4218 4084 if (*src != '}') { 4219 4085 err("unclosed ${\n"); 4220 return (0);4086 return 0; 4221 4087 } 4222 4088 } … … 4253 4119 else if (operator == '?') { 4254 4120 err(alt_value); 4255 return (0);4121 return 0; 4256 4122 } else if (alt_index && (operator != '+')) { 4257 4123 value = alt_value; … … 4275 4141 4276 4142 if (openpipe(pf) < 0) 4277 return (0);4143 return 0; 4278 4144 4279 4145 while ((i = vfork()) == -1 && errno == EAGAIN); … … 4284 4150 closepipe(pf); 4285 4151 err((char *) bb_msg_memory_exhausted); 4286 return (0);4152 return 0; 4287 4153 } 4288 4154 if (i != 0) { … … 4291 4157 close(pf[1]); 4292 4158 PUSHIO(afile, remap(pf[0]), 4293 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : 4294 gravechar)); 4295 return (1); 4159 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar)); 4160 return 1; 4296 4161 } 4297 4162 /* allow trapped signals */ … … 4301 4166 signal(j, SIG_DFL); 4302 4167 4303 dup2(pf[1], 1); 4304 closepipe(pf); 4168 /* Testcase where below checks are needed: 4169 * close stdout & run this script: 4170 * files=`ls` 4171 * echo "$files" >zz 4172 */ 4173 xmove_fd(pf[1], 1); 4174 if (pf[0] != 1) close(pf[0]); 4305 4175 4306 4176 argument_list[0] = (char *) DEFAULT_SHELL; 4307 argument_list[1] = "-c";4177 argument_list[1] = (char *) "-c"; 4308 4178 argument_list[2] = child_cmd; 4309 argument_list[3] = 0;4179 argument_list[3] = NULL; 4310 4180 4311 4181 cp = rexecve(argument_list[0], argument_list, makenv(1, wb)); … … 4317 4187 4318 4188 4319 static char *unquote(REGISTER char *as) 4320 { 4321 REGISTER char *s; 4322 4323 if ((s = as) != NULL) 4189 static char *unquote(char *as) 4190 { 4191 char *s; 4192 4193 s = as; 4194 if (s != NULL) 4324 4195 while (*s) 4325 4196 *s++ &= ~QUOTE; 4326 return (as);4197 return as; 4327 4198 } 4328 4199 … … 4338 4209 4339 4210 static struct wdblock *cl, *nl; 4340 static c har spcl[]= "[?*";4211 static const char spcl[] ALIGN1= "[?*"; 4341 4212 4342 4213 static struct wdblock *glob(char *cp, struct wdblock *wb) 4343 4214 { 4344 REGISTERint i;4345 REGISTERchar *pp;4215 int i; 4216 char *pp; 4346 4217 4347 4218 if (cp == 0) 4348 return (wb);4219 return wb; 4349 4220 i = 0; 4350 4221 for (pp = cp; *pp; pp++) … … 4354 4225 *pp &= ~QUOTE; 4355 4226 if (i != 0) { 4356 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl); 4357 cl = nl) { 4227 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) { 4358 4228 nl = newword(cl->w_nword * 2); 4359 4229 for (i = 0; i < cl->w_nword; i++) { /* for each argument */ … … 4377 4247 wb = addword(cl->w_words[i], wb); 4378 4248 DELETE(cl); 4379 return (wb);4249 return wb; 4380 4250 } 4381 4251 } 4382 4252 wb = addword(unquote(cp), wb); 4383 return (wb);4384 } 4385 4386 static void globname(char *we, REGISTERchar *pp)4387 { 4388 REGISTERchar *np, *cp;4253 return wb; 4254 } 4255 4256 static void globname(char *we, char *pp) 4257 { 4258 char *np, *cp; 4389 4259 char *name, *gp, *dp; 4390 4260 int k; … … 4415 4285 /* 4416 4286 if (ent[j].d_ino == 0) 4417 continue;4287 continue; 4418 4288 */ 4419 4289 strncpy(dname, de->d_name, NAME_MAX); … … 4445 4315 * the slashes come for free 4446 4316 */ 4447 static char *generate(char *start1, REGISTERchar *end1, char *middle, char *end)4317 static char *generate(char *start1, char *end1, char *middle, char *end) 4448 4318 { 4449 4319 char *p; 4450 REGISTER char *op, *xp; 4451 4452 p = op = 4453 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2); 4320 char *op, *xp; 4321 4322 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2); 4454 4323 for (xp = start1; xp != end1;) 4455 4324 *op++ = *xp++; … … 4457 4326 op--; 4458 4327 for (xp = end; (*op++ = *xp++) != '\0';); 4459 return (p);4460 } 4461 4462 static int anyspcl( REGISTERstruct wdblock *wb)4463 { 4464 REGISTERint i;4465 REGISTERchar **wd;4328 return p; 4329 } 4330 4331 static int anyspcl(struct wdblock *wb) 4332 { 4333 int i; 4334 char **wd; 4466 4335 4467 4336 wd = wb->w_words; 4468 4337 for (i = 0; i < wb->w_nword; i++) 4469 4338 if (anys(spcl, *wd++)) 4470 return (1);4471 return (0);4339 return 1; 4340 return 0; 4472 4341 } 4473 4342 4474 4343 static int xstrcmp(char *p1, char *p2) 4475 4344 { 4476 return (strcmp(*(char **) p1, *(char **) p2)); 4477 } 4345 return strcmp(*(char **) p1, *(char **) p2); 4346 } 4347 4478 4348 4479 4349 /* -------- word.c -------- */ 4480 4350 4481 static struct wdblock *newword( REGISTERint nw)4482 { 4483 REGISTERstruct wdblock *wb;4351 static struct wdblock *newword(int nw) 4352 { 4353 struct wdblock *wb; 4484 4354 4485 4355 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *)); 4486 4356 wb->w_bsize = nw; 4487 4357 wb->w_nword = 0; 4488 return (wb);4489 } 4490 4491 static struct wdblock *addword(char *wd, REGISTERstruct wdblock *wb)4492 { 4493 REGISTERstruct wdblock *wb2;4494 REGISTERint nw;4358 return wb; 4359 } 4360 4361 static struct wdblock *addword(char *wd, struct wdblock *wb) 4362 { 4363 struct wdblock *wb2; 4364 int nw; 4495 4365 4496 4366 if (wb == NULL) 4497 4367 wb = newword(NSTART); 4498 if ((nw = wb->w_nword) >= wb->w_bsize) { 4368 nw = wb->w_nword; 4369 if (nw >= wb->w_bsize) { 4499 4370 wb2 = newword(nw * 2); 4500 4371 memcpy((char *) wb2->w_words, (char *) wb->w_words, … … 4505 4376 } 4506 4377 wb->w_words[wb->w_nword++] = wd; 4507 return (wb); 4508 } 4509 4510 static 4511 char **getwords(REGISTER struct wdblock *wb) 4512 { 4513 REGISTER char **wd; 4514 REGISTER int nb; 4378 return wb; 4379 } 4380 4381 static char **getwords(struct wdblock *wb) 4382 { 4383 char **wd; 4384 int nb; 4515 4385 4516 4386 if (wb == NULL) 4517 return ((char **) NULL);4387 return NULL; 4518 4388 if (wb->w_nword == 0) { 4519 4389 DELETE(wb); 4520 return ((char **) NULL);4390 return NULL; 4521 4391 } 4522 4392 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword); 4523 4393 memcpy((char *) wd, (char *) wb->w_words, nb); 4524 4394 DELETE(wb); /* perhaps should done by caller */ 4525 return (wd);4395 return wd; 4526 4396 } 4527 4397 … … 4529 4399 static int globv; 4530 4400 4531 static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))4532 {4533 func = a3;4534 globv = a2;4535 glob1(a0, a0 + a1 * a2);4536 }4537 4538 static void glob1(char *base, char *lim)4539 {4540 REGISTER char *i, *j;4541 int v2;4542 char *lptr, *hptr;4543 int c;4544 unsigned n;4545 4546 4547 v2 = globv;4548 4549 top:4550 if ((n = (int) (lim - base)) <= v2)4551 return;4552 n = v2 * (n / (2 * v2));4553 hptr = lptr = base + n;4554 i = base;4555 j = lim - v2;4556 for (;;) {4557 if (i < lptr) {4558 if ((c = (*func) (i, lptr)) == 0) {4559 glob2(i, lptr -= v2);4560 continue;4561 }4562 if (c < 0) {4563 i += v2;4564 continue;4565 }4566 }4567 4568 begin:4569 if (j > hptr) {4570 if ((c = (*func) (hptr, j)) == 0) {4571 glob2(hptr += v2, j);4572 goto begin;4573 }4574 if (c > 0) {4575 if (i == lptr) {4576 glob3(i, hptr += v2, j);4577 i = lptr += v2;4578 goto begin;4579 }4580 glob2(i, j);4581 j -= v2;4582 i += v2;4583 continue;4584 }4585 j -= v2;4586 goto begin;4587 }4588 4589 4590 if (i == lptr) {4591 if (lptr - base >= lim - hptr) {4592 glob1(hptr + v2, lim);4593 lim = lptr;4594 } else {4595 glob1(base, lptr);4596 base = hptr + v2;4597 }4598 goto top;4599 }4600 4601 4602 glob3(j, lptr -= v2, i);4603 j = hptr -= v2;4604 }4605 }4606 4607 static void glob2(char *i, char *j)4608 {4609 REGISTER char *index1, *index2, c;4610 int m;4611 4612 m = globv;4613 index1 = i;4614 index2 = j;4615 do {4616 c = *index1;4617 *index1++ = *index2;4618 *index2++ = c;4619 } while (--m);4620 }4621 4622 4401 static void glob3(char *i, char *j, char *k) 4623 4402 { 4624 REGISTERchar *index1, *index2, *index3;4403 char *index1, *index2, *index3; 4625 4404 int c; 4626 4405 int m; … … 4638 4417 } 4639 4418 4419 static void glob2(char *i, char *j) 4420 { 4421 char *index1, *index2, c; 4422 int m; 4423 4424 m = globv; 4425 index1 = i; 4426 index2 = j; 4427 do { 4428 c = *index1; 4429 *index1++ = *index2; 4430 *index2++ = c; 4431 } while (--m); 4432 } 4433 4434 static void glob1(char *base, char *lim) 4435 { 4436 char *i, *j; 4437 int v2; 4438 char *lptr, *hptr; 4439 int c; 4440 unsigned n; 4441 4442 v2 = globv; 4443 4444 top: 4445 n = (int) (lim - base); 4446 if (n <= v2) 4447 return; 4448 n = v2 * (n / (2 * v2)); 4449 hptr = lptr = base + n; 4450 i = base; 4451 j = lim - v2; 4452 for (;;) { 4453 if (i < lptr) { 4454 c = (*func) (i, lptr); 4455 if (c == 0) { 4456 lptr -= v2; 4457 glob2(i, lptr); 4458 continue; 4459 } 4460 if (c < 0) { 4461 i += v2; 4462 continue; 4463 } 4464 } 4465 4466 begin: 4467 if (j > hptr) { 4468 c = (*func) (hptr, j); 4469 if (c == 0) { 4470 hptr += v2; 4471 glob2(hptr, j); 4472 goto begin; 4473 } 4474 if (c > 0) { 4475 if (i == lptr) { 4476 hptr += v2; 4477 glob3(i, hptr, j); 4478 i = (lptr += v2); 4479 goto begin; 4480 } 4481 glob2(i, j); 4482 j -= v2; 4483 i += v2; 4484 continue; 4485 } 4486 j -= v2; 4487 goto begin; 4488 } 4489 4490 4491 if (i == lptr) { 4492 if (lptr - base >= lim - hptr) { 4493 glob1(hptr + v2, lim); 4494 lim = lptr; 4495 } else { 4496 glob1(base, lptr); 4497 base = hptr + v2; 4498 } 4499 goto top; 4500 } 4501 4502 lptr -= v2; 4503 glob3(j, lptr, i); 4504 j = (hptr -= v2); 4505 } 4506 } 4507 4508 static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *)) 4509 { 4510 func = a3; 4511 globv = a2; 4512 glob1(a0, a0 + a1 * a2); 4513 } 4514 4515 4640 4516 /* -------- io.c -------- */ 4641 4517 … … 4646 4522 static int my_getc(int ec) 4647 4523 { 4648 REGISTERint c;4524 int c; 4649 4525 4650 4526 if (e.linep > elinep) { … … 4652 4528 err("input line too long"); 4653 4529 gflg++; 4654 return (c);4530 return c; 4655 4531 } 4656 4532 c = readc(); … … 4659 4535 c = readc(); 4660 4536 if (c == '\n' && ec != '\"') 4661 return (my_getc(ec));4537 return my_getc(ec); 4662 4538 c |= QUOTE; 4663 4539 } 4664 4540 } 4665 return (c);4541 return c; 4666 4542 } 4667 4543 … … 4679 4555 static int readc(void) 4680 4556 { 4681 REGISTERint c;4557 int c; 4682 4558 4683 4559 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase)); … … 4685 4561 for (; e.iop >= e.iobase; e.iop--) { 4686 4562 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc)); 4687 if ((c = e.iop->peekc) != '\0') { 4563 c = e.iop->peekc; 4564 if (c != '\0') { 4688 4565 e.iop->peekc = 0; 4689 return (c); 4690 } else { 4691 if (e.iop->prev != 0) { 4692 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') { 4693 if (c == -1) { 4694 e.iop++; 4695 continue; 4696 } 4697 if (e.iop == iostack) 4698 ioecho(c); 4699 return (e.iop->prev = c); 4700 } else if (e.iop->task == XIO && e.iop->prev != '\n') { 4701 e.iop->prev = 0; 4702 if (e.iop == iostack) 4703 ioecho('\n'); 4704 return '\n'; 4566 return c; 4567 } 4568 if (e.iop->prev != 0) { 4569 c = (*e.iop->iofn)(e.iop->argp, e.iop); 4570 if (c != '\0') { 4571 if (c == -1) { 4572 e.iop++; 4573 continue; 4705 4574 } 4575 if (e.iop == iostack) 4576 ioecho(c); 4577 e.iop->prev = c; 4578 return e.iop->prev; 4706 4579 } 4707 if (e.iop->task == XIO) { 4708 if (multiline) { 4709 return e.iop->prev = 0; 4710 } 4711 if (interactive && e.iop == iostack + 1) { 4712 #ifdef CONFIG_FEATURE_COMMAND_EDITING 4713 current_prompt = prompt->value; 4580 if (e.iop->task == XIO && e.iop->prev != '\n') { 4581 e.iop->prev = 0; 4582 if (e.iop == iostack) 4583 ioecho('\n'); 4584 return '\n'; 4585 } 4586 } 4587 if (e.iop->task == XIO) { 4588 if (multiline) { 4589 e.iop->prev = 0; 4590 return e.iop->prev; 4591 } 4592 if (interactive && e.iop == iostack + 1) { 4593 #if ENABLE_FEATURE_EDITING 4594 current_prompt = prompt->value; 4714 4595 #else 4715 4596 prs(prompt->value); 4716 4597 #endif 4717 }4718 4598 } 4719 4599 } 4720 4721 4600 } /* FOR */ 4722 4601 4723 4602 if (e.iop >= iostack) { 4724 4603 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop)); 4725 return (0);4604 return 0; 4726 4605 } 4727 4606 … … 4730 4609 4731 4610 /* NOTREACHED */ 4732 return (0);4611 return 0; 4733 4612 } 4734 4613 4735 4614 static void ioecho(char c) 4736 4615 { 4737 if ( flag['v'])4616 if (FLAG['v']) 4738 4617 write(2, &c, sizeof c); 4739 4618 } … … 4775 4654 if ((isatty(e.iop->argp->afile) == 0) 4776 4655 && (e.iop == &iostack[0] 4777 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {4656 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) { 4778 4657 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */ 4779 4658 bufid = AFID_ID; /* AFID_ID = 0 */ … … 4797 4676 e.iop->task = XIO; 4798 4677 else if (fn == (int (*)(struct ioarg *)) gravechar 4799 4678 || fn == (int (*)(struct ioarg *)) qgravechar) 4800 4679 e.iop->task = XGRAVE; 4801 4680 else 4802 4681 e.iop->task = XOTHER; 4803 4804 return;4805 4682 } 4806 4683 4807 4684 static struct io *setbase(struct io *ip) 4808 4685 { 4809 REGISTERstruct io *xp;4686 struct io *xp; 4810 4687 4811 4688 xp = e.iobase; 4812 4689 e.iobase = ip; 4813 return (xp);4690 return xp; 4814 4691 } 4815 4692 … … 4821 4698 * Produce the characters of a string, then a newline, then EOF. 4822 4699 */ 4823 static int nlchar( REGISTERstruct ioarg *ap)4824 { 4825 REGISTERint c;4700 static int nlchar(struct ioarg *ap) 4701 { 4702 int c; 4826 4703 4827 4704 if (ap->aword == NULL) 4828 return (0); 4829 if ((c = *ap->aword++) == 0) { 4705 return 0; 4706 c = *ap->aword++; 4707 if (c == 0) { 4830 4708 ap->aword = NULL; 4831 return ('\n');4832 } 4833 return (c);4709 return '\n'; 4710 } 4711 return c; 4834 4712 } 4835 4713 … … 4838 4716 * in them, with a space after each word. 4839 4717 */ 4840 static int wdchar(REGISTER struct ioarg *ap) 4841 { 4842 REGISTER char c; 4843 REGISTER char **wl; 4844 4845 if ((wl = ap->awordlist) == NULL) 4846 return (0); 4718 static int wdchar(struct ioarg *ap) 4719 { 4720 char c; 4721 char **wl; 4722 4723 wl = ap->awordlist; 4724 if (wl == NULL) 4725 return 0; 4847 4726 if (*wl != NULL) { 4848 if ((c = *(*wl)++) != 0) 4849 return (c & 0177); 4727 c = *(*wl)++; 4728 if (c != 0) 4729 return c & 0177; 4850 4730 ap->awordlist++; 4851 return (' ');4731 return ' '; 4852 4732 } 4853 4733 ap->awordlist = NULL; 4854 return ('\n');4734 return '\n'; 4855 4735 } 4856 4736 … … 4859 4739 * producing a space between them. 4860 4740 */ 4861 static int dolchar(REGISTER struct ioarg *ap) 4862 { 4863 REGISTER char *wp; 4864 4865 if ((wp = *ap->awordlist++) != NULL) { 4741 static int dolchar(struct ioarg *ap) 4742 { 4743 char *wp; 4744 4745 wp = *ap->awordlist++; 4746 if (wp != NULL) { 4866 4747 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar); 4867 return (-1);4868 } 4869 return (0);4870 } 4871 4872 static int xxchar( REGISTERstruct ioarg *ap)4873 { 4874 REGISTERint c;4748 return -1; 4749 } 4750 return 0; 4751 } 4752 4753 static int xxchar(struct ioarg *ap) 4754 { 4755 int c; 4875 4756 4876 4757 if (ap->aword == NULL) 4877 return (0); 4878 if ((c = *ap->aword++) == '\0') { 4758 return 0; 4759 c = *ap->aword++; 4760 if (c == '\0') { 4879 4761 ap->aword = NULL; 4880 return (' ');4881 } 4882 return (c);4762 return ' '; 4763 } 4764 return c; 4883 4765 } 4884 4766 … … 4886 4768 * Produce the characters from a single word (string). 4887 4769 */ 4888 static int strchar(REGISTER struct ioarg *ap) 4889 { 4890 REGISTER int c; 4891 4892 if (ap->aword == NULL || (c = *ap->aword++) == 0) 4893 return (0); 4894 return (c); 4770 static int strchar(struct ioarg *ap) 4771 { 4772 if (ap->aword == NULL) 4773 return 0; 4774 return *ap->aword++; 4895 4775 } 4896 4776 … … 4898 4778 * Produce quoted characters from a single word (string). 4899 4779 */ 4900 static int qstrchar(REGISTER struct ioarg *ap) 4901 { 4902 REGISTER int c; 4903 4904 if (ap->aword == NULL || (c = *ap->aword++) == 0) 4905 return (0); 4906 return (c | QUOTE); 4780 static int qstrchar(struct ioarg *ap) 4781 { 4782 int c; 4783 4784 if (ap->aword == NULL) 4785 return 0; 4786 c = *ap->aword++; 4787 if (c) 4788 c |= QUOTE; 4789 return c; 4907 4790 } 4908 4791 … … 4910 4793 * Return the characters from a file. 4911 4794 */ 4912 static int filechar( REGISTERstruct ioarg *ap)4913 { 4914 REGISTERint i;4795 static int filechar(struct ioarg *ap) 4796 { 4797 int i; 4915 4798 char c; 4916 4799 struct iobuf *bp = ap->afbuf; 4917 4800 4918 4801 if (ap->afid != AFID_NOBUF) { 4919 i f ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {4920 4802 i = (ap->afid != bp->id); 4803 if (i || bp->bufp == bp->ebufp) { 4921 4804 if (i) 4922 lseek(ap->afile, ap->afpos, 0);4805 lseek(ap->afile, ap->afpos, SEEK_SET); 4923 4806 4924 4807 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); 4925 4926 4808 if (i <= 0) { 4927 4809 closef(ap->afile); … … 4930 4812 4931 4813 bp->id = ap->afid; 4932 bp->ebufp = (bp->bufp = bp->buf) + i; 4814 bp->bufp = bp->buf; 4815 bp->ebufp = bp->bufp + i; 4933 4816 } 4934 4817 … … 4936 4819 return *bp->bufp++ & 0177; 4937 4820 } 4938 #if def CONFIG_FEATURE_COMMAND_EDITING4821 #if ENABLE_FEATURE_EDITING 4939 4822 if (interactive && isatty(ap->afile)) { 4940 static char mycommand[BUFSIZ];4823 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */ 4941 4824 static int position = 0, size = 0; 4942 4825 4943 4826 while (size == 0 || position >= size) { 4944 cmdedit_read_input(current_prompt, mycommand);4945 size = strlen( mycommand);4827 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state); 4828 size = strlen(filechar_cmdbuf); 4946 4829 position = 0; 4947 4830 } 4948 c = mycommand[position];4831 c = filechar_cmdbuf[position]; 4949 4832 position++; 4950 return (c);4951 } else4833 return c; 4834 } 4952 4835 #endif 4953 4954 { 4955 i = safe_read(ap->afile, &c, sizeof(c)); 4956 return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0)); 4957 } 4836 i = safe_read(ap->afile, &c, sizeof(c)); 4837 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); 4958 4838 } 4959 4839 … … 4961 4841 * Return the characters from a here temp file. 4962 4842 */ 4963 static int herechar( REGISTERstruct ioarg *ap)4843 static int herechar(struct ioarg *ap) 4964 4844 { 4965 4845 char c; 4966 4967 4846 4968 4847 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { 4969 4848 close(ap->afile); 4970 c = 0; 4971 } 4972 return (c); 4973 4849 c = '\0'; 4850 } 4851 return c; 4974 4852 } 4975 4853 … … 4980 4858 static int gravechar(struct ioarg *ap, struct io *iop) 4981 4859 { 4982 REGISTER int c; 4983 4984 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n') 4860 int c; 4861 4862 c = qgravechar(ap, iop) & ~QUOTE; 4863 if (c == '\n') 4985 4864 c = ' '; 4986 return (c);4987 } 4988 4989 static int qgravechar( REGISTERstruct ioarg *ap, struct io *iop)4990 { 4991 REGISTERint c;4865 return c; 4866 } 4867 4868 static int qgravechar(struct ioarg *ap, struct io *iop) 4869 { 4870 int c; 4992 4871 4993 4872 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop)); … … 4996 4875 if (iop->nlcount) { 4997 4876 iop->nlcount--; 4998 return ('\n' | QUOTE);4877 return '\n' | QUOTE; 4999 4878 } 5000 4879 c = iop->xchar; … … 5006 4885 iop->xchar = c; 5007 4886 if (c == 0) 5008 return (c);4887 return c; 5009 4888 iop->nlcount--; 5010 4889 c = '\n'; 5011 4890 } 5012 return (c != 0 ? c | QUOTE : 0);4891 return c != 0 ? c | QUOTE : 0; 5013 4892 } 5014 4893 … … 5016 4895 * Return a single command (usually the first line) from a file. 5017 4896 */ 5018 static int linechar(REGISTER struct ioarg *ap) 5019 { 5020 REGISTER int c; 5021 5022 if ((c = filechar(ap)) == '\n') { 4897 static int linechar(struct ioarg *ap) 4898 { 4899 int c; 4900 4901 c = filechar(ap); 4902 if (c == '\n') { 5023 4903 if (!multiline) { 5024 4904 closef(ap->afile); … … 5026 4906 } 5027 4907 } 5028 return (c); 5029 } 5030 5031 static void prs(REGISTER const char *s) 5032 { 5033 if (*s) 5034 write(2, s, strlen(s)); 5035 } 5036 5037 static void prn(unsigned u) 5038 { 5039 prs(itoa(u)); 5040 } 5041 5042 static void closef(REGISTER int i) 5043 { 5044 if (i > 2) 5045 close(i); 5046 } 5047 5048 static void closeall(void) 5049 { 5050 REGISTER int u; 5051 5052 for (u = NUFILE; u < NOFILE;) 5053 close(u++); 5054 } 5055 4908 return c; 4909 } 5056 4910 5057 4911 /* 5058 4912 * remap fd into Shell's fd space 5059 4913 */ 5060 static int remap( REGISTERint fd)5061 { 5062 REGISTERint i;4914 static int remap(int fd) 4915 { 4916 int i; 5063 4917 int map[NOFILE]; 5064 4918 int newfd; 5065 5066 4919 5067 4920 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd)); … … 5085 4938 } 5086 4939 5087 return (fd); 5088 } 5089 5090 static int openpipe(REGISTER int *pv) 5091 { 5092 REGISTER int i; 5093 5094 if ((i = pipe(pv)) < 0) 4940 return fd; 4941 } 4942 4943 static int openpipe(int *pv) 4944 { 4945 int i; 4946 4947 i = pipe(pv); 4948 if (i < 0) 5095 4949 err("can't create pipe - try again"); 5096 return (i);5097 } 5098 5099 static void closepipe( REGISTERint *pv)4950 return i; 4951 } 4952 4953 static void closepipe(int *pv) 5100 4954 { 5101 4955 if (pv != NULL) { … … 5105 4959 } 5106 4960 4961 5107 4962 /* -------- here.c -------- */ 5108 4963 … … 5111 4966 */ 5112 4967 5113 static void markhere( REGISTERchar *s, struct ioword *iop)5114 { 5115 REGISTERstruct here *h, *lh;4968 static void markhere(char *s, struct ioword *iop) 4969 { 4970 struct here *h, *lh; 5116 4971 5117 4972 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s)); 5118 4973 5119 4974 h = (struct here *) space(sizeof(struct here)); 5120 if (h == 0)4975 if (h == NULL) 5121 4976 return; 5122 4977 … … 5130 4985 if (inhere == 0) 5131 4986 inhere = h; 5132 else 5133 for (lh = inhere; lh != NULL; lh = lh->h_next) 4987 else { 4988 for (lh = inhere; lh != NULL; lh = lh->h_next) { 5134 4989 if (lh->h_next == 0) { 5135 4990 lh->h_next = h; 5136 4991 break; 5137 4992 } 4993 } 4994 } 5138 4995 iop->io_flag |= IOHERE | IOXHERE; 5139 for (s = h->h_tag; *s; s++) 4996 for (s = h->h_tag; *s; s++) { 5140 4997 if (*s & QUOTE) { 5141 4998 iop->io_flag &= ~IOXHERE; 5142 4999 *s &= ~QUOTE; 5143 5000 } 5001 } 5144 5002 h->h_dosub = iop->io_flag & IOXHERE; 5145 5003 } … … 5147 5005 static void gethere(void) 5148 5006 { 5149 REGISTERstruct here *h, *hp;5007 struct here *h, *hp; 5150 5008 5151 5009 DBGPRINTF7(("GETHERE: enter...\n")); … … 5163 5021 } 5164 5022 5165 static void readhere(char **name, REGISTERchar *s, int ec)5023 static void readhere(char **name, char *s, int ec) 5166 5024 { 5167 5025 int tf; 5168 5026 char tname[30] = ".msh_XXXXXX"; 5169 REGISTERint c;5027 int c; 5170 5028 jmp_buf ev; 5171 5029 char myline[LINELIM + 1]; … … 5179 5037 5180 5038 *name = strsave(tname, areanum); 5181 if (newenv(setjmp(errpt = ev)) != 0) 5039 errpt = ev; 5040 if (newenv(setjmp(errpt)) != 0) 5182 5041 unlink(tname); 5183 5042 else { … … 5186 5045 for (;;) { 5187 5046 if (interactive && e.iop <= iostack) { 5188 #if def CONFIG_FEATURE_COMMAND_EDITING5047 #if ENABLE_FEATURE_EDITING 5189 5048 current_prompt = cprompt->value; 5190 5049 #else … … 5224 5083 static int herein(char *hname, int xdoll) 5225 5084 { 5226 REGISTERint hf;5085 int hf; 5227 5086 int tf; 5228 5087 … … 5232 5091 #endif 5233 5092 if (hname == NULL) 5234 return (-1);5093 return -1; 5235 5094 5236 5095 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll)); 5237 5096 5238 hf = open(hname, 0);5097 hf = open(hname, O_RDONLY); 5239 5098 if (hf < 0) 5240 return (-1);5099 return -1; 5241 5100 5242 5101 if (xdoll) { … … 5247 5106 tf = mkstemp(tname); 5248 5107 if (tf < 0) 5249 return (-1); 5250 if (newenv(setjmp(errpt = ev)) == 0) { 5108 return -1; 5109 errpt = ev; 5110 if (newenv(setjmp(errpt)) == 0) { 5251 5111 PUSHIO(afile, hf, herechar); 5252 5112 setbase(e.iop); … … 5259 5119 unlink(tname); 5260 5120 close(tf); 5261 tf = open(tname, 0);5121 tf = open(tname, O_RDONLY); 5262 5122 unlink(tname); 5263 return (tf);5264 } else5265 return (hf);5123 return tf; 5124 } 5125 return hf; 5266 5126 } 5267 5127 5268 5128 static void scraphere(void) 5269 5129 { 5270 REGISTERstruct here *h;5130 struct here *h; 5271 5131 5272 5132 DBGPRINTF7(("SCRAPHERE: enter...\n")); … … 5282 5142 static void freehere(int area) 5283 5143 { 5284 REGISTERstruct here *h, *hl;5144 struct here *h, *hl; 5285 5145 5286 5146 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area)); … … 5299 5159 } 5300 5160 5161 5162 /* -------- sh.c -------- */ 5163 /* 5164 * shell 5165 */ 5166 5167 int msh_main(int argc, char **argv); 5168 int msh_main(int argc, char **argv) 5169 { 5170 int f; 5171 char *s; 5172 int cflag; 5173 char *name, **ap; 5174 int (*iof) (struct ioarg *); 5175 5176 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 5177 sharedbuf.id = AFID_NOBUF; 5178 mainbuf.id = AFID_NOBUF; 5179 e.linep = line; 5180 elinep = line + sizeof(line) - 5; 5181 5182 #if ENABLE_FEATURE_EDITING 5183 line_input_state = new_line_input_t(FOR_SHELL); 5184 #endif 5185 5186 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); 5187 5188 initarea(); 5189 ap = environ; 5190 if (ap != NULL) { 5191 while (*ap) 5192 assign(*ap++, !COPYV); 5193 for (ap = environ; *ap;) 5194 export(lookup(*ap++)); 5195 } 5196 closeall(); 5197 areanum = 1; 5198 5199 shell = lookup("SHELL"); 5200 if (shell->value == null) 5201 setval(shell, (char *)DEFAULT_SHELL); 5202 export(shell); 5203 5204 homedir = lookup("HOME"); 5205 if (homedir->value == null) 5206 setval(homedir, "/"); 5207 export(homedir); 5208 5209 setval(lookup("$"), putn(getpid())); 5210 5211 path = lookup("PATH"); 5212 if (path->value == null) { 5213 /* Can be merged with same string elsewhere in bbox */ 5214 if (geteuid() == 0) 5215 setval(path, bb_default_root_path); 5216 else 5217 setval(path, bb_default_path); 5218 } 5219 export(path); 5220 5221 ifs = lookup("IFS"); 5222 if (ifs->value == null) 5223 setval(ifs, " \t\n"); 5224 5225 #ifdef MSHDEBUG 5226 mshdbg_var = lookup("MSHDEBUG"); 5227 if (mshdbg_var->value == null) 5228 setval(mshdbg_var, "0"); 5229 #endif 5230 5231 prompt = lookup("PS1"); 5232 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT 5233 if (prompt->value == null) 5234 #endif 5235 setval(prompt, DEFAULT_USER_PROMPT); 5236 if (geteuid() == 0) { 5237 setval(prompt, DEFAULT_ROOT_PROMPT); 5238 prompt->status &= ~EXPORT; 5239 } 5240 cprompt = lookup("PS2"); 5241 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT 5242 if (cprompt->value == null) 5243 #endif 5244 setval(cprompt, "> "); 5245 5246 iof = filechar; 5247 cflag = 0; 5248 name = *argv++; 5249 if (--argc >= 1) { 5250 if (argv[0][0] == '-' && argv[0][1] != '\0') { 5251 for (s = argv[0] + 1; *s; s++) 5252 switch (*s) { 5253 case 'c': 5254 prompt->status &= ~EXPORT; 5255 cprompt->status &= ~EXPORT; 5256 setval(prompt, ""); 5257 setval(cprompt, ""); 5258 cflag = 1; 5259 if (--argc > 0) 5260 PUSHIO(aword, *++argv, iof = nlchar); 5261 break; 5262 5263 case 'q': 5264 qflag = SIG_DFL; 5265 break; 5266 5267 case 's': 5268 /* standard input */ 5269 break; 5270 5271 case 't': 5272 prompt->status &= ~EXPORT; 5273 setval(prompt, ""); 5274 iof = linechar; 5275 break; 5276 5277 case 'i': 5278 interactive++; 5279 default: 5280 if (*s >= 'a' && *s <= 'z') 5281 FLAG[(int) *s]++; 5282 } 5283 } else { 5284 argv--; 5285 argc++; 5286 } 5287 5288 if (iof == filechar && --argc > 0) { 5289 setval(prompt, ""); 5290 setval(cprompt, ""); 5291 prompt->status &= ~EXPORT; 5292 cprompt->status &= ~EXPORT; 5293 5294 /* Shell is non-interactive, activate printf-based debug */ 5295 #ifdef MSHDEBUG 5296 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0'); 5297 if (mshdbg < 0) 5298 mshdbg = 0; 5299 #endif 5300 DBGPRINTF(("MSH_MAIN: calling newfile()\n")); 5301 5302 name = *++argv; 5303 if (newfile(name)) 5304 exit(1); /* Exit on error */ 5305 } 5306 } 5307 5308 setdash(); 5309 5310 /* This won't be true if PUSHIO has been called, say from newfile() above */ 5311 if (e.iop < iostack) { 5312 PUSHIO(afile, 0, iof); 5313 if (isatty(0) && isatty(1) && !cflag) { 5314 interactive++; 5315 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 5316 #ifdef MSHDEBUG 5317 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner); 5318 #else 5319 printf("\n\n%s built-in shell (msh)\n", bb_banner); 5320 #endif 5321 printf("Enter 'help' for a list of built-in commands.\n\n"); 5322 #endif 5323 } 5324 } 5325 5326 signal(SIGQUIT, qflag); 5327 if (name && name[0] == '-') { 5328 interactive++; 5329 f = open(".profile", O_RDONLY); 5330 if (f >= 0) 5331 next(remap(f)); 5332 f = open("/etc/profile", O_RDONLY); 5333 if (f >= 0) 5334 next(remap(f)); 5335 } 5336 if (interactive) 5337 signal(SIGTERM, sig); 5338 5339 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 5340 signal(SIGINT, onintr); 5341 dolv = argv; 5342 dolc = argc; 5343 dolv[0] = name; 5344 if (dolc > 1) { 5345 for (ap = ++argv; --argc > 0;) { 5346 *ap = *argv++; 5347 if (assign(*ap, !COPYV)) { 5348 dolc--; /* keyword */ 5349 } else { 5350 ap++; 5351 } 5352 } 5353 } 5354 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); 5355 5356 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack)); 5357 5358 for (;;) { 5359 if (interactive && e.iop <= iostack) { 5360 #if ENABLE_FEATURE_EDITING 5361 current_prompt = prompt->value; 5362 #else 5363 prs(prompt->value); 5364 #endif 5365 } 5366 onecommand(); 5367 /* Ensure that getenv("PATH") stays current */ 5368 setenv("PATH", path->value, 1); 5369 } 5370 5371 DBGPRINTF(("MSH_MAIN: returning.\n")); 5372 } 5301 5373 5302 5374
Note:
See TracChangeset
for help on using the changeset viewer.